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