xref: /linux/drivers/media/cec/platform/stm32/stm32-cec.c (revision 4be5e8648b0c287aefc6ac3f3a0b12c696054f43)
1*4be5e864SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2*4be5e864SMauro Carvalho Chehab /*
3*4be5e864SMauro Carvalho Chehab  * STM32 CEC driver
4*4be5e864SMauro Carvalho Chehab  * Copyright (C) STMicroelectronics SA 2017
5*4be5e864SMauro Carvalho Chehab  *
6*4be5e864SMauro Carvalho Chehab  */
7*4be5e864SMauro Carvalho Chehab 
8*4be5e864SMauro Carvalho Chehab #include <linux/clk.h>
9*4be5e864SMauro Carvalho Chehab #include <linux/interrupt.h>
10*4be5e864SMauro Carvalho Chehab #include <linux/kernel.h>
11*4be5e864SMauro Carvalho Chehab #include <linux/module.h>
12*4be5e864SMauro Carvalho Chehab #include <linux/of.h>
13*4be5e864SMauro Carvalho Chehab #include <linux/of_device.h>
14*4be5e864SMauro Carvalho Chehab #include <linux/platform_device.h>
15*4be5e864SMauro Carvalho Chehab #include <linux/regmap.h>
16*4be5e864SMauro Carvalho Chehab 
17*4be5e864SMauro Carvalho Chehab #include <media/cec.h>
18*4be5e864SMauro Carvalho Chehab 
19*4be5e864SMauro Carvalho Chehab #define CEC_NAME	"stm32-cec"
20*4be5e864SMauro Carvalho Chehab 
21*4be5e864SMauro Carvalho Chehab /* CEC registers  */
22*4be5e864SMauro Carvalho Chehab #define CEC_CR		0x0000 /* Control Register */
23*4be5e864SMauro Carvalho Chehab #define CEC_CFGR	0x0004 /* ConFiGuration Register */
24*4be5e864SMauro Carvalho Chehab #define CEC_TXDR	0x0008 /* Rx data Register */
25*4be5e864SMauro Carvalho Chehab #define CEC_RXDR	0x000C /* Rx data Register */
26*4be5e864SMauro Carvalho Chehab #define CEC_ISR		0x0010 /* Interrupt and status Register */
27*4be5e864SMauro Carvalho Chehab #define CEC_IER		0x0014 /* Interrupt enable Register */
28*4be5e864SMauro Carvalho Chehab 
29*4be5e864SMauro Carvalho Chehab #define TXEOM		BIT(2)
30*4be5e864SMauro Carvalho Chehab #define TXSOM		BIT(1)
31*4be5e864SMauro Carvalho Chehab #define CECEN		BIT(0)
32*4be5e864SMauro Carvalho Chehab 
33*4be5e864SMauro Carvalho Chehab #define LSTN		BIT(31)
34*4be5e864SMauro Carvalho Chehab #define OAR		GENMASK(30, 16)
35*4be5e864SMauro Carvalho Chehab #define SFTOP		BIT(8)
36*4be5e864SMauro Carvalho Chehab #define BRDNOGEN	BIT(7)
37*4be5e864SMauro Carvalho Chehab #define LBPEGEN		BIT(6)
38*4be5e864SMauro Carvalho Chehab #define BREGEN		BIT(5)
39*4be5e864SMauro Carvalho Chehab #define BRESTP		BIT(4)
40*4be5e864SMauro Carvalho Chehab #define RXTOL		BIT(3)
41*4be5e864SMauro Carvalho Chehab #define SFT		GENMASK(2, 0)
42*4be5e864SMauro Carvalho Chehab #define FULL_CFG	(LSTN | SFTOP | BRDNOGEN | LBPEGEN | BREGEN | BRESTP \
43*4be5e864SMauro Carvalho Chehab 			 | RXTOL)
44*4be5e864SMauro Carvalho Chehab 
45*4be5e864SMauro Carvalho Chehab #define TXACKE		BIT(12)
46*4be5e864SMauro Carvalho Chehab #define TXERR		BIT(11)
47*4be5e864SMauro Carvalho Chehab #define TXUDR		BIT(10)
48*4be5e864SMauro Carvalho Chehab #define TXEND		BIT(9)
49*4be5e864SMauro Carvalho Chehab #define TXBR		BIT(8)
50*4be5e864SMauro Carvalho Chehab #define ARBLST		BIT(7)
51*4be5e864SMauro Carvalho Chehab #define RXACKE		BIT(6)
52*4be5e864SMauro Carvalho Chehab #define RXOVR		BIT(2)
53*4be5e864SMauro Carvalho Chehab #define RXEND		BIT(1)
54*4be5e864SMauro Carvalho Chehab #define RXBR		BIT(0)
55*4be5e864SMauro Carvalho Chehab 
56*4be5e864SMauro Carvalho Chehab #define ALL_TX_IT	(TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST)
57*4be5e864SMauro Carvalho Chehab #define ALL_RX_IT	(RXEND | RXBR | RXACKE | RXOVR)
58*4be5e864SMauro Carvalho Chehab 
59*4be5e864SMauro Carvalho Chehab /*
60*4be5e864SMauro Carvalho Chehab  * 400 ms is the time it takes for one 16 byte message to be
61*4be5e864SMauro Carvalho Chehab  * transferred and 5 is the maximum number of retries. Add
62*4be5e864SMauro Carvalho Chehab  * another 100 ms as a margin.
63*4be5e864SMauro Carvalho Chehab  */
64*4be5e864SMauro Carvalho Chehab #define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
65*4be5e864SMauro Carvalho Chehab 
66*4be5e864SMauro Carvalho Chehab struct stm32_cec {
67*4be5e864SMauro Carvalho Chehab 	struct cec_adapter	*adap;
68*4be5e864SMauro Carvalho Chehab 	struct device		*dev;
69*4be5e864SMauro Carvalho Chehab 	struct clk		*clk_cec;
70*4be5e864SMauro Carvalho Chehab 	struct clk		*clk_hdmi_cec;
71*4be5e864SMauro Carvalho Chehab 	struct reset_control	*rstc;
72*4be5e864SMauro Carvalho Chehab 	struct regmap		*regmap;
73*4be5e864SMauro Carvalho Chehab 	int			irq;
74*4be5e864SMauro Carvalho Chehab 	u32			irq_status;
75*4be5e864SMauro Carvalho Chehab 	struct cec_msg		rx_msg;
76*4be5e864SMauro Carvalho Chehab 	struct cec_msg		tx_msg;
77*4be5e864SMauro Carvalho Chehab 	int			tx_cnt;
78*4be5e864SMauro Carvalho Chehab };
79*4be5e864SMauro Carvalho Chehab 
80*4be5e864SMauro Carvalho Chehab static void cec_hw_init(struct stm32_cec *cec)
81*4be5e864SMauro Carvalho Chehab {
82*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0);
83*4be5e864SMauro Carvalho Chehab 
84*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT,
85*4be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT);
86*4be5e864SMauro Carvalho Chehab 
87*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG);
88*4be5e864SMauro Carvalho Chehab }
89*4be5e864SMauro Carvalho Chehab 
90*4be5e864SMauro Carvalho Chehab static void stm32_tx_done(struct stm32_cec *cec, u32 status)
91*4be5e864SMauro Carvalho Chehab {
92*4be5e864SMauro Carvalho Chehab 	if (status & (TXERR | TXUDR)) {
93*4be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR,
94*4be5e864SMauro Carvalho Chehab 				  0, 0, 0, 1);
95*4be5e864SMauro Carvalho Chehab 		return;
96*4be5e864SMauro Carvalho Chehab 	}
97*4be5e864SMauro Carvalho Chehab 
98*4be5e864SMauro Carvalho Chehab 	if (status & ARBLST) {
99*4be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST,
100*4be5e864SMauro Carvalho Chehab 				  1, 0, 0, 0);
101*4be5e864SMauro Carvalho Chehab 		return;
102*4be5e864SMauro Carvalho Chehab 	}
103*4be5e864SMauro Carvalho Chehab 
104*4be5e864SMauro Carvalho Chehab 	if (status & TXACKE) {
105*4be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK,
106*4be5e864SMauro Carvalho Chehab 				  0, 1, 0, 0);
107*4be5e864SMauro Carvalho Chehab 		return;
108*4be5e864SMauro Carvalho Chehab 	}
109*4be5e864SMauro Carvalho Chehab 
110*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & TXBR) {
111*4be5e864SMauro Carvalho Chehab 		/* send next byte */
112*4be5e864SMauro Carvalho Chehab 		if (cec->tx_cnt < cec->tx_msg.len)
113*4be5e864SMauro Carvalho Chehab 			regmap_write(cec->regmap, CEC_TXDR,
114*4be5e864SMauro Carvalho Chehab 				     cec->tx_msg.msg[cec->tx_cnt++]);
115*4be5e864SMauro Carvalho Chehab 
116*4be5e864SMauro Carvalho Chehab 		/* TXEOM is set to command transmission of the last byte */
117*4be5e864SMauro Carvalho Chehab 		if (cec->tx_cnt == cec->tx_msg.len)
118*4be5e864SMauro Carvalho Chehab 			regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
119*4be5e864SMauro Carvalho Chehab 	}
120*4be5e864SMauro Carvalho Chehab 
121*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & TXEND)
122*4be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
123*4be5e864SMauro Carvalho Chehab }
124*4be5e864SMauro Carvalho Chehab 
125*4be5e864SMauro Carvalho Chehab static void stm32_rx_done(struct stm32_cec *cec, u32 status)
126*4be5e864SMauro Carvalho Chehab {
127*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & (RXACKE | RXOVR)) {
128*4be5e864SMauro Carvalho Chehab 		cec->rx_msg.len = 0;
129*4be5e864SMauro Carvalho Chehab 		return;
130*4be5e864SMauro Carvalho Chehab 	}
131*4be5e864SMauro Carvalho Chehab 
132*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & RXBR) {
133*4be5e864SMauro Carvalho Chehab 		u32 val;
134*4be5e864SMauro Carvalho Chehab 
135*4be5e864SMauro Carvalho Chehab 		regmap_read(cec->regmap, CEC_RXDR, &val);
136*4be5e864SMauro Carvalho Chehab 		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
137*4be5e864SMauro Carvalho Chehab 	}
138*4be5e864SMauro Carvalho Chehab 
139*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & RXEND) {
140*4be5e864SMauro Carvalho Chehab 		cec_received_msg(cec->adap, &cec->rx_msg);
141*4be5e864SMauro Carvalho Chehab 		cec->rx_msg.len = 0;
142*4be5e864SMauro Carvalho Chehab 	}
143*4be5e864SMauro Carvalho Chehab }
144*4be5e864SMauro Carvalho Chehab 
145*4be5e864SMauro Carvalho Chehab static irqreturn_t stm32_cec_irq_thread(int irq, void *arg)
146*4be5e864SMauro Carvalho Chehab {
147*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = arg;
148*4be5e864SMauro Carvalho Chehab 
149*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & ALL_TX_IT)
150*4be5e864SMauro Carvalho Chehab 		stm32_tx_done(cec, cec->irq_status);
151*4be5e864SMauro Carvalho Chehab 
152*4be5e864SMauro Carvalho Chehab 	if (cec->irq_status & ALL_RX_IT)
153*4be5e864SMauro Carvalho Chehab 		stm32_rx_done(cec, cec->irq_status);
154*4be5e864SMauro Carvalho Chehab 
155*4be5e864SMauro Carvalho Chehab 	cec->irq_status = 0;
156*4be5e864SMauro Carvalho Chehab 
157*4be5e864SMauro Carvalho Chehab 	return IRQ_HANDLED;
158*4be5e864SMauro Carvalho Chehab }
159*4be5e864SMauro Carvalho Chehab 
160*4be5e864SMauro Carvalho Chehab static irqreturn_t stm32_cec_irq_handler(int irq, void *arg)
161*4be5e864SMauro Carvalho Chehab {
162*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = arg;
163*4be5e864SMauro Carvalho Chehab 
164*4be5e864SMauro Carvalho Chehab 	regmap_read(cec->regmap, CEC_ISR, &cec->irq_status);
165*4be5e864SMauro Carvalho Chehab 
166*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_ISR,
167*4be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT,
168*4be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT);
169*4be5e864SMauro Carvalho Chehab 
170*4be5e864SMauro Carvalho Chehab 	return IRQ_WAKE_THREAD;
171*4be5e864SMauro Carvalho Chehab }
172*4be5e864SMauro Carvalho Chehab 
173*4be5e864SMauro Carvalho Chehab static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable)
174*4be5e864SMauro Carvalho Chehab {
175*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
176*4be5e864SMauro Carvalho Chehab 	int ret = 0;
177*4be5e864SMauro Carvalho Chehab 
178*4be5e864SMauro Carvalho Chehab 	if (enable) {
179*4be5e864SMauro Carvalho Chehab 		ret = clk_enable(cec->clk_cec);
180*4be5e864SMauro Carvalho Chehab 		if (ret)
181*4be5e864SMauro Carvalho Chehab 			dev_err(cec->dev, "fail to enable cec clock\n");
182*4be5e864SMauro Carvalho Chehab 
183*4be5e864SMauro Carvalho Chehab 		clk_enable(cec->clk_hdmi_cec);
184*4be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
185*4be5e864SMauro Carvalho Chehab 	} else {
186*4be5e864SMauro Carvalho Chehab 		clk_disable(cec->clk_cec);
187*4be5e864SMauro Carvalho Chehab 		clk_disable(cec->clk_hdmi_cec);
188*4be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
189*4be5e864SMauro Carvalho Chehab 	}
190*4be5e864SMauro Carvalho Chehab 
191*4be5e864SMauro Carvalho Chehab 	return ret;
192*4be5e864SMauro Carvalho Chehab }
193*4be5e864SMauro Carvalho Chehab 
194*4be5e864SMauro Carvalho Chehab static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
195*4be5e864SMauro Carvalho Chehab {
196*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
197*4be5e864SMauro Carvalho Chehab 	u32 oar = (1 << logical_addr) << 16;
198*4be5e864SMauro Carvalho Chehab 	u32 val;
199*4be5e864SMauro Carvalho Chehab 
200*4be5e864SMauro Carvalho Chehab 	/* Poll every 100µs the register CEC_CR to wait end of transmission */
201*4be5e864SMauro Carvalho Chehab 	regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM),
202*4be5e864SMauro Carvalho Chehab 				 100, CEC_XFER_TIMEOUT_MS * 1000);
203*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
204*4be5e864SMauro Carvalho Chehab 
205*4be5e864SMauro Carvalho Chehab 	if (logical_addr == CEC_LOG_ADDR_INVALID)
206*4be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
207*4be5e864SMauro Carvalho Chehab 	else
208*4be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar);
209*4be5e864SMauro Carvalho Chehab 
210*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
211*4be5e864SMauro Carvalho Chehab 
212*4be5e864SMauro Carvalho Chehab 	return 0;
213*4be5e864SMauro Carvalho Chehab }
214*4be5e864SMauro Carvalho Chehab 
215*4be5e864SMauro Carvalho Chehab static int stm32_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
216*4be5e864SMauro Carvalho Chehab 				   u32 signal_free_time, struct cec_msg *msg)
217*4be5e864SMauro Carvalho Chehab {
218*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
219*4be5e864SMauro Carvalho Chehab 
220*4be5e864SMauro Carvalho Chehab 	/* Copy message */
221*4be5e864SMauro Carvalho Chehab 	cec->tx_msg = *msg;
222*4be5e864SMauro Carvalho Chehab 	cec->tx_cnt = 0;
223*4be5e864SMauro Carvalho Chehab 
224*4be5e864SMauro Carvalho Chehab 	/*
225*4be5e864SMauro Carvalho Chehab 	 * If the CEC message consists of only one byte,
226*4be5e864SMauro Carvalho Chehab 	 * TXEOM must be set before of TXSOM.
227*4be5e864SMauro Carvalho Chehab 	 */
228*4be5e864SMauro Carvalho Chehab 	if (cec->tx_msg.len == 1)
229*4be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
230*4be5e864SMauro Carvalho Chehab 
231*4be5e864SMauro Carvalho Chehab 	/* TXSOM is set to command transmission of the first byte */
232*4be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, TXSOM, TXSOM);
233*4be5e864SMauro Carvalho Chehab 
234*4be5e864SMauro Carvalho Chehab 	/* Write the header (first byte of message) */
235*4be5e864SMauro Carvalho Chehab 	regmap_write(cec->regmap, CEC_TXDR, cec->tx_msg.msg[0]);
236*4be5e864SMauro Carvalho Chehab 	cec->tx_cnt++;
237*4be5e864SMauro Carvalho Chehab 
238*4be5e864SMauro Carvalho Chehab 	return 0;
239*4be5e864SMauro Carvalho Chehab }
240*4be5e864SMauro Carvalho Chehab 
241*4be5e864SMauro Carvalho Chehab static const struct cec_adap_ops stm32_cec_adap_ops = {
242*4be5e864SMauro Carvalho Chehab 	.adap_enable = stm32_cec_adap_enable,
243*4be5e864SMauro Carvalho Chehab 	.adap_log_addr = stm32_cec_adap_log_addr,
244*4be5e864SMauro Carvalho Chehab 	.adap_transmit = stm32_cec_adap_transmit,
245*4be5e864SMauro Carvalho Chehab };
246*4be5e864SMauro Carvalho Chehab 
247*4be5e864SMauro Carvalho Chehab static const struct regmap_config stm32_cec_regmap_cfg = {
248*4be5e864SMauro Carvalho Chehab 	.reg_bits = 32,
249*4be5e864SMauro Carvalho Chehab 	.val_bits = 32,
250*4be5e864SMauro Carvalho Chehab 	.reg_stride = sizeof(u32),
251*4be5e864SMauro Carvalho Chehab 	.max_register = 0x14,
252*4be5e864SMauro Carvalho Chehab 	.fast_io = true,
253*4be5e864SMauro Carvalho Chehab };
254*4be5e864SMauro Carvalho Chehab 
255*4be5e864SMauro Carvalho Chehab static int stm32_cec_probe(struct platform_device *pdev)
256*4be5e864SMauro Carvalho Chehab {
257*4be5e864SMauro Carvalho Chehab 	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_MODE_MONITOR_ALL;
258*4be5e864SMauro Carvalho Chehab 	struct resource *res;
259*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec;
260*4be5e864SMauro Carvalho Chehab 	void __iomem *mmio;
261*4be5e864SMauro Carvalho Chehab 	int ret;
262*4be5e864SMauro Carvalho Chehab 
263*4be5e864SMauro Carvalho Chehab 	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
264*4be5e864SMauro Carvalho Chehab 	if (!cec)
265*4be5e864SMauro Carvalho Chehab 		return -ENOMEM;
266*4be5e864SMauro Carvalho Chehab 
267*4be5e864SMauro Carvalho Chehab 	cec->dev = &pdev->dev;
268*4be5e864SMauro Carvalho Chehab 
269*4be5e864SMauro Carvalho Chehab 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
270*4be5e864SMauro Carvalho Chehab 	mmio = devm_ioremap_resource(&pdev->dev, res);
271*4be5e864SMauro Carvalho Chehab 	if (IS_ERR(mmio))
272*4be5e864SMauro Carvalho Chehab 		return PTR_ERR(mmio);
273*4be5e864SMauro Carvalho Chehab 
274*4be5e864SMauro Carvalho Chehab 	cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio,
275*4be5e864SMauro Carvalho Chehab 						&stm32_cec_regmap_cfg);
276*4be5e864SMauro Carvalho Chehab 
277*4be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->regmap))
278*4be5e864SMauro Carvalho Chehab 		return PTR_ERR(cec->regmap);
279*4be5e864SMauro Carvalho Chehab 
280*4be5e864SMauro Carvalho Chehab 	cec->irq = platform_get_irq(pdev, 0);
281*4be5e864SMauro Carvalho Chehab 	if (cec->irq < 0)
282*4be5e864SMauro Carvalho Chehab 		return cec->irq;
283*4be5e864SMauro Carvalho Chehab 
284*4be5e864SMauro Carvalho Chehab 	ret = devm_request_threaded_irq(&pdev->dev, cec->irq,
285*4be5e864SMauro Carvalho Chehab 					stm32_cec_irq_handler,
286*4be5e864SMauro Carvalho Chehab 					stm32_cec_irq_thread,
287*4be5e864SMauro Carvalho Chehab 					0,
288*4be5e864SMauro Carvalho Chehab 					pdev->name, cec);
289*4be5e864SMauro Carvalho Chehab 	if (ret)
290*4be5e864SMauro Carvalho Chehab 		return ret;
291*4be5e864SMauro Carvalho Chehab 
292*4be5e864SMauro Carvalho Chehab 	cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
293*4be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->clk_cec)) {
294*4be5e864SMauro Carvalho Chehab 		if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER)
295*4be5e864SMauro Carvalho Chehab 			dev_err(&pdev->dev, "Cannot get cec clock\n");
296*4be5e864SMauro Carvalho Chehab 
297*4be5e864SMauro Carvalho Chehab 		return PTR_ERR(cec->clk_cec);
298*4be5e864SMauro Carvalho Chehab 	}
299*4be5e864SMauro Carvalho Chehab 
300*4be5e864SMauro Carvalho Chehab 	ret = clk_prepare(cec->clk_cec);
301*4be5e864SMauro Carvalho Chehab 	if (ret) {
302*4be5e864SMauro Carvalho Chehab 		dev_err(&pdev->dev, "Unable to prepare cec clock\n");
303*4be5e864SMauro Carvalho Chehab 		return ret;
304*4be5e864SMauro Carvalho Chehab 	}
305*4be5e864SMauro Carvalho Chehab 
306*4be5e864SMauro Carvalho Chehab 	cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
307*4be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->clk_hdmi_cec) &&
308*4be5e864SMauro Carvalho Chehab 	    PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER)
309*4be5e864SMauro Carvalho Chehab 		return -EPROBE_DEFER;
310*4be5e864SMauro Carvalho Chehab 
311*4be5e864SMauro Carvalho Chehab 	if (!IS_ERR(cec->clk_hdmi_cec)) {
312*4be5e864SMauro Carvalho Chehab 		ret = clk_prepare(cec->clk_hdmi_cec);
313*4be5e864SMauro Carvalho Chehab 		if (ret) {
314*4be5e864SMauro Carvalho Chehab 			dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n");
315*4be5e864SMauro Carvalho Chehab 			return ret;
316*4be5e864SMauro Carvalho Chehab 		}
317*4be5e864SMauro Carvalho Chehab 	}
318*4be5e864SMauro Carvalho Chehab 
319*4be5e864SMauro Carvalho Chehab 	/*
320*4be5e864SMauro Carvalho Chehab 	 * CEC_CAP_PHYS_ADDR caps should be removed when a cec notifier is
321*4be5e864SMauro Carvalho Chehab 	 * available for example when a drm driver can provide edid
322*4be5e864SMauro Carvalho Chehab 	 */
323*4be5e864SMauro Carvalho Chehab 	cec->adap = cec_allocate_adapter(&stm32_cec_adap_ops, cec,
324*4be5e864SMauro Carvalho Chehab 			CEC_NAME, caps,	CEC_MAX_LOG_ADDRS);
325*4be5e864SMauro Carvalho Chehab 	ret = PTR_ERR_OR_ZERO(cec->adap);
326*4be5e864SMauro Carvalho Chehab 	if (ret)
327*4be5e864SMauro Carvalho Chehab 		return ret;
328*4be5e864SMauro Carvalho Chehab 
329*4be5e864SMauro Carvalho Chehab 	ret = cec_register_adapter(cec->adap, &pdev->dev);
330*4be5e864SMauro Carvalho Chehab 	if (ret) {
331*4be5e864SMauro Carvalho Chehab 		cec_delete_adapter(cec->adap);
332*4be5e864SMauro Carvalho Chehab 		return ret;
333*4be5e864SMauro Carvalho Chehab 	}
334*4be5e864SMauro Carvalho Chehab 
335*4be5e864SMauro Carvalho Chehab 	cec_hw_init(cec);
336*4be5e864SMauro Carvalho Chehab 
337*4be5e864SMauro Carvalho Chehab 	platform_set_drvdata(pdev, cec);
338*4be5e864SMauro Carvalho Chehab 
339*4be5e864SMauro Carvalho Chehab 	return 0;
340*4be5e864SMauro Carvalho Chehab }
341*4be5e864SMauro Carvalho Chehab 
342*4be5e864SMauro Carvalho Chehab static int stm32_cec_remove(struct platform_device *pdev)
343*4be5e864SMauro Carvalho Chehab {
344*4be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = platform_get_drvdata(pdev);
345*4be5e864SMauro Carvalho Chehab 
346*4be5e864SMauro Carvalho Chehab 	clk_unprepare(cec->clk_cec);
347*4be5e864SMauro Carvalho Chehab 	clk_unprepare(cec->clk_hdmi_cec);
348*4be5e864SMauro Carvalho Chehab 
349*4be5e864SMauro Carvalho Chehab 	cec_unregister_adapter(cec->adap);
350*4be5e864SMauro Carvalho Chehab 
351*4be5e864SMauro Carvalho Chehab 	return 0;
352*4be5e864SMauro Carvalho Chehab }
353*4be5e864SMauro Carvalho Chehab 
354*4be5e864SMauro Carvalho Chehab static const struct of_device_id stm32_cec_of_match[] = {
355*4be5e864SMauro Carvalho Chehab 	{ .compatible = "st,stm32-cec" },
356*4be5e864SMauro Carvalho Chehab 	{ /* end node */ }
357*4be5e864SMauro Carvalho Chehab };
358*4be5e864SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
359*4be5e864SMauro Carvalho Chehab 
360*4be5e864SMauro Carvalho Chehab static struct platform_driver stm32_cec_driver = {
361*4be5e864SMauro Carvalho Chehab 	.probe  = stm32_cec_probe,
362*4be5e864SMauro Carvalho Chehab 	.remove = stm32_cec_remove,
363*4be5e864SMauro Carvalho Chehab 	.driver = {
364*4be5e864SMauro Carvalho Chehab 		.name		= CEC_NAME,
365*4be5e864SMauro Carvalho Chehab 		.of_match_table = stm32_cec_of_match,
366*4be5e864SMauro Carvalho Chehab 	},
367*4be5e864SMauro Carvalho Chehab };
368*4be5e864SMauro Carvalho Chehab 
369*4be5e864SMauro Carvalho Chehab module_platform_driver(stm32_cec_driver);
370*4be5e864SMauro Carvalho Chehab 
371*4be5e864SMauro Carvalho Chehab MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
372*4be5e864SMauro Carvalho Chehab MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
373*4be5e864SMauro Carvalho Chehab MODULE_DESCRIPTION("STMicroelectronics STM32 Consumer Electronics Control");
374*4be5e864SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
375