xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * adv7511_cec.c - Analog Devices ADV7511/33 cec driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you may redistribute it and/or modify
7*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun  * the Free Software Foundation; version 2 of the License.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17*4882a593Smuzhiyun  * SOFTWARE.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  */
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <linux/device.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/of_device.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <linux/clk.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <media/cec.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "adv7511.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define ADV7511_INT1_CEC_MASK \
32*4882a593Smuzhiyun 	(ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
33*4882a593Smuzhiyun 	 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1)
34*4882a593Smuzhiyun 
adv_cec_tx_raw_status(struct adv7511 * adv7511,u8 tx_raw_status)35*4882a593Smuzhiyun static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
38*4882a593Smuzhiyun 					ADV7533_REG_CEC_OFFSET : 0;
39*4882a593Smuzhiyun 	unsigned int val;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	if (regmap_read(adv7511->regmap_cec,
42*4882a593Smuzhiyun 			ADV7511_REG_CEC_TX_ENABLE + offset, &val))
43*4882a593Smuzhiyun 		return;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if ((val & 0x01) == 0)
46*4882a593Smuzhiyun 		return;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
49*4882a593Smuzhiyun 		cec_transmit_attempt_done(adv7511->cec_adap,
50*4882a593Smuzhiyun 					  CEC_TX_STATUS_ARB_LOST);
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 	if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
54*4882a593Smuzhiyun 		u8 status;
55*4882a593Smuzhiyun 		u8 err_cnt = 0;
56*4882a593Smuzhiyun 		u8 nack_cnt = 0;
57*4882a593Smuzhiyun 		u8 low_drive_cnt = 0;
58*4882a593Smuzhiyun 		unsigned int cnt;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 		/*
61*4882a593Smuzhiyun 		 * We set this status bit since this hardware performs
62*4882a593Smuzhiyun 		 * retransmissions.
63*4882a593Smuzhiyun 		 */
64*4882a593Smuzhiyun 		status = CEC_TX_STATUS_MAX_RETRIES;
65*4882a593Smuzhiyun 		if (regmap_read(adv7511->regmap_cec,
66*4882a593Smuzhiyun 			    ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {
67*4882a593Smuzhiyun 			err_cnt = 1;
68*4882a593Smuzhiyun 			status |= CEC_TX_STATUS_ERROR;
69*4882a593Smuzhiyun 		} else {
70*4882a593Smuzhiyun 			nack_cnt = cnt & 0xf;
71*4882a593Smuzhiyun 			if (nack_cnt)
72*4882a593Smuzhiyun 				status |= CEC_TX_STATUS_NACK;
73*4882a593Smuzhiyun 			low_drive_cnt = cnt >> 4;
74*4882a593Smuzhiyun 			if (low_drive_cnt)
75*4882a593Smuzhiyun 				status |= CEC_TX_STATUS_LOW_DRIVE;
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 		cec_transmit_done(adv7511->cec_adap, status,
78*4882a593Smuzhiyun 				  0, nack_cnt, low_drive_cnt, err_cnt);
79*4882a593Smuzhiyun 		return;
80*4882a593Smuzhiyun 	}
81*4882a593Smuzhiyun 	if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
82*4882a593Smuzhiyun 		cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
83*4882a593Smuzhiyun 		return;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
adv7511_cec_irq_process(struct adv7511 * adv7511,unsigned int irq1)87*4882a593Smuzhiyun void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
90*4882a593Smuzhiyun 					ADV7533_REG_CEC_OFFSET : 0;
91*4882a593Smuzhiyun 	const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
92*4882a593Smuzhiyun 				ADV7511_INT1_CEC_TX_ARBIT_LOST |
93*4882a593Smuzhiyun 				ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
94*4882a593Smuzhiyun 	struct cec_msg msg = {};
95*4882a593Smuzhiyun 	unsigned int len;
96*4882a593Smuzhiyun 	unsigned int val;
97*4882a593Smuzhiyun 	u8 i;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (irq1 & irq_tx_mask)
100*4882a593Smuzhiyun 		adv_cec_tx_raw_status(adv7511, irq1);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (!(irq1 & ADV7511_INT1_CEC_RX_READY1))
103*4882a593Smuzhiyun 		return;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (regmap_read(adv7511->regmap_cec,
106*4882a593Smuzhiyun 			ADV7511_REG_CEC_RX_FRAME_LEN + offset, &len))
107*4882a593Smuzhiyun 		return;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	msg.len = len & 0x1f;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (msg.len > 16)
112*4882a593Smuzhiyun 		msg.len = 16;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if (!msg.len)
115*4882a593Smuzhiyun 		return;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	for (i = 0; i < msg.len; i++) {
118*4882a593Smuzhiyun 		regmap_read(adv7511->regmap_cec,
119*4882a593Smuzhiyun 			    i + ADV7511_REG_CEC_RX_FRAME_HDR + offset, &val);
120*4882a593Smuzhiyun 		msg.msg[i] = val;
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* toggle to re-enable rx 1 */
124*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
125*4882a593Smuzhiyun 		     ADV7511_REG_CEC_RX_BUFFERS + offset, 1);
126*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
127*4882a593Smuzhiyun 		     ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
128*4882a593Smuzhiyun 	cec_received_msg(adv7511->cec_adap, &msg);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
adv7511_cec_adap_enable(struct cec_adapter * adap,bool enable)131*4882a593Smuzhiyun static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct adv7511 *adv7511 = cec_get_drvdata(adap);
134*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
135*4882a593Smuzhiyun 					ADV7533_REG_CEC_OFFSET : 0;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	if (adv7511->i2c_cec == NULL)
138*4882a593Smuzhiyun 		return -EIO;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (!adv7511->cec_enabled_adap && enable) {
141*4882a593Smuzhiyun 		/* power up cec section */
142*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
143*4882a593Smuzhiyun 				   ADV7511_REG_CEC_CLK_DIV + offset,
144*4882a593Smuzhiyun 				   0x03, 0x01);
145*4882a593Smuzhiyun 		/* legacy mode and clear all rx buffers */
146*4882a593Smuzhiyun 		regmap_write(adv7511->regmap_cec,
147*4882a593Smuzhiyun 			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x07);
148*4882a593Smuzhiyun 		regmap_write(adv7511->regmap_cec,
149*4882a593Smuzhiyun 			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
150*4882a593Smuzhiyun 		/* initially disable tx */
151*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
152*4882a593Smuzhiyun 				   ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
153*4882a593Smuzhiyun 		/* enabled irqs: */
154*4882a593Smuzhiyun 		/* tx: ready */
155*4882a593Smuzhiyun 		/* tx: arbitration lost */
156*4882a593Smuzhiyun 		/* tx: retry timeout */
157*4882a593Smuzhiyun 		/* rx: ready 1 */
158*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap,
159*4882a593Smuzhiyun 				   ADV7511_REG_INT_ENABLE(1), 0x3f,
160*4882a593Smuzhiyun 				   ADV7511_INT1_CEC_MASK);
161*4882a593Smuzhiyun 	} else if (adv7511->cec_enabled_adap && !enable) {
162*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap,
163*4882a593Smuzhiyun 				   ADV7511_REG_INT_ENABLE(1), 0x3f, 0);
164*4882a593Smuzhiyun 		/* disable address mask 1-3 */
165*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
166*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
167*4882a593Smuzhiyun 				   0x70, 0x00);
168*4882a593Smuzhiyun 		/* power down cec section */
169*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
170*4882a593Smuzhiyun 				   ADV7511_REG_CEC_CLK_DIV + offset,
171*4882a593Smuzhiyun 				   0x03, 0x00);
172*4882a593Smuzhiyun 		adv7511->cec_valid_addrs = 0;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 	adv7511->cec_enabled_adap = enable;
175*4882a593Smuzhiyun 	return 0;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
adv7511_cec_adap_log_addr(struct cec_adapter * adap,u8 addr)178*4882a593Smuzhiyun static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct adv7511 *adv7511 = cec_get_drvdata(adap);
181*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
182*4882a593Smuzhiyun 					ADV7533_REG_CEC_OFFSET : 0;
183*4882a593Smuzhiyun 	unsigned int i, free_idx = ADV7511_MAX_ADDRS;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (!adv7511->cec_enabled_adap)
186*4882a593Smuzhiyun 		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (addr == CEC_LOG_ADDR_INVALID) {
189*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
190*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
191*4882a593Smuzhiyun 				   0x70, 0);
192*4882a593Smuzhiyun 		adv7511->cec_valid_addrs = 0;
193*4882a593Smuzhiyun 		return 0;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
197*4882a593Smuzhiyun 		bool is_valid = adv7511->cec_valid_addrs & (1 << i);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
200*4882a593Smuzhiyun 			free_idx = i;
201*4882a593Smuzhiyun 		if (is_valid && adv7511->cec_addr[i] == addr)
202*4882a593Smuzhiyun 			return 0;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 	if (i == ADV7511_MAX_ADDRS) {
205*4882a593Smuzhiyun 		i = free_idx;
206*4882a593Smuzhiyun 		if (i == ADV7511_MAX_ADDRS)
207*4882a593Smuzhiyun 			return -ENXIO;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 	adv7511->cec_addr[i] = addr;
210*4882a593Smuzhiyun 	adv7511->cec_valid_addrs |= 1 << i;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	switch (i) {
213*4882a593Smuzhiyun 	case 0:
214*4882a593Smuzhiyun 		/* enable address mask 0 */
215*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
216*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
217*4882a593Smuzhiyun 				   0x10, 0x10);
218*4882a593Smuzhiyun 		/* set address for mask 0 */
219*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
220*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
221*4882a593Smuzhiyun 				   0x0f, addr);
222*4882a593Smuzhiyun 		break;
223*4882a593Smuzhiyun 	case 1:
224*4882a593Smuzhiyun 		/* enable address mask 1 */
225*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
226*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
227*4882a593Smuzhiyun 				   0x20, 0x20);
228*4882a593Smuzhiyun 		/* set address for mask 1 */
229*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
230*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
231*4882a593Smuzhiyun 				   0xf0, addr << 4);
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case 2:
234*4882a593Smuzhiyun 		/* enable address mask 2 */
235*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
236*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
237*4882a593Smuzhiyun 				   0x40, 0x40);
238*4882a593Smuzhiyun 		/* set address for mask 1 */
239*4882a593Smuzhiyun 		regmap_update_bits(adv7511->regmap_cec,
240*4882a593Smuzhiyun 				   ADV7511_REG_CEC_LOG_ADDR_2 + offset,
241*4882a593Smuzhiyun 				   0x0f, addr);
242*4882a593Smuzhiyun 		break;
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
adv7511_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)247*4882a593Smuzhiyun static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
248*4882a593Smuzhiyun 				     u32 signal_free_time, struct cec_msg *msg)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct adv7511 *adv7511 = cec_get_drvdata(adap);
251*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
252*4882a593Smuzhiyun 					ADV7533_REG_CEC_OFFSET : 0;
253*4882a593Smuzhiyun 	u8 len = msg->len;
254*4882a593Smuzhiyun 	unsigned int i;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/*
257*4882a593Smuzhiyun 	 * The number of retries is the number of attempts - 1, but retry
258*4882a593Smuzhiyun 	 * at least once. It's not clear if a value of 0 is allowed, so
259*4882a593Smuzhiyun 	 * let's do at least one retry.
260*4882a593Smuzhiyun 	 */
261*4882a593Smuzhiyun 	regmap_update_bits(adv7511->regmap_cec,
262*4882a593Smuzhiyun 			   ADV7511_REG_CEC_TX_RETRY + offset,
263*4882a593Smuzhiyun 			   0x70, max(1, attempts - 1) << 4);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* blocking, clear cec tx irq status */
266*4882a593Smuzhiyun 	regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* write data */
269*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
270*4882a593Smuzhiyun 		regmap_write(adv7511->regmap_cec,
271*4882a593Smuzhiyun 			     i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,
272*4882a593Smuzhiyun 			     msg->msg[i]);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	/* set length (data + header) */
275*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
276*4882a593Smuzhiyun 		     ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
277*4882a593Smuzhiyun 	/* start transmit, enable tx */
278*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
279*4882a593Smuzhiyun 		     ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
280*4882a593Smuzhiyun 	return 0;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun static const struct cec_adap_ops adv7511_cec_adap_ops = {
284*4882a593Smuzhiyun 	.adap_enable = adv7511_cec_adap_enable,
285*4882a593Smuzhiyun 	.adap_log_addr = adv7511_cec_adap_log_addr,
286*4882a593Smuzhiyun 	.adap_transmit = adv7511_cec_adap_transmit,
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
adv7511_cec_parse_dt(struct device * dev,struct adv7511 * adv7511)289*4882a593Smuzhiyun static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	adv7511->cec_clk = devm_clk_get(dev, "cec");
292*4882a593Smuzhiyun 	if (IS_ERR(adv7511->cec_clk)) {
293*4882a593Smuzhiyun 		int ret = PTR_ERR(adv7511->cec_clk);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		adv7511->cec_clk = NULL;
296*4882a593Smuzhiyun 		return ret;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 	clk_prepare_enable(adv7511->cec_clk);
299*4882a593Smuzhiyun 	adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
300*4882a593Smuzhiyun 	return 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
adv7511_cec_init(struct device * dev,struct adv7511 * adv7511)303*4882a593Smuzhiyun int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	unsigned int offset = adv7511->type == ADV7533 ?
306*4882a593Smuzhiyun 						ADV7533_REG_CEC_OFFSET : 0;
307*4882a593Smuzhiyun 	int ret = adv7511_cec_parse_dt(dev, adv7511);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (ret)
310*4882a593Smuzhiyun 		goto err_cec_parse_dt;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
313*4882a593Smuzhiyun 		adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
314*4882a593Smuzhiyun 	if (IS_ERR(adv7511->cec_adap)) {
315*4882a593Smuzhiyun 		ret = PTR_ERR(adv7511->cec_adap);
316*4882a593Smuzhiyun 		goto err_cec_alloc;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0);
320*4882a593Smuzhiyun 	/* cec soft reset */
321*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
322*4882a593Smuzhiyun 		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
323*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
324*4882a593Smuzhiyun 		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* legacy mode */
327*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
328*4882a593Smuzhiyun 		     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x00);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	regmap_write(adv7511->regmap_cec,
331*4882a593Smuzhiyun 		     ADV7511_REG_CEC_CLK_DIV + offset,
332*4882a593Smuzhiyun 		     ((adv7511->cec_clk_freq / 750000) - 1) << 2);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	ret = cec_register_adapter(adv7511->cec_adap, dev);
335*4882a593Smuzhiyun 	if (ret)
336*4882a593Smuzhiyun 		goto err_cec_register;
337*4882a593Smuzhiyun 	return 0;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun err_cec_register:
340*4882a593Smuzhiyun 	cec_delete_adapter(adv7511->cec_adap);
341*4882a593Smuzhiyun 	adv7511->cec_adap = NULL;
342*4882a593Smuzhiyun err_cec_alloc:
343*4882a593Smuzhiyun 	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
344*4882a593Smuzhiyun 		 ret);
345*4882a593Smuzhiyun err_cec_parse_dt:
346*4882a593Smuzhiyun 	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
347*4882a593Smuzhiyun 		     ADV7511_CEC_CTRL_POWER_DOWN);
348*4882a593Smuzhiyun 	return ret == -EPROBE_DEFER ? ret : 0;
349*4882a593Smuzhiyun }
350