linux/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * adv7511_cec.c - Analog Devices ADV7511/33 cec driver
   4 *
   5 * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/module.h>
  10#include <linux/of_device.h>
  11#include <linux/slab.h>
  12#include <linux/clk.h>
  13
  14#include <media/cec.h>
  15
  16#include "adv7511.h"
  17
  18#define ADV7511_INT1_CEC_MASK \
  19        (ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
  20         ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1)
  21
  22static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
  23{
  24        unsigned int offset = adv7511->type == ADV7533 ?
  25                                        ADV7533_REG_CEC_OFFSET : 0;
  26        unsigned int val;
  27
  28        if (regmap_read(adv7511->regmap_cec,
  29                        ADV7511_REG_CEC_TX_ENABLE + offset, &val))
  30                return;
  31
  32        if ((val & 0x01) == 0)
  33                return;
  34
  35        if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
  36                cec_transmit_attempt_done(adv7511->cec_adap,
  37                                          CEC_TX_STATUS_ARB_LOST);
  38                return;
  39        }
  40        if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
  41                u8 status;
  42                u8 err_cnt = 0;
  43                u8 nack_cnt = 0;
  44                u8 low_drive_cnt = 0;
  45                unsigned int cnt;
  46
  47                /*
  48                 * We set this status bit since this hardware performs
  49                 * retransmissions.
  50                 */
  51                status = CEC_TX_STATUS_MAX_RETRIES;
  52                if (regmap_read(adv7511->regmap_cec,
  53                            ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {
  54                        err_cnt = 1;
  55                        status |= CEC_TX_STATUS_ERROR;
  56                } else {
  57                        nack_cnt = cnt & 0xf;
  58                        if (nack_cnt)
  59                                status |= CEC_TX_STATUS_NACK;
  60                        low_drive_cnt = cnt >> 4;
  61                        if (low_drive_cnt)
  62                                status |= CEC_TX_STATUS_LOW_DRIVE;
  63                }
  64                cec_transmit_done(adv7511->cec_adap, status,
  65                                  0, nack_cnt, low_drive_cnt, err_cnt);
  66                return;
  67        }
  68        if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
  69                cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
  70                return;
  71        }
  72}
  73
  74void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
  75{
  76        unsigned int offset = adv7511->type == ADV7533 ?
  77                                        ADV7533_REG_CEC_OFFSET : 0;
  78        const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
  79                                ADV7511_INT1_CEC_TX_ARBIT_LOST |
  80                                ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
  81        struct cec_msg msg = {};
  82        unsigned int len;
  83        unsigned int val;
  84        u8 i;
  85
  86        if (irq1 & irq_tx_mask)
  87                adv_cec_tx_raw_status(adv7511, irq1);
  88
  89        if (!(irq1 & ADV7511_INT1_CEC_RX_READY1))
  90                return;
  91
  92        if (regmap_read(adv7511->regmap_cec,
  93                        ADV7511_REG_CEC_RX_FRAME_LEN + offset, &len))
  94                return;
  95
  96        msg.len = len & 0x1f;
  97
  98        if (msg.len > 16)
  99                msg.len = 16;
 100
 101        if (!msg.len)
 102                return;
 103
 104        for (i = 0; i < msg.len; i++) {
 105                regmap_read(adv7511->regmap_cec,
 106                            i + ADV7511_REG_CEC_RX_FRAME_HDR + offset, &val);
 107                msg.msg[i] = val;
 108        }
 109
 110        /* toggle to re-enable rx 1 */
 111        regmap_write(adv7511->regmap_cec,
 112                     ADV7511_REG_CEC_RX_BUFFERS + offset, 1);
 113        regmap_write(adv7511->regmap_cec,
 114                     ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
 115        cec_received_msg(adv7511->cec_adap, &msg);
 116}
 117
 118static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
 119{
 120        struct adv7511 *adv7511 = cec_get_drvdata(adap);
 121        unsigned int offset = adv7511->type == ADV7533 ?
 122                                        ADV7533_REG_CEC_OFFSET : 0;
 123
 124        if (adv7511->i2c_cec == NULL)
 125                return -EIO;
 126
 127        if (!adv7511->cec_enabled_adap && enable) {
 128                /* power up cec section */
 129                regmap_update_bits(adv7511->regmap_cec,
 130                                   ADV7511_REG_CEC_CLK_DIV + offset,
 131                                   0x03, 0x01);
 132                /* legacy mode and clear all rx buffers */
 133                regmap_write(adv7511->regmap_cec,
 134                             ADV7511_REG_CEC_RX_BUFFERS + offset, 0x07);
 135                regmap_write(adv7511->regmap_cec,
 136                             ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
 137                /* initially disable tx */
 138                regmap_update_bits(adv7511->regmap_cec,
 139                                   ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
 140                /* enabled irqs: */
 141                /* tx: ready */
 142                /* tx: arbitration lost */
 143                /* tx: retry timeout */
 144                /* rx: ready 1 */
 145                regmap_update_bits(adv7511->regmap,
 146                                   ADV7511_REG_INT_ENABLE(1), 0x3f,
 147                                   ADV7511_INT1_CEC_MASK);
 148        } else if (adv7511->cec_enabled_adap && !enable) {
 149                regmap_update_bits(adv7511->regmap,
 150                                   ADV7511_REG_INT_ENABLE(1), 0x3f, 0);
 151                /* disable address mask 1-3 */
 152                regmap_update_bits(adv7511->regmap_cec,
 153                                   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
 154                                   0x70, 0x00);
 155                /* power down cec section */
 156                regmap_update_bits(adv7511->regmap_cec,
 157                                   ADV7511_REG_CEC_CLK_DIV + offset,
 158                                   0x03, 0x00);
 159                adv7511->cec_valid_addrs = 0;
 160        }
 161        adv7511->cec_enabled_adap = enable;
 162        return 0;
 163}
 164
 165static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
 166{
 167        struct adv7511 *adv7511 = cec_get_drvdata(adap);
 168        unsigned int offset = adv7511->type == ADV7533 ?
 169                                        ADV7533_REG_CEC_OFFSET : 0;
 170        unsigned int i, free_idx = ADV7511_MAX_ADDRS;
 171
 172        if (!adv7511->cec_enabled_adap)
 173                return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
 174
 175        if (addr == CEC_LOG_ADDR_INVALID) {
 176                regmap_update_bits(adv7511->regmap_cec,
 177                                   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
 178                                   0x70, 0);
 179                adv7511->cec_valid_addrs = 0;
 180                return 0;
 181        }
 182
 183        for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
 184                bool is_valid = adv7511->cec_valid_addrs & (1 << i);
 185
 186                if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
 187                        free_idx = i;
 188                if (is_valid && adv7511->cec_addr[i] == addr)
 189                        return 0;
 190        }
 191        if (i == ADV7511_MAX_ADDRS) {
 192                i = free_idx;
 193                if (i == ADV7511_MAX_ADDRS)
 194                        return -ENXIO;
 195        }
 196        adv7511->cec_addr[i] = addr;
 197        adv7511->cec_valid_addrs |= 1 << i;
 198
 199        switch (i) {
 200        case 0:
 201                /* enable address mask 0 */
 202                regmap_update_bits(adv7511->regmap_cec,
 203                                   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
 204                                   0x10, 0x10);
 205                /* set address for mask 0 */
 206                regmap_update_bits(adv7511->regmap_cec,
 207                                   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
 208                                   0x0f, addr);
 209                break;
 210        case 1:
 211                /* enable address mask 1 */
 212                regmap_update_bits(adv7511->regmap_cec,
 213                                   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
 214                                   0x20, 0x20);
 215                /* set address for mask 1 */
 216                regmap_update_bits(adv7511->regmap_cec,
 217                                   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
 218                                   0xf0, addr << 4);
 219                break;
 220        case 2:
 221                /* enable address mask 2 */
 222                regmap_update_bits(adv7511->regmap_cec,
 223                                   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
 224                                   0x40, 0x40);
 225                /* set address for mask 1 */
 226                regmap_update_bits(adv7511->regmap_cec,
 227                                   ADV7511_REG_CEC_LOG_ADDR_2 + offset,
 228                                   0x0f, addr);
 229                break;
 230        }
 231        return 0;
 232}
 233
 234static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
 235                                     u32 signal_free_time, struct cec_msg *msg)
 236{
 237        struct adv7511 *adv7511 = cec_get_drvdata(adap);
 238        unsigned int offset = adv7511->type == ADV7533 ?
 239                                        ADV7533_REG_CEC_OFFSET : 0;
 240        u8 len = msg->len;
 241        unsigned int i;
 242
 243        /*
 244         * The number of retries is the number of attempts - 1, but retry
 245         * at least once. It's not clear if a value of 0 is allowed, so
 246         * let's do at least one retry.
 247         */
 248        regmap_update_bits(adv7511->regmap_cec,
 249                           ADV7511_REG_CEC_TX_RETRY + offset,
 250                           0x70, max(1, attempts - 1) << 4);
 251
 252        /* blocking, clear cec tx irq status */
 253        regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
 254
 255        /* write data */
 256        for (i = 0; i < len; i++)
 257                regmap_write(adv7511->regmap_cec,
 258                             i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,
 259                             msg->msg[i]);
 260
 261        /* set length (data + header) */
 262        regmap_write(adv7511->regmap_cec,
 263                     ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
 264        /* start transmit, enable tx */
 265        regmap_write(adv7511->regmap_cec,
 266                     ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
 267        return 0;
 268}
 269
 270static const struct cec_adap_ops adv7511_cec_adap_ops = {
 271        .adap_enable = adv7511_cec_adap_enable,
 272        .adap_log_addr = adv7511_cec_adap_log_addr,
 273        .adap_transmit = adv7511_cec_adap_transmit,
 274};
 275
 276static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
 277{
 278        adv7511->cec_clk = devm_clk_get(dev, "cec");
 279        if (IS_ERR(adv7511->cec_clk)) {
 280                int ret = PTR_ERR(adv7511->cec_clk);
 281
 282                adv7511->cec_clk = NULL;
 283                return ret;
 284        }
 285        clk_prepare_enable(adv7511->cec_clk);
 286        adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
 287        return 0;
 288}
 289
 290int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 291{
 292        unsigned int offset = adv7511->type == ADV7533 ?
 293                                                ADV7533_REG_CEC_OFFSET : 0;
 294        int ret = adv7511_cec_parse_dt(dev, adv7511);
 295
 296        if (ret)
 297                goto err_cec_parse_dt;
 298
 299        adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
 300                adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
 301        if (IS_ERR(adv7511->cec_adap)) {
 302                ret = PTR_ERR(adv7511->cec_adap);
 303                goto err_cec_alloc;
 304        }
 305
 306        regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
 307        /* cec soft reset */
 308        regmap_write(adv7511->regmap_cec,
 309                     ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
 310        regmap_write(adv7511->regmap_cec,
 311                     ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
 312
 313        /* legacy mode */
 314        regmap_write(adv7511->regmap_cec,
 315                     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x00);
 316
 317        regmap_write(adv7511->regmap_cec,
 318                     ADV7511_REG_CEC_CLK_DIV + offset,
 319                     ((adv7511->cec_clk_freq / 750000) - 1) << 2);
 320
 321        ret = cec_register_adapter(adv7511->cec_adap, dev);
 322        if (ret)
 323                goto err_cec_register;
 324        return 0;
 325
 326err_cec_register:
 327        cec_delete_adapter(adv7511->cec_adap);
 328        adv7511->cec_adap = NULL;
 329err_cec_alloc:
 330        dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
 331                 ret);
 332err_cec_parse_dt:
 333        regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
 334                     ADV7511_CEC_CTRL_POWER_DOWN);
 335        return ret == -EPROBE_DEFER ? ret : 0;
 336}
 337