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