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