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