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