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