xref: /linux/drivers/media/cec/platform/stm32/stm32-cec.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
14be5e864SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
24be5e864SMauro Carvalho Chehab /*
34be5e864SMauro Carvalho Chehab  * STM32 CEC driver
44be5e864SMauro Carvalho Chehab  * Copyright (C) STMicroelectronics SA 2017
54be5e864SMauro Carvalho Chehab  *
64be5e864SMauro Carvalho Chehab  */
74be5e864SMauro Carvalho Chehab 
84be5e864SMauro Carvalho Chehab #include <linux/clk.h>
94be5e864SMauro Carvalho Chehab #include <linux/interrupt.h>
104be5e864SMauro Carvalho Chehab #include <linux/kernel.h>
114be5e864SMauro Carvalho Chehab #include <linux/module.h>
124be5e864SMauro Carvalho Chehab #include <linux/of.h>
134be5e864SMauro Carvalho Chehab #include <linux/platform_device.h>
144be5e864SMauro Carvalho Chehab #include <linux/regmap.h>
154be5e864SMauro Carvalho Chehab 
164be5e864SMauro Carvalho Chehab #include <media/cec.h>
174be5e864SMauro Carvalho Chehab 
184be5e864SMauro Carvalho Chehab #define CEC_NAME	"stm32-cec"
194be5e864SMauro Carvalho Chehab 
204be5e864SMauro Carvalho Chehab /* CEC registers  */
214be5e864SMauro Carvalho Chehab #define CEC_CR		0x0000 /* Control Register */
224be5e864SMauro Carvalho Chehab #define CEC_CFGR	0x0004 /* ConFiGuration Register */
234be5e864SMauro Carvalho Chehab #define CEC_TXDR	0x0008 /* Rx data Register */
244be5e864SMauro Carvalho Chehab #define CEC_RXDR	0x000C /* Rx data Register */
254be5e864SMauro Carvalho Chehab #define CEC_ISR		0x0010 /* Interrupt and status Register */
264be5e864SMauro Carvalho Chehab #define CEC_IER		0x0014 /* Interrupt enable Register */
274be5e864SMauro Carvalho Chehab 
284be5e864SMauro Carvalho Chehab #define TXEOM		BIT(2)
294be5e864SMauro Carvalho Chehab #define TXSOM		BIT(1)
304be5e864SMauro Carvalho Chehab #define CECEN		BIT(0)
314be5e864SMauro Carvalho Chehab 
324be5e864SMauro Carvalho Chehab #define LSTN		BIT(31)
334be5e864SMauro Carvalho Chehab #define OAR		GENMASK(30, 16)
344be5e864SMauro Carvalho Chehab #define SFTOP		BIT(8)
354be5e864SMauro Carvalho Chehab #define BRDNOGEN	BIT(7)
364be5e864SMauro Carvalho Chehab #define LBPEGEN		BIT(6)
374be5e864SMauro Carvalho Chehab #define BREGEN		BIT(5)
384be5e864SMauro Carvalho Chehab #define BRESTP		BIT(4)
394be5e864SMauro Carvalho Chehab #define RXTOL		BIT(3)
404be5e864SMauro Carvalho Chehab #define SFT		GENMASK(2, 0)
414be5e864SMauro Carvalho Chehab #define FULL_CFG	(LSTN | SFTOP | BRDNOGEN | LBPEGEN | BREGEN | BRESTP \
424be5e864SMauro Carvalho Chehab 			 | RXTOL)
434be5e864SMauro Carvalho Chehab 
444be5e864SMauro Carvalho Chehab #define TXACKE		BIT(12)
454be5e864SMauro Carvalho Chehab #define TXERR		BIT(11)
464be5e864SMauro Carvalho Chehab #define TXUDR		BIT(10)
474be5e864SMauro Carvalho Chehab #define TXEND		BIT(9)
484be5e864SMauro Carvalho Chehab #define TXBR		BIT(8)
494be5e864SMauro Carvalho Chehab #define ARBLST		BIT(7)
504be5e864SMauro Carvalho Chehab #define RXACKE		BIT(6)
514be5e864SMauro Carvalho Chehab #define RXOVR		BIT(2)
524be5e864SMauro Carvalho Chehab #define RXEND		BIT(1)
534be5e864SMauro Carvalho Chehab #define RXBR		BIT(0)
544be5e864SMauro Carvalho Chehab 
554be5e864SMauro Carvalho Chehab #define ALL_TX_IT	(TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST)
564be5e864SMauro Carvalho Chehab #define ALL_RX_IT	(RXEND | RXBR | RXACKE | RXOVR)
574be5e864SMauro Carvalho Chehab 
584be5e864SMauro Carvalho Chehab /*
594be5e864SMauro Carvalho Chehab  * 400 ms is the time it takes for one 16 byte message to be
604be5e864SMauro Carvalho Chehab  * transferred and 5 is the maximum number of retries. Add
614be5e864SMauro Carvalho Chehab  * another 100 ms as a margin.
624be5e864SMauro Carvalho Chehab  */
634be5e864SMauro Carvalho Chehab #define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
644be5e864SMauro Carvalho Chehab 
654be5e864SMauro Carvalho Chehab struct stm32_cec {
664be5e864SMauro Carvalho Chehab 	struct cec_adapter	*adap;
674be5e864SMauro Carvalho Chehab 	struct device		*dev;
684be5e864SMauro Carvalho Chehab 	struct clk		*clk_cec;
694be5e864SMauro Carvalho Chehab 	struct clk		*clk_hdmi_cec;
704be5e864SMauro Carvalho Chehab 	struct reset_control	*rstc;
714be5e864SMauro Carvalho Chehab 	struct regmap		*regmap;
724be5e864SMauro Carvalho Chehab 	int			irq;
734be5e864SMauro Carvalho Chehab 	u32			irq_status;
744be5e864SMauro Carvalho Chehab 	struct cec_msg		rx_msg;
754be5e864SMauro Carvalho Chehab 	struct cec_msg		tx_msg;
764be5e864SMauro Carvalho Chehab 	int			tx_cnt;
774be5e864SMauro Carvalho Chehab };
784be5e864SMauro Carvalho Chehab 
cec_hw_init(struct stm32_cec * cec)794be5e864SMauro Carvalho Chehab static void cec_hw_init(struct stm32_cec *cec)
804be5e864SMauro Carvalho Chehab {
814be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0);
824be5e864SMauro Carvalho Chehab 
834be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT,
844be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT);
854be5e864SMauro Carvalho Chehab 
864be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG);
874be5e864SMauro Carvalho Chehab }
884be5e864SMauro Carvalho Chehab 
stm32_tx_done(struct stm32_cec * cec,u32 status)894be5e864SMauro Carvalho Chehab static void stm32_tx_done(struct stm32_cec *cec, u32 status)
904be5e864SMauro Carvalho Chehab {
914be5e864SMauro Carvalho Chehab 	if (status & (TXERR | TXUDR)) {
924be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR,
934be5e864SMauro Carvalho Chehab 				  0, 0, 0, 1);
944be5e864SMauro Carvalho Chehab 		return;
954be5e864SMauro Carvalho Chehab 	}
964be5e864SMauro Carvalho Chehab 
974be5e864SMauro Carvalho Chehab 	if (status & ARBLST) {
984be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST,
994be5e864SMauro Carvalho Chehab 				  1, 0, 0, 0);
1004be5e864SMauro Carvalho Chehab 		return;
1014be5e864SMauro Carvalho Chehab 	}
1024be5e864SMauro Carvalho Chehab 
1034be5e864SMauro Carvalho Chehab 	if (status & TXACKE) {
1044be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK,
1054be5e864SMauro Carvalho Chehab 				  0, 1, 0, 0);
1064be5e864SMauro Carvalho Chehab 		return;
1074be5e864SMauro Carvalho Chehab 	}
1084be5e864SMauro Carvalho Chehab 
1094be5e864SMauro Carvalho Chehab 	if (cec->irq_status & TXBR) {
1104be5e864SMauro Carvalho Chehab 		/* send next byte */
1114be5e864SMauro Carvalho Chehab 		if (cec->tx_cnt < cec->tx_msg.len)
1124be5e864SMauro Carvalho Chehab 			regmap_write(cec->regmap, CEC_TXDR,
1134be5e864SMauro Carvalho Chehab 				     cec->tx_msg.msg[cec->tx_cnt++]);
1144be5e864SMauro Carvalho Chehab 
1154be5e864SMauro Carvalho Chehab 		/* TXEOM is set to command transmission of the last byte */
1164be5e864SMauro Carvalho Chehab 		if (cec->tx_cnt == cec->tx_msg.len)
1174be5e864SMauro Carvalho Chehab 			regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
1184be5e864SMauro Carvalho Chehab 	}
1194be5e864SMauro Carvalho Chehab 
1204be5e864SMauro Carvalho Chehab 	if (cec->irq_status & TXEND)
1214be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
1224be5e864SMauro Carvalho Chehab }
1234be5e864SMauro Carvalho Chehab 
stm32_rx_done(struct stm32_cec * cec,u32 status)1244be5e864SMauro Carvalho Chehab static void stm32_rx_done(struct stm32_cec *cec, u32 status)
1254be5e864SMauro Carvalho Chehab {
1264be5e864SMauro Carvalho Chehab 	if (cec->irq_status & (RXACKE | RXOVR)) {
1274be5e864SMauro Carvalho Chehab 		cec->rx_msg.len = 0;
1284be5e864SMauro Carvalho Chehab 		return;
1294be5e864SMauro Carvalho Chehab 	}
1304be5e864SMauro Carvalho Chehab 
1314be5e864SMauro Carvalho Chehab 	if (cec->irq_status & RXBR) {
1324be5e864SMauro Carvalho Chehab 		u32 val;
1334be5e864SMauro Carvalho Chehab 
1344be5e864SMauro Carvalho Chehab 		regmap_read(cec->regmap, CEC_RXDR, &val);
1354be5e864SMauro Carvalho Chehab 		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
1364be5e864SMauro Carvalho Chehab 	}
1374be5e864SMauro Carvalho Chehab 
1384be5e864SMauro Carvalho Chehab 	if (cec->irq_status & RXEND) {
1394be5e864SMauro Carvalho Chehab 		cec_received_msg(cec->adap, &cec->rx_msg);
1404be5e864SMauro Carvalho Chehab 		cec->rx_msg.len = 0;
1414be5e864SMauro Carvalho Chehab 	}
1424be5e864SMauro Carvalho Chehab }
1434be5e864SMauro Carvalho Chehab 
stm32_cec_irq_thread(int irq,void * arg)1444be5e864SMauro Carvalho Chehab static irqreturn_t stm32_cec_irq_thread(int irq, void *arg)
1454be5e864SMauro Carvalho Chehab {
1464be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = arg;
1474be5e864SMauro Carvalho Chehab 
1484be5e864SMauro Carvalho Chehab 	if (cec->irq_status & ALL_TX_IT)
1494be5e864SMauro Carvalho Chehab 		stm32_tx_done(cec, cec->irq_status);
1504be5e864SMauro Carvalho Chehab 
1514be5e864SMauro Carvalho Chehab 	if (cec->irq_status & ALL_RX_IT)
1524be5e864SMauro Carvalho Chehab 		stm32_rx_done(cec, cec->irq_status);
1534be5e864SMauro Carvalho Chehab 
1544be5e864SMauro Carvalho Chehab 	cec->irq_status = 0;
1554be5e864SMauro Carvalho Chehab 
1564be5e864SMauro Carvalho Chehab 	return IRQ_HANDLED;
1574be5e864SMauro Carvalho Chehab }
1584be5e864SMauro Carvalho Chehab 
stm32_cec_irq_handler(int irq,void * arg)1594be5e864SMauro Carvalho Chehab static irqreturn_t stm32_cec_irq_handler(int irq, void *arg)
1604be5e864SMauro Carvalho Chehab {
1614be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = arg;
1624be5e864SMauro Carvalho Chehab 
1634be5e864SMauro Carvalho Chehab 	regmap_read(cec->regmap, CEC_ISR, &cec->irq_status);
1644be5e864SMauro Carvalho Chehab 
1654be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_ISR,
1664be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT,
1674be5e864SMauro Carvalho Chehab 			   ALL_TX_IT | ALL_RX_IT);
1684be5e864SMauro Carvalho Chehab 
1694be5e864SMauro Carvalho Chehab 	return IRQ_WAKE_THREAD;
1704be5e864SMauro Carvalho Chehab }
1714be5e864SMauro Carvalho Chehab 
stm32_cec_adap_enable(struct cec_adapter * adap,bool enable)1724be5e864SMauro Carvalho Chehab static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable)
1734be5e864SMauro Carvalho Chehab {
1744be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
1754be5e864SMauro Carvalho Chehab 	int ret = 0;
1764be5e864SMauro Carvalho Chehab 
1774be5e864SMauro Carvalho Chehab 	if (enable) {
1784be5e864SMauro Carvalho Chehab 		ret = clk_enable(cec->clk_cec);
1794be5e864SMauro Carvalho Chehab 		if (ret)
1804be5e864SMauro Carvalho Chehab 			dev_err(cec->dev, "fail to enable cec clock\n");
1814be5e864SMauro Carvalho Chehab 
1824be5e864SMauro Carvalho Chehab 		clk_enable(cec->clk_hdmi_cec);
1834be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
1844be5e864SMauro Carvalho Chehab 	} else {
1854be5e864SMauro Carvalho Chehab 		clk_disable(cec->clk_cec);
1864be5e864SMauro Carvalho Chehab 		clk_disable(cec->clk_hdmi_cec);
1874be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
1884be5e864SMauro Carvalho Chehab 	}
1894be5e864SMauro Carvalho Chehab 
1904be5e864SMauro Carvalho Chehab 	return ret;
1914be5e864SMauro Carvalho Chehab }
1924be5e864SMauro Carvalho Chehab 
stm32_cec_adap_log_addr(struct cec_adapter * adap,u8 logical_addr)1934be5e864SMauro Carvalho Chehab static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
1944be5e864SMauro Carvalho Chehab {
1954be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
1964be5e864SMauro Carvalho Chehab 	u32 oar = (1 << logical_addr) << 16;
1974be5e864SMauro Carvalho Chehab 	u32 val;
1984be5e864SMauro Carvalho Chehab 
1994be5e864SMauro Carvalho Chehab 	/* Poll every 100µs the register CEC_CR to wait end of transmission */
2004be5e864SMauro Carvalho Chehab 	regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM),
2014be5e864SMauro Carvalho Chehab 				 100, CEC_XFER_TIMEOUT_MS * 1000);
2024be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
2034be5e864SMauro Carvalho Chehab 
2044be5e864SMauro Carvalho Chehab 	if (logical_addr == CEC_LOG_ADDR_INVALID)
2054be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
2064be5e864SMauro Carvalho Chehab 	else
2074be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar);
2084be5e864SMauro Carvalho Chehab 
2094be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
2104be5e864SMauro Carvalho Chehab 
2114be5e864SMauro Carvalho Chehab 	return 0;
2124be5e864SMauro Carvalho Chehab }
2134be5e864SMauro Carvalho Chehab 
stm32_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)2144be5e864SMauro Carvalho Chehab static int stm32_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
2154be5e864SMauro Carvalho Chehab 				   u32 signal_free_time, struct cec_msg *msg)
2164be5e864SMauro Carvalho Chehab {
2174be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = adap->priv;
2184be5e864SMauro Carvalho Chehab 
2194be5e864SMauro Carvalho Chehab 	/* Copy message */
2204be5e864SMauro Carvalho Chehab 	cec->tx_msg = *msg;
2214be5e864SMauro Carvalho Chehab 	cec->tx_cnt = 0;
2224be5e864SMauro Carvalho Chehab 
2234be5e864SMauro Carvalho Chehab 	/*
2244be5e864SMauro Carvalho Chehab 	 * If the CEC message consists of only one byte,
2254be5e864SMauro Carvalho Chehab 	 * TXEOM must be set before of TXSOM.
2264be5e864SMauro Carvalho Chehab 	 */
2274be5e864SMauro Carvalho Chehab 	if (cec->tx_msg.len == 1)
2284be5e864SMauro Carvalho Chehab 		regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
2294be5e864SMauro Carvalho Chehab 
2304be5e864SMauro Carvalho Chehab 	/* TXSOM is set to command transmission of the first byte */
2314be5e864SMauro Carvalho Chehab 	regmap_update_bits(cec->regmap, CEC_CR, TXSOM, TXSOM);
2324be5e864SMauro Carvalho Chehab 
2334be5e864SMauro Carvalho Chehab 	/* Write the header (first byte of message) */
2344be5e864SMauro Carvalho Chehab 	regmap_write(cec->regmap, CEC_TXDR, cec->tx_msg.msg[0]);
2354be5e864SMauro Carvalho Chehab 	cec->tx_cnt++;
2364be5e864SMauro Carvalho Chehab 
2374be5e864SMauro Carvalho Chehab 	return 0;
2384be5e864SMauro Carvalho Chehab }
2394be5e864SMauro Carvalho Chehab 
2404be5e864SMauro Carvalho Chehab static const struct cec_adap_ops stm32_cec_adap_ops = {
2414be5e864SMauro Carvalho Chehab 	.adap_enable = stm32_cec_adap_enable,
2424be5e864SMauro Carvalho Chehab 	.adap_log_addr = stm32_cec_adap_log_addr,
2434be5e864SMauro Carvalho Chehab 	.adap_transmit = stm32_cec_adap_transmit,
2444be5e864SMauro Carvalho Chehab };
2454be5e864SMauro Carvalho Chehab 
2464be5e864SMauro Carvalho Chehab static const struct regmap_config stm32_cec_regmap_cfg = {
2474be5e864SMauro Carvalho Chehab 	.reg_bits = 32,
2484be5e864SMauro Carvalho Chehab 	.val_bits = 32,
2494be5e864SMauro Carvalho Chehab 	.reg_stride = sizeof(u32),
2504be5e864SMauro Carvalho Chehab 	.max_register = 0x14,
2514be5e864SMauro Carvalho Chehab 	.fast_io = true,
2524be5e864SMauro Carvalho Chehab };
2534be5e864SMauro Carvalho Chehab 
stm32_cec_probe(struct platform_device * pdev)2544be5e864SMauro Carvalho Chehab static int stm32_cec_probe(struct platform_device *pdev)
2554be5e864SMauro Carvalho Chehab {
2564be5e864SMauro Carvalho Chehab 	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_MODE_MONITOR_ALL;
2574be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec;
2584be5e864SMauro Carvalho Chehab 	void __iomem *mmio;
2594be5e864SMauro Carvalho Chehab 	int ret;
2604be5e864SMauro Carvalho Chehab 
2614be5e864SMauro Carvalho Chehab 	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
2624be5e864SMauro Carvalho Chehab 	if (!cec)
2634be5e864SMauro Carvalho Chehab 		return -ENOMEM;
2644be5e864SMauro Carvalho Chehab 
2654be5e864SMauro Carvalho Chehab 	cec->dev = &pdev->dev;
2664be5e864SMauro Carvalho Chehab 
267092c69b2SCai Huoqing 	mmio = devm_platform_ioremap_resource(pdev, 0);
2684be5e864SMauro Carvalho Chehab 	if (IS_ERR(mmio))
2694be5e864SMauro Carvalho Chehab 		return PTR_ERR(mmio);
2704be5e864SMauro Carvalho Chehab 
2714be5e864SMauro Carvalho Chehab 	cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio,
2724be5e864SMauro Carvalho Chehab 						&stm32_cec_regmap_cfg);
2734be5e864SMauro Carvalho Chehab 
2744be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->regmap))
2754be5e864SMauro Carvalho Chehab 		return PTR_ERR(cec->regmap);
2764be5e864SMauro Carvalho Chehab 
2774be5e864SMauro Carvalho Chehab 	cec->irq = platform_get_irq(pdev, 0);
2784be5e864SMauro Carvalho Chehab 	if (cec->irq < 0)
2794be5e864SMauro Carvalho Chehab 		return cec->irq;
2804be5e864SMauro Carvalho Chehab 
2814be5e864SMauro Carvalho Chehab 	ret = devm_request_threaded_irq(&pdev->dev, cec->irq,
2824be5e864SMauro Carvalho Chehab 					stm32_cec_irq_handler,
2834be5e864SMauro Carvalho Chehab 					stm32_cec_irq_thread,
2844be5e864SMauro Carvalho Chehab 					0,
2854be5e864SMauro Carvalho Chehab 					pdev->name, cec);
2864be5e864SMauro Carvalho Chehab 	if (ret)
2874be5e864SMauro Carvalho Chehab 		return ret;
2884be5e864SMauro Carvalho Chehab 
2894be5e864SMauro Carvalho Chehab 	cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
2906cb7d1b3SYang Yingliang 	if (IS_ERR(cec->clk_cec))
2916cb7d1b3SYang Yingliang 		return dev_err_probe(&pdev->dev, PTR_ERR(cec->clk_cec),
2926cb7d1b3SYang Yingliang 				     "Cannot get cec clock\n");
2934be5e864SMauro Carvalho Chehab 
2944be5e864SMauro Carvalho Chehab 	ret = clk_prepare(cec->clk_cec);
2954be5e864SMauro Carvalho Chehab 	if (ret) {
2964be5e864SMauro Carvalho Chehab 		dev_err(&pdev->dev, "Unable to prepare cec clock\n");
2974be5e864SMauro Carvalho Chehab 		return ret;
2984be5e864SMauro Carvalho Chehab 	}
2994be5e864SMauro Carvalho Chehab 
3004be5e864SMauro Carvalho Chehab 	cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
3014be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->clk_hdmi_cec) &&
302055d2db2SEvgeny Novikov 	    PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) {
303055d2db2SEvgeny Novikov 		ret = -EPROBE_DEFER;
304055d2db2SEvgeny Novikov 		goto err_unprepare_cec_clk;
305055d2db2SEvgeny Novikov 	}
3064be5e864SMauro Carvalho Chehab 
3074be5e864SMauro Carvalho Chehab 	if (!IS_ERR(cec->clk_hdmi_cec)) {
3084be5e864SMauro Carvalho Chehab 		ret = clk_prepare(cec->clk_hdmi_cec);
3094be5e864SMauro Carvalho Chehab 		if (ret) {
3104be5e864SMauro Carvalho Chehab 			dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n");
311055d2db2SEvgeny Novikov 			goto err_unprepare_cec_clk;
3124be5e864SMauro Carvalho Chehab 		}
3134be5e864SMauro Carvalho Chehab 	}
3144be5e864SMauro Carvalho Chehab 
3154be5e864SMauro Carvalho Chehab 	/*
3164be5e864SMauro Carvalho Chehab 	 * CEC_CAP_PHYS_ADDR caps should be removed when a cec notifier is
3174be5e864SMauro Carvalho Chehab 	 * available for example when a drm driver can provide edid
3184be5e864SMauro Carvalho Chehab 	 */
3194be5e864SMauro Carvalho Chehab 	cec->adap = cec_allocate_adapter(&stm32_cec_adap_ops, cec,
3204be5e864SMauro Carvalho Chehab 			CEC_NAME, caps,	CEC_MAX_LOG_ADDRS);
3214be5e864SMauro Carvalho Chehab 	ret = PTR_ERR_OR_ZERO(cec->adap);
3224be5e864SMauro Carvalho Chehab 	if (ret)
323055d2db2SEvgeny Novikov 		goto err_unprepare_hdmi_cec_clk;
3244be5e864SMauro Carvalho Chehab 
3254be5e864SMauro Carvalho Chehab 	ret = cec_register_adapter(cec->adap, &pdev->dev);
326055d2db2SEvgeny Novikov 	if (ret)
327055d2db2SEvgeny Novikov 		goto err_delete_adapter;
3284be5e864SMauro Carvalho Chehab 
3294be5e864SMauro Carvalho Chehab 	cec_hw_init(cec);
3304be5e864SMauro Carvalho Chehab 
3314be5e864SMauro Carvalho Chehab 	platform_set_drvdata(pdev, cec);
3324be5e864SMauro Carvalho Chehab 
3334be5e864SMauro Carvalho Chehab 	return 0;
334055d2db2SEvgeny Novikov 
335055d2db2SEvgeny Novikov err_delete_adapter:
336055d2db2SEvgeny Novikov 	cec_delete_adapter(cec->adap);
337055d2db2SEvgeny Novikov 
338055d2db2SEvgeny Novikov err_unprepare_hdmi_cec_clk:
339055d2db2SEvgeny Novikov 	clk_unprepare(cec->clk_hdmi_cec);
340055d2db2SEvgeny Novikov 
341055d2db2SEvgeny Novikov err_unprepare_cec_clk:
342055d2db2SEvgeny Novikov 	clk_unprepare(cec->clk_cec);
343055d2db2SEvgeny Novikov 	return ret;
3444be5e864SMauro Carvalho Chehab }
3454be5e864SMauro Carvalho Chehab 
stm32_cec_remove(struct platform_device * pdev)346*1bef2ac8SUwe Kleine-König static void stm32_cec_remove(struct platform_device *pdev)
3474be5e864SMauro Carvalho Chehab {
3484be5e864SMauro Carvalho Chehab 	struct stm32_cec *cec = platform_get_drvdata(pdev);
3494be5e864SMauro Carvalho Chehab 
3504be5e864SMauro Carvalho Chehab 	clk_unprepare(cec->clk_cec);
3514be5e864SMauro Carvalho Chehab 	clk_unprepare(cec->clk_hdmi_cec);
3524be5e864SMauro Carvalho Chehab 
3534be5e864SMauro Carvalho Chehab 	cec_unregister_adapter(cec->adap);
3544be5e864SMauro Carvalho Chehab }
3554be5e864SMauro Carvalho Chehab 
3564be5e864SMauro Carvalho Chehab static const struct of_device_id stm32_cec_of_match[] = {
3574be5e864SMauro Carvalho Chehab 	{ .compatible = "st,stm32-cec" },
3584be5e864SMauro Carvalho Chehab 	{ /* end node */ }
3594be5e864SMauro Carvalho Chehab };
3604be5e864SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
3614be5e864SMauro Carvalho Chehab 
3624be5e864SMauro Carvalho Chehab static struct platform_driver stm32_cec_driver = {
3634be5e864SMauro Carvalho Chehab 	.probe  = stm32_cec_probe,
364*1bef2ac8SUwe Kleine-König 	.remove_new = stm32_cec_remove,
3654be5e864SMauro Carvalho Chehab 	.driver = {
3664be5e864SMauro Carvalho Chehab 		.name		= CEC_NAME,
3674be5e864SMauro Carvalho Chehab 		.of_match_table = stm32_cec_of_match,
3684be5e864SMauro Carvalho Chehab 	},
3694be5e864SMauro Carvalho Chehab };
3704be5e864SMauro Carvalho Chehab 
3714be5e864SMauro Carvalho Chehab module_platform_driver(stm32_cec_driver);
3724be5e864SMauro Carvalho Chehab 
3734be5e864SMauro Carvalho Chehab MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
3744be5e864SMauro Carvalho Chehab MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
3754be5e864SMauro Carvalho Chehab MODULE_DESCRIPTION("STMicroelectronics STM32 Consumer Electronics Control");
3764be5e864SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
377