root/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. adv_cec_tx_raw_status
  2. adv7511_cec_irq_process
  3. adv7511_cec_adap_enable
  4. adv7511_cec_adap_log_addr
  5. adv7511_cec_adap_transmit
  6. adv7511_cec_parse_dt
  7. adv7511_cec_init

   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 
  35 static 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 
  87 void 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 
 131 static 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 
 178 static 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 
 247 static 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 
 283 static 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 
 289 static 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 
 303 int 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 
 339 err_cec_register:
 340         cec_delete_adapter(adv7511->cec_adap);
 341         adv7511->cec_adap = NULL;
 342 err_cec_alloc:
 343         dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
 344                  ret);
 345 err_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 }

/* [<][>][^][v][top][bottom][index][help] */