root/drivers/media/platform/tegra-cec/tegra_cec.c

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

DEFINITIONS

This source file includes following definitions.
  1. cec_read
  2. cec_write
  3. tegra_cec_error_recovery
  4. tegra_cec_irq_thread_handler
  5. tegra_cec_irq_handler
  6. tegra_cec_adap_enable
  7. tegra_cec_adap_log_addr
  8. tegra_cec_adap_monitor_all_enable
  9. tegra_cec_adap_transmit
  10. tegra_cec_probe
  11. tegra_cec_remove
  12. tegra_cec_suspend
  13. tegra_cec_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Tegra CEC implementation
   4  *
   5  * The original 3.10 CEC driver using a custom API:
   6  *
   7  * Copyright (c) 2012-2015, NVIDIA CORPORATION.  All rights reserved.
   8  *
   9  * Conversion to the CEC framework and to the mainline kernel:
  10  *
  11  * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  12  */
  13 
  14 #include <linux/module.h>
  15 #include <linux/kernel.h>
  16 #include <linux/err.h>
  17 #include <linux/errno.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/slab.h>
  20 #include <linux/io.h>
  21 #include <linux/clk.h>
  22 #include <linux/delay.h>
  23 #include <linux/pm.h>
  24 #include <linux/of.h>
  25 #include <linux/of_platform.h>
  26 #include <linux/platform_device.h>
  27 #include <linux/clk/tegra.h>
  28 
  29 #include <media/cec-notifier.h>
  30 
  31 #include "tegra_cec.h"
  32 
  33 #define TEGRA_CEC_NAME "tegra-cec"
  34 
  35 struct tegra_cec {
  36         struct cec_adapter      *adap;
  37         struct device           *dev;
  38         struct clk              *clk;
  39         void __iomem            *cec_base;
  40         struct cec_notifier     *notifier;
  41         int                     tegra_cec_irq;
  42         bool                    rx_done;
  43         bool                    tx_done;
  44         int                     tx_status;
  45         u8                      rx_buf[CEC_MAX_MSG_SIZE];
  46         u8                      rx_buf_cnt;
  47         u32                     tx_buf[CEC_MAX_MSG_SIZE];
  48         u8                      tx_buf_cur;
  49         u8                      tx_buf_cnt;
  50 };
  51 
  52 static inline u32 cec_read(struct tegra_cec *cec, u32 reg)
  53 {
  54         return readl(cec->cec_base + reg);
  55 }
  56 
  57 static inline void cec_write(struct tegra_cec *cec, u32 reg, u32 val)
  58 {
  59         writel(val, cec->cec_base + reg);
  60 }
  61 
  62 static void tegra_cec_error_recovery(struct tegra_cec *cec)
  63 {
  64         u32 hw_ctrl;
  65 
  66         hw_ctrl = cec_read(cec, TEGRA_CEC_HW_CONTROL);
  67         cec_write(cec, TEGRA_CEC_HW_CONTROL, 0);
  68         cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff);
  69         cec_write(cec, TEGRA_CEC_HW_CONTROL, hw_ctrl);
  70 }
  71 
  72 static irqreturn_t tegra_cec_irq_thread_handler(int irq, void *data)
  73 {
  74         struct device *dev = data;
  75         struct tegra_cec *cec = dev_get_drvdata(dev);
  76 
  77         if (cec->tx_done) {
  78                 cec_transmit_attempt_done(cec->adap, cec->tx_status);
  79                 cec->tx_done = false;
  80         }
  81         if (cec->rx_done) {
  82                 struct cec_msg msg = {};
  83 
  84                 msg.len = cec->rx_buf_cnt;
  85                 memcpy(msg.msg, cec->rx_buf, msg.len);
  86                 cec_received_msg(cec->adap, &msg);
  87                 cec->rx_done = false;
  88                 cec->rx_buf_cnt = 0;
  89         }
  90         return IRQ_HANDLED;
  91 }
  92 
  93 static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
  94 {
  95         struct device *dev = data;
  96         struct tegra_cec *cec = dev_get_drvdata(dev);
  97         u32 status, mask;
  98 
  99         status = cec_read(cec, TEGRA_CEC_INT_STAT);
 100         mask = cec_read(cec, TEGRA_CEC_INT_MASK);
 101 
 102         status &= mask;
 103 
 104         if (!status)
 105                 return IRQ_HANDLED;
 106 
 107         if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) {
 108                 dev_err(dev, "TX underrun, interrupt timing issue!\n");
 109 
 110                 tegra_cec_error_recovery(cec);
 111                 cec_write(cec, TEGRA_CEC_INT_MASK,
 112                           mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);
 113 
 114                 cec->tx_done = true;
 115                 cec->tx_status = CEC_TX_STATUS_ERROR;
 116                 return IRQ_WAKE_THREAD;
 117         }
 118 
 119         if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) ||
 120                    (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) {
 121                 tegra_cec_error_recovery(cec);
 122                 cec_write(cec, TEGRA_CEC_INT_MASK,
 123                           mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);
 124 
 125                 cec->tx_done = true;
 126                 if (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)
 127                         cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
 128                 else
 129                         cec->tx_status = CEC_TX_STATUS_ARB_LOST;
 130                 return IRQ_WAKE_THREAD;
 131         }
 132 
 133         if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) {
 134                 cec_write(cec, TEGRA_CEC_INT_STAT,
 135                           TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED);
 136 
 137                 if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) {
 138                         tegra_cec_error_recovery(cec);
 139 
 140                         cec->tx_done = true;
 141                         cec->tx_status = CEC_TX_STATUS_NACK;
 142                 } else {
 143                         cec->tx_done = true;
 144                         cec->tx_status = CEC_TX_STATUS_OK;
 145                 }
 146                 return IRQ_WAKE_THREAD;
 147         }
 148 
 149         if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD)
 150                 dev_warn(dev, "TX NAKed on the fly!\n");
 151 
 152         if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) {
 153                 if (cec->tx_buf_cur == cec->tx_buf_cnt) {
 154                         cec_write(cec, TEGRA_CEC_INT_MASK,
 155                                   mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);
 156                 } else {
 157                         cec_write(cec, TEGRA_CEC_TX_REGISTER,
 158                                   cec->tx_buf[cec->tx_buf_cur++]);
 159                         cec_write(cec, TEGRA_CEC_INT_STAT,
 160                                   TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY);
 161                 }
 162         }
 163 
 164         if (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) {
 165                 cec_write(cec, TEGRA_CEC_INT_STAT,
 166                           TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED);
 167                 cec->rx_done = false;
 168                 cec->rx_buf_cnt = 0;
 169         }
 170         if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
 171                 u32 v;
 172 
 173                 cec_write(cec, TEGRA_CEC_INT_STAT,
 174                           TEGRA_CEC_INT_STAT_RX_REGISTER_FULL);
 175                 v = cec_read(cec, TEGRA_CEC_RX_REGISTER);
 176                 if (cec->rx_buf_cnt < CEC_MAX_MSG_SIZE)
 177                         cec->rx_buf[cec->rx_buf_cnt++] = v & 0xff;
 178                 if (v & TEGRA_CEC_RX_REGISTER_EOM) {
 179                         cec->rx_done = true;
 180                         return IRQ_WAKE_THREAD;
 181                 }
 182         }
 183 
 184         return IRQ_HANDLED;
 185 }
 186 
 187 static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)
 188 {
 189         struct tegra_cec *cec = adap->priv;
 190 
 191         cec->rx_buf_cnt = 0;
 192         cec->tx_buf_cnt = 0;
 193         cec->tx_buf_cur = 0;
 194 
 195         cec_write(cec, TEGRA_CEC_HW_CONTROL, 0);
 196         cec_write(cec, TEGRA_CEC_INT_MASK, 0);
 197         cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff);
 198         cec_write(cec, TEGRA_CEC_SW_CONTROL, 0);
 199 
 200         if (!enable)
 201                 return 0;
 202 
 203         cec_write(cec, TEGRA_CEC_INPUT_FILTER, (1U << 31) | 0x20);
 204 
 205         cec_write(cec, TEGRA_CEC_RX_TIMING_0,
 206                   (0x7a << TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT) |
 207                   (0x6d << TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT) |
 208                   (0x93 << TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT) |
 209                   (0x86 << TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT));
 210 
 211         cec_write(cec, TEGRA_CEC_RX_TIMING_1,
 212                   (0x35 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT) |
 213                   (0x21 << TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT) |
 214                   (0x56 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT) |
 215                   (0x40 << TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT));
 216 
 217         cec_write(cec, TEGRA_CEC_RX_TIMING_2,
 218                   (0x50 << TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT));
 219 
 220         cec_write(cec, TEGRA_CEC_TX_TIMING_0,
 221                   (0x74 << TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT) |
 222                   (0x8d << TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT) |
 223                   (0x08 << TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT) |
 224                   (0x71 << TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT));
 225 
 226         cec_write(cec, TEGRA_CEC_TX_TIMING_1,
 227                   (0x2f << TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT) |
 228                   (0x13 << TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT) |
 229                   (0x4b << TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT) |
 230                   (0x21 << TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT));
 231 
 232         cec_write(cec, TEGRA_CEC_TX_TIMING_2,
 233                   (0x07 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT) |
 234                   (0x05 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT) |
 235                   (0x03 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT));
 236 
 237         cec_write(cec, TEGRA_CEC_INT_MASK,
 238                   TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN |
 239                   TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD |
 240                   TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED |
 241                   TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
 242                   TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED |
 243                   TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
 244                   TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED);
 245 
 246         cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE);
 247         return 0;
 248 }
 249 
 250 static int tegra_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
 251 {
 252         struct tegra_cec *cec = adap->priv;
 253         u32 state = cec_read(cec, TEGRA_CEC_HW_CONTROL);
 254 
 255         if (logical_addr == CEC_LOG_ADDR_INVALID)
 256                 state &= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK;
 257         else
 258                 state |= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr));
 259 
 260         cec_write(cec, TEGRA_CEC_HW_CONTROL, state);
 261         return 0;
 262 }
 263 
 264 static int tegra_cec_adap_monitor_all_enable(struct cec_adapter *adap,
 265                                              bool enable)
 266 {
 267         struct tegra_cec *cec = adap->priv;
 268         u32 reg = cec_read(cec, TEGRA_CEC_HW_CONTROL);
 269 
 270         if (enable)
 271                 reg |= TEGRA_CEC_HWCTRL_RX_SNOOP;
 272         else
 273                 reg &= ~TEGRA_CEC_HWCTRL_RX_SNOOP;
 274         cec_write(cec, TEGRA_CEC_HW_CONTROL, reg);
 275         return 0;
 276 }
 277 
 278 static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
 279                                    u32 signal_free_time_ms, struct cec_msg *msg)
 280 {
 281         bool retry_xfer = signal_free_time_ms == CEC_SIGNAL_FREE_TIME_RETRY;
 282         struct tegra_cec *cec = adap->priv;
 283         unsigned int i;
 284         u32 mode = 0;
 285         u32 mask;
 286 
 287         if (cec_msg_is_broadcast(msg))
 288                 mode = TEGRA_CEC_TX_REG_BCAST;
 289 
 290         cec->tx_buf_cur = 0;
 291         cec->tx_buf_cnt = msg->len;
 292 
 293         for (i = 0; i < msg->len; i++) {
 294                 cec->tx_buf[i] = mode | msg->msg[i];
 295                 if (i == 0)
 296                         cec->tx_buf[i] |= TEGRA_CEC_TX_REG_START_BIT;
 297                 if (i == msg->len - 1)
 298                         cec->tx_buf[i] |= TEGRA_CEC_TX_REG_EOM;
 299                 if (i == 0 && retry_xfer)
 300                         cec->tx_buf[i] |= TEGRA_CEC_TX_REG_RETRY;
 301         }
 302 
 303         mask = cec_read(cec, TEGRA_CEC_INT_MASK);
 304         cec_write(cec, TEGRA_CEC_INT_MASK,
 305                   mask | TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);
 306 
 307         return 0;
 308 }
 309 
 310 static const struct cec_adap_ops tegra_cec_ops = {
 311         .adap_enable = tegra_cec_adap_enable,
 312         .adap_log_addr = tegra_cec_adap_log_addr,
 313         .adap_transmit = tegra_cec_adap_transmit,
 314         .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable,
 315 };
 316 
 317 static int tegra_cec_probe(struct platform_device *pdev)
 318 {
 319         struct device *hdmi_dev;
 320         struct tegra_cec *cec;
 321         struct resource *res;
 322         int ret = 0;
 323 
 324         hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
 325 
 326         if (IS_ERR(hdmi_dev))
 327                 return PTR_ERR(hdmi_dev);
 328 
 329         cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL);
 330 
 331         if (!cec)
 332                 return -ENOMEM;
 333 
 334         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 335 
 336         if (!res) {
 337                 dev_err(&pdev->dev,
 338                         "Unable to allocate resources for device\n");
 339                 return -EBUSY;
 340         }
 341 
 342         if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
 343                 pdev->name)) {
 344                 dev_err(&pdev->dev,
 345                         "Unable to request mem region for device\n");
 346                 return -EBUSY;
 347         }
 348 
 349         cec->tegra_cec_irq = platform_get_irq(pdev, 0);
 350 
 351         if (cec->tegra_cec_irq <= 0)
 352                 return -EBUSY;
 353 
 354         cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start,
 355                                              resource_size(res));
 356 
 357         if (!cec->cec_base) {
 358                 dev_err(&pdev->dev, "Unable to grab IOs for device\n");
 359                 return -EBUSY;
 360         }
 361 
 362         cec->clk = devm_clk_get(&pdev->dev, "cec");
 363 
 364         if (IS_ERR_OR_NULL(cec->clk)) {
 365                 dev_err(&pdev->dev, "Can't get clock for CEC\n");
 366                 return -ENOENT;
 367         }
 368 
 369         clk_prepare_enable(cec->clk);
 370 
 371         /* set context info. */
 372         cec->dev = &pdev->dev;
 373 
 374         platform_set_drvdata(pdev, cec);
 375 
 376         ret = devm_request_threaded_irq(&pdev->dev, cec->tegra_cec_irq,
 377                 tegra_cec_irq_handler, tegra_cec_irq_thread_handler,
 378                 0, "cec_irq", &pdev->dev);
 379 
 380         if (ret) {
 381                 dev_err(&pdev->dev,
 382                         "Unable to request interrupt for device\n");
 383                 goto err_clk;
 384         }
 385 
 386         cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME,
 387                         CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL |
 388                         CEC_CAP_CONNECTOR_INFO,
 389                         CEC_MAX_LOG_ADDRS);
 390         if (IS_ERR(cec->adap)) {
 391                 ret = -ENOMEM;
 392                 dev_err(&pdev->dev, "Couldn't create cec adapter\n");
 393                 goto err_clk;
 394         }
 395 
 396         cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
 397                                                        cec->adap);
 398         if (!cec->notifier) {
 399                 ret = -ENOMEM;
 400                 goto err_adapter;
 401         }
 402 
 403         ret = cec_register_adapter(cec->adap, &pdev->dev);
 404         if (ret) {
 405                 dev_err(&pdev->dev, "Couldn't register device\n");
 406                 goto err_notifier;
 407         }
 408 
 409         return 0;
 410 
 411 err_notifier:
 412         cec_notifier_cec_adap_unregister(cec->notifier);
 413 err_adapter:
 414         cec_delete_adapter(cec->adap);
 415 err_clk:
 416         clk_disable_unprepare(cec->clk);
 417         return ret;
 418 }
 419 
 420 static int tegra_cec_remove(struct platform_device *pdev)
 421 {
 422         struct tegra_cec *cec = platform_get_drvdata(pdev);
 423 
 424         clk_disable_unprepare(cec->clk);
 425 
 426         cec_notifier_cec_adap_unregister(cec->notifier);
 427         cec_unregister_adapter(cec->adap);
 428 
 429         return 0;
 430 }
 431 
 432 #ifdef CONFIG_PM
 433 static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state)
 434 {
 435         struct tegra_cec *cec = platform_get_drvdata(pdev);
 436 
 437         clk_disable_unprepare(cec->clk);
 438 
 439         dev_notice(&pdev->dev, "suspended\n");
 440         return 0;
 441 }
 442 
 443 static int tegra_cec_resume(struct platform_device *pdev)
 444 {
 445         struct tegra_cec *cec = platform_get_drvdata(pdev);
 446 
 447         dev_notice(&pdev->dev, "Resuming\n");
 448 
 449         clk_prepare_enable(cec->clk);
 450 
 451         return 0;
 452 }
 453 #endif
 454 
 455 static const struct of_device_id tegra_cec_of_match[] = {
 456         { .compatible = "nvidia,tegra114-cec", },
 457         { .compatible = "nvidia,tegra124-cec", },
 458         { .compatible = "nvidia,tegra210-cec", },
 459         {},
 460 };
 461 
 462 static struct platform_driver tegra_cec_driver = {
 463         .driver = {
 464                 .name = TEGRA_CEC_NAME,
 465                 .of_match_table = of_match_ptr(tegra_cec_of_match),
 466         },
 467         .probe = tegra_cec_probe,
 468         .remove = tegra_cec_remove,
 469 
 470 #ifdef CONFIG_PM
 471         .suspend = tegra_cec_suspend,
 472         .resume = tegra_cec_resume,
 473 #endif
 474 };
 475 
 476 module_platform_driver(tegra_cec_driver);
 477 
 478 MODULE_DESCRIPTION("Tegra HDMI CEC driver");
 479 MODULE_AUTHOR("NVIDIA CORPORATION");
 480 MODULE_AUTHOR("Cisco Systems, Inc. and/or its affiliates");
 481 MODULE_LICENSE("GPL v2");

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