linux/drivers/media/platform/meson/ao-cec-g12a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Driver for Amlogic Meson AO CEC G12A Controller
   4 *
   5 * Copyright (C) 2017 Amlogic, Inc. All rights reserved
   6 * Copyright (C) 2019 BayLibre, SAS
   7 * Author: Neil Armstrong <narmstrong@baylibre.com>
   8 */
   9
  10#include <linux/bitfield.h>
  11#include <linux/clk.h>
  12#include <linux/device.h>
  13#include <linux/io.h>
  14#include <linux/delay.h>
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <linux/of.h>
  18#include <linux/of_platform.h>
  19#include <linux/platform_device.h>
  20#include <linux/types.h>
  21#include <linux/interrupt.h>
  22#include <linux/reset.h>
  23#include <linux/slab.h>
  24#include <linux/regmap.h>
  25#include <media/cec.h>
  26#include <media/cec-notifier.h>
  27#include <linux/clk-provider.h>
  28
  29/* CEC Registers */
  30
  31#define CECB_CLK_CNTL_REG0              0x00
  32
  33#define CECB_CLK_CNTL_N1                GENMASK(11, 0)
  34#define CECB_CLK_CNTL_N2                GENMASK(23, 12)
  35#define CECB_CLK_CNTL_DUAL_EN           BIT(28)
  36#define CECB_CLK_CNTL_OUTPUT_EN         BIT(30)
  37#define CECB_CLK_CNTL_INPUT_EN          BIT(31)
  38
  39#define CECB_CLK_CNTL_REG1              0x04
  40
  41#define CECB_CLK_CNTL_M1                GENMASK(11, 0)
  42#define CECB_CLK_CNTL_M2                GENMASK(23, 12)
  43#define CECB_CLK_CNTL_BYPASS_EN         BIT(24)
  44
  45/*
  46 * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal
  47 *       change pulse width < filter_del * T(filter_tick) * 3.
  48 * [9:8] Filter_tick_sel: Select which periodical pulse for
  49 *       glitch-filtering CEC line signal.
  50 *  - 0=Use T(xtal)*3 = 125ns;
  51 *  - 1=Use once-per-1us pulse;
  52 *  - 2=Use once-per-10us pulse;
  53 *  - 3=Use once-per-100us pulse.
  54 * [3]   Sysclk_en. 0=Disable system clock; 1=Enable system clock.
  55 * [2:1] cntl_clk
  56 *  - 0 = Disable clk (Power-off mode)
  57 *  - 1 = Enable gated clock (Normal mode)
  58 *  - 2 = Enable free-run clk (Debug mode)
  59 * [0] SW_RESET 1=Apply reset; 0=No reset.
  60 */
  61#define CECB_GEN_CNTL_REG               0x08
  62
  63#define CECB_GEN_CNTL_RESET             BIT(0)
  64#define CECB_GEN_CNTL_CLK_DISABLE       0
  65#define CECB_GEN_CNTL_CLK_ENABLE        1
  66#define CECB_GEN_CNTL_CLK_ENABLE_DBG    2
  67#define CECB_GEN_CNTL_CLK_CTRL_MASK     GENMASK(2, 1)
  68#define CECB_GEN_CNTL_SYS_CLK_EN        BIT(3)
  69#define CECB_GEN_CNTL_FILTER_TICK_125NS 0
  70#define CECB_GEN_CNTL_FILTER_TICK_1US   1
  71#define CECB_GEN_CNTL_FILTER_TICK_10US  2
  72#define CECB_GEN_CNTL_FILTER_TICK_100US 3
  73#define CECB_GEN_CNTL_FILTER_TICK_SEL   GENMASK(9, 8)
  74#define CECB_GEN_CNTL_FILTER_DEL        GENMASK(14, 12)
  75
  76/*
  77 * [7:0] cec_reg_addr
  78 * [15:8] cec_reg_wrdata
  79 * [16] cec_reg_wr
  80 *  - 0 = Read
  81 *  - 1 = Write
  82 * [31:24] cec_reg_rddata
  83 */
  84#define CECB_RW_REG                     0x0c
  85
  86#define CECB_RW_ADDR                    GENMASK(7, 0)
  87#define CECB_RW_WR_DATA                 GENMASK(15, 8)
  88#define CECB_RW_WRITE_EN                BIT(16)
  89#define CECB_RW_BUS_BUSY                BIT(23)
  90#define CECB_RW_RD_DATA                 GENMASK(31, 24)
  91
  92/*
  93 * [0] DONE Interrupt
  94 * [1] End Of Message Interrupt
  95 * [2] Not Acknowlegde Interrupt
  96 * [3] Arbitration Loss Interrupt
  97 * [4] Initiator Error Interrupt
  98 * [5] Follower Error Interrupt
  99 * [6] Wake-Up Interrupt
 100 */
 101#define CECB_INTR_MASKN_REG             0x10
 102#define CECB_INTR_CLR_REG               0x14
 103#define CECB_INTR_STAT_REG              0x18
 104
 105#define CECB_INTR_DONE                  BIT(0)
 106#define CECB_INTR_EOM                   BIT(1)
 107#define CECB_INTR_NACK                  BIT(2)
 108#define CECB_INTR_ARB_LOSS              BIT(3)
 109#define CECB_INTR_INITIATOR_ERR         BIT(4)
 110#define CECB_INTR_FOLLOWER_ERR          BIT(5)
 111#define CECB_INTR_WAKE_UP               BIT(6)
 112
 113/* CEC Commands */
 114
 115#define CECB_CTRL               0x00
 116
 117#define CECB_CTRL_SEND          BIT(0)
 118#define CECB_CTRL_TYPE          GENMASK(2, 1)
 119#define CECB_CTRL_TYPE_RETRY    0
 120#define CECB_CTRL_TYPE_NEW      1
 121#define CECB_CTRL_TYPE_NEXT     2
 122
 123#define CECB_CTRL2              0x01
 124#define CECB_INTR_MASK          0x02
 125#define CECB_LADD_LOW           0x05
 126#define CECB_LADD_HIGH          0x06
 127#define CECB_TX_CNT             0x07
 128#define CECB_RX_CNT             0x08
 129#define CECB_STAT0              0x09
 130#define CECB_TX_DATA00          0x10
 131#define CECB_TX_DATA01          0x11
 132#define CECB_TX_DATA02          0x12
 133#define CECB_TX_DATA03          0x13
 134#define CECB_TX_DATA04          0x14
 135#define CECB_TX_DATA05          0x15
 136#define CECB_TX_DATA06          0x16
 137#define CECB_TX_DATA07          0x17
 138#define CECB_TX_DATA08          0x18
 139#define CECB_TX_DATA09          0x19
 140#define CECB_TX_DATA10          0x1A
 141#define CECB_TX_DATA11          0x1B
 142#define CECB_TX_DATA12          0x1C
 143#define CECB_TX_DATA13          0x1D
 144#define CECB_TX_DATA14          0x1E
 145#define CECB_TX_DATA15          0x1F
 146#define CECB_RX_DATA00          0x20
 147#define CECB_RX_DATA01          0x21
 148#define CECB_RX_DATA02          0x22
 149#define CECB_RX_DATA03          0x23
 150#define CECB_RX_DATA04          0x24
 151#define CECB_RX_DATA05          0x25
 152#define CECB_RX_DATA06          0x26
 153#define CECB_RX_DATA07          0x27
 154#define CECB_RX_DATA08          0x28
 155#define CECB_RX_DATA09          0x29
 156#define CECB_RX_DATA10          0x2A
 157#define CECB_RX_DATA11          0x2B
 158#define CECB_RX_DATA12          0x2C
 159#define CECB_RX_DATA13          0x2D
 160#define CECB_RX_DATA14          0x2E
 161#define CECB_RX_DATA15          0x2F
 162#define CECB_LOCK_BUF           0x30
 163
 164#define CECB_LOCK_BUF_EN        BIT(0)
 165
 166#define CECB_WAKEUPCTRL         0x31
 167
 168struct meson_ao_cec_g12a_device {
 169        struct platform_device          *pdev;
 170        struct regmap                   *regmap;
 171        struct regmap                   *regmap_cec;
 172        spinlock_t                      cec_reg_lock;
 173        struct cec_notifier             *notify;
 174        struct cec_adapter              *adap;
 175        struct cec_msg                  rx_msg;
 176        struct clk                      *oscin;
 177        struct clk                      *core;
 178};
 179
 180static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
 181        .reg_bits = 8,
 182        .val_bits = 32,
 183        .reg_stride = 4,
 184        .max_register = CECB_INTR_STAT_REG,
 185};
 186
 187/*
 188 * The AO-CECB embeds a dual/divider to generate a more precise
 189 * 32,768KHz clock for CEC core clock.
 190 *                      ______   ______
 191 *                     |      | |      |
 192 *         ______      | Div1 |-| Cnt1 |       ______
 193 *        |      |    /|______| |______|\     |      |
 194 * Xtal-->| Gate |---|  ______   ______  X-X--| Gate |-->
 195 *        |______| |  \|      | |      |/  |  |______|
 196 *                 |   | Div2 |-| Cnt2 |   |
 197 *                 |   |______| |______|   |
 198 *                 |_______________________|
 199 *
 200 * The dividing can be switched to single or dual, with a counter
 201 * for each divider to set when the switching is done.
 202 * The entire dividing mechanism can be also bypassed.
 203 */
 204
 205struct meson_ao_cec_g12a_dualdiv_clk {
 206        struct clk_hw hw;
 207        struct regmap *regmap;
 208};
 209
 210#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw)                        \
 211        container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw)     \
 212
 213static unsigned long
 214meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw,
 215                                          unsigned long parent_rate)
 216{
 217        struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
 218                hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
 219        unsigned long n1;
 220        u32 reg0, reg1;
 221
 222        regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg0);
 223        regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg1);
 224
 225        if (reg1 & CECB_CLK_CNTL_BYPASS_EN)
 226                return parent_rate;
 227
 228        if (reg0 & CECB_CLK_CNTL_DUAL_EN) {
 229                unsigned long n2, m1, m2, f1, f2, p1, p2;
 230
 231                n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
 232                n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1;
 233
 234                m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
 235                m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
 236
 237                f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
 238                f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
 239
 240                p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
 241                p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
 242
 243                return DIV_ROUND_UP(100000000, p1 + p2);
 244        }
 245
 246        n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
 247
 248        return DIV_ROUND_CLOSEST(parent_rate, n1);
 249}
 250
 251static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw)
 252{
 253        struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
 254                hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
 255
 256
 257        /* Disable Input & Output */
 258        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 259                           CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
 260                           0);
 261
 262        /* Set N1 & N2 */
 263        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 264                           CECB_CLK_CNTL_N1,
 265                           FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1));
 266
 267        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 268                           CECB_CLK_CNTL_N2,
 269                           FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1));
 270
 271        /* Set M1 & M2 */
 272        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
 273                           CECB_CLK_CNTL_M1,
 274                           FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1));
 275
 276        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
 277                           CECB_CLK_CNTL_M2,
 278                           FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1));
 279
 280        /* Enable Dual divisor */
 281        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 282                           CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN);
 283
 284        /* Disable divisor bypass */
 285        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
 286                           CECB_CLK_CNTL_BYPASS_EN, 0);
 287
 288        /* Enable Input & Output */
 289        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 290                           CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
 291                           CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN);
 292
 293        return 0;
 294}
 295
 296static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw)
 297{
 298        struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
 299                hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
 300
 301        regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
 302                           CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
 303                           0);
 304}
 305
 306static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw)
 307{
 308        struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
 309                hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
 310        int val;
 311
 312        regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val);
 313
 314        return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN));
 315}
 316
 317static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = {
 318        .recalc_rate    = meson_ao_cec_g12a_dualdiv_clk_recalc_rate,
 319        .is_enabled     = meson_ao_cec_g12a_dualdiv_clk_is_enabled,
 320        .enable         = meson_ao_cec_g12a_dualdiv_clk_enable,
 321        .disable        = meson_ao_cec_g12a_dualdiv_clk_disable,
 322};
 323
 324static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec)
 325{
 326        struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk;
 327        struct device *dev = &ao_cec->pdev->dev;
 328        struct clk_init_data init;
 329        const char *parent_name;
 330        struct clk *clk;
 331        char *name;
 332
 333        dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL);
 334        if (!dualdiv_clk)
 335                return -ENOMEM;
 336
 337        name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev));
 338        if (!name)
 339                return -ENOMEM;
 340
 341        parent_name = __clk_get_name(ao_cec->oscin);
 342
 343        init.name = name;
 344        init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops;
 345        init.flags = 0;
 346        init.parent_names = &parent_name;
 347        init.num_parents = 1;
 348        dualdiv_clk->regmap = ao_cec->regmap;
 349        dualdiv_clk->hw.init = &init;
 350
 351        clk = devm_clk_register(dev, &dualdiv_clk->hw);
 352        kfree(name);
 353        if (IS_ERR(clk)) {
 354                dev_err(dev, "failed to register clock\n");
 355                return PTR_ERR(clk);
 356        }
 357
 358        ao_cec->core = clk;
 359
 360        return 0;
 361}
 362
 363static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
 364                                  unsigned int *data)
 365{
 366        struct meson_ao_cec_g12a_device *ao_cec = context;
 367        u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
 368        int ret = 0;
 369
 370        ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
 371        if (ret)
 372                return ret;
 373
 374        ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
 375                                       !(reg & CECB_RW_BUS_BUSY),
 376                                       5, 1000);
 377        if (ret)
 378                return ret;
 379
 380        ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg);
 381
 382        *data = FIELD_GET(CECB_RW_RD_DATA, reg);
 383
 384        return ret;
 385}
 386
 387static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
 388                                   unsigned int data)
 389{
 390        struct meson_ao_cec_g12a_device *ao_cec = context;
 391        u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
 392                  FIELD_PREP(CECB_RW_WR_DATA, data) |
 393                  CECB_RW_WRITE_EN;
 394
 395        return regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
 396}
 397
 398static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
 399        .reg_bits = 8,
 400        .val_bits = 8,
 401        .reg_read = meson_ao_cec_g12a_read,
 402        .reg_write = meson_ao_cec_g12a_write,
 403        .max_register = 0xffff,
 404};
 405
 406static inline void
 407meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec,
 408                            bool enable)
 409{
 410        u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK |
 411                  CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR |
 412                  CECB_INTR_FOLLOWER_ERR;
 413
 414        regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG,
 415                     enable ? cfg : 0);
 416}
 417
 418static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec)
 419{
 420        int i, ret = 0;
 421        u32 val;
 422
 423        ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val);
 424
 425        ao_cec->rx_msg.len = val;
 426        if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE)
 427                ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE;
 428
 429        for (i = 0; i < ao_cec->rx_msg.len; i++) {
 430                ret |= regmap_read(ao_cec->regmap_cec,
 431                                   CECB_RX_DATA00 + i, &val);
 432
 433                ao_cec->rx_msg.msg[i] = val & 0xff;
 434        }
 435
 436        ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
 437        if (ret)
 438                return;
 439
 440        cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
 441}
 442
 443static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data)
 444{
 445        struct meson_ao_cec_g12a_device *ao_cec = data;
 446        u32 stat;
 447
 448        regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
 449        if (stat)
 450                return IRQ_WAKE_THREAD;
 451
 452        return IRQ_NONE;
 453}
 454
 455static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data)
 456{
 457        struct meson_ao_cec_g12a_device *ao_cec = data;
 458        u32 stat;
 459
 460        regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
 461        regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat);
 462
 463        if (stat & CECB_INTR_DONE)
 464                cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK);
 465
 466        if (stat & CECB_INTR_EOM)
 467                meson_ao_cec_g12a_irq_rx(ao_cec);
 468
 469        if (stat & CECB_INTR_NACK)
 470                cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK);
 471
 472        if (stat & CECB_INTR_ARB_LOSS) {
 473                regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0);
 474                regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
 475                                   CECB_CTRL_SEND | CECB_CTRL_TYPE, 0);
 476                cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST);
 477        }
 478
 479        /* Initiator reports an error on the CEC bus */
 480        if (stat & CECB_INTR_INITIATOR_ERR)
 481                cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR);
 482
 483        /* Follower reports a receive error, just reset RX buffer */
 484        if (stat & CECB_INTR_FOLLOWER_ERR)
 485                regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
 486
 487        return IRQ_HANDLED;
 488}
 489
 490static int
 491meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
 492{
 493        struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
 494        int ret = 0;
 495
 496        if (logical_addr == CEC_LOG_ADDR_INVALID) {
 497                /* Assume this will allways succeed */
 498                regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0);
 499                regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0);
 500
 501                return 0;
 502        } else if (logical_addr < 8) {
 503                ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW,
 504                                         BIT(logical_addr),
 505                                         BIT(logical_addr));
 506        } else {
 507                ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
 508                                         BIT(logical_addr - 8),
 509                                         BIT(logical_addr - 8));
 510        }
 511
 512        /* Always set Broadcast/Unregistered 15 address */
 513        ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
 514                                  BIT(CEC_LOG_ADDR_UNREGISTERED - 8),
 515                                  BIT(CEC_LOG_ADDR_UNREGISTERED - 8));
 516
 517        return ret ? -EIO : 0;
 518}
 519
 520static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts,
 521                                 u32 signal_free_time, struct cec_msg *msg)
 522{
 523        struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
 524        unsigned int type;
 525        int ret = 0;
 526        u32 val;
 527        int i;
 528
 529        /* Check if RX is in progress */
 530        ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val);
 531        if (ret)
 532                return ret;
 533        if (val & CECB_LOCK_BUF_EN)
 534                return -EBUSY;
 535
 536        /* Check if TX Busy */
 537        ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val);
 538        if (ret)
 539                return ret;
 540        if (val & CECB_CTRL_SEND)
 541                return -EBUSY;
 542
 543        switch (signal_free_time) {
 544        case CEC_SIGNAL_FREE_TIME_RETRY:
 545                type = CECB_CTRL_TYPE_RETRY;
 546                break;
 547        case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
 548                type = CECB_CTRL_TYPE_NEXT;
 549                break;
 550        case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
 551        default:
 552                type = CECB_CTRL_TYPE_NEW;
 553                break;
 554        }
 555
 556        for (i = 0; i < msg->len; i++)
 557                ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i,
 558                                    msg->msg[i]);
 559
 560        ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len);
 561        if (ret)
 562                return -EIO;
 563
 564        ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
 565                                 CECB_CTRL_SEND |
 566                                 CECB_CTRL_TYPE,
 567                                 CECB_CTRL_SEND |
 568                                 FIELD_PREP(CECB_CTRL_TYPE, type));
 569
 570        return ret;
 571}
 572
 573static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
 574{
 575        struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
 576
 577        meson_ao_cec_g12a_irq_setup(ao_cec, false);
 578
 579        regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
 580                           CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET);
 581
 582        if (!enable)
 583                return 0;
 584
 585        /* Setup Filter */
 586        regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
 587                           CECB_GEN_CNTL_FILTER_TICK_SEL |
 588                           CECB_GEN_CNTL_FILTER_DEL,
 589                           FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL,
 590                                      CECB_GEN_CNTL_FILTER_TICK_1US) |
 591                           FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7));
 592
 593        /* Enable System Clock */
 594        regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
 595                           CECB_GEN_CNTL_SYS_CLK_EN,
 596                           CECB_GEN_CNTL_SYS_CLK_EN);
 597
 598        /* Enable gated clock (Normal mode). */
 599        regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
 600                           CECB_GEN_CNTL_CLK_CTRL_MASK,
 601                            FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK,
 602                                       CECB_GEN_CNTL_CLK_ENABLE));
 603
 604        /* Release Reset */
 605        regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
 606                           CECB_GEN_CNTL_RESET, 0);
 607
 608        meson_ao_cec_g12a_irq_setup(ao_cec, true);
 609
 610        return 0;
 611}
 612
 613static const struct cec_adap_ops meson_ao_cec_g12a_ops = {
 614        .adap_enable = meson_ao_cec_g12a_adap_enable,
 615        .adap_log_addr = meson_ao_cec_g12a_set_log_addr,
 616        .adap_transmit = meson_ao_cec_g12a_transmit,
 617};
 618
 619static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
 620{
 621        struct meson_ao_cec_g12a_device *ao_cec;
 622        struct device *hdmi_dev;
 623        struct resource *res;
 624        void __iomem *base;
 625        int ret, irq;
 626
 627        hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
 628        if (IS_ERR(hdmi_dev))
 629                return PTR_ERR(hdmi_dev);
 630
 631        ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
 632        if (!ao_cec)
 633                return -ENOMEM;
 634
 635        spin_lock_init(&ao_cec->cec_reg_lock);
 636        ao_cec->pdev = pdev;
 637
 638        ao_cec->notify = cec_notifier_get(hdmi_dev);
 639        if (!ao_cec->notify)
 640                return -ENOMEM;
 641
 642        ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec,
 643                                            "meson_g12a_ao_cec",
 644                                            CEC_CAP_DEFAULTS,
 645                                            CEC_MAX_LOG_ADDRS);
 646        if (IS_ERR(ao_cec->adap)) {
 647                ret = PTR_ERR(ao_cec->adap);
 648                goto out_probe_notify;
 649        }
 650
 651        ao_cec->adap->owner = THIS_MODULE;
 652
 653        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 654        base = devm_ioremap_resource(&pdev->dev, res);
 655        if (IS_ERR(base)) {
 656                ret = PTR_ERR(base);
 657                goto out_probe_adapter;
 658        }
 659
 660        ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
 661                                               &meson_ao_cec_g12a_regmap_conf);
 662        if (IS_ERR(ao_cec->regmap)) {
 663                ret = PTR_ERR(ao_cec->regmap);
 664                goto out_probe_adapter;
 665        }
 666
 667        ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec,
 668                                           &meson_ao_cec_g12a_cec_regmap_conf);
 669        if (IS_ERR(ao_cec->regmap_cec)) {
 670                ret = PTR_ERR(ao_cec->regmap_cec);
 671                goto out_probe_adapter;
 672        }
 673
 674        irq = platform_get_irq(pdev, 0);
 675        ret = devm_request_threaded_irq(&pdev->dev, irq,
 676                                        meson_ao_cec_g12a_irq,
 677                                        meson_ao_cec_g12a_irq_thread,
 678                                        0, NULL, ao_cec);
 679        if (ret) {
 680                dev_err(&pdev->dev, "irq request failed\n");
 681                goto out_probe_adapter;
 682        }
 683
 684        ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
 685        if (IS_ERR(ao_cec->oscin)) {
 686                dev_err(&pdev->dev, "oscin clock request failed\n");
 687                ret = PTR_ERR(ao_cec->oscin);
 688                goto out_probe_adapter;
 689        }
 690
 691        ret = meson_ao_cec_g12a_setup_clk(ao_cec);
 692        if (ret)
 693                goto out_probe_adapter;
 694
 695        ret = clk_prepare_enable(ao_cec->core);
 696        if (ret) {
 697                dev_err(&pdev->dev, "core clock enable failed\n");
 698                goto out_probe_adapter;
 699        }
 700
 701        device_reset_optional(&pdev->dev);
 702
 703        platform_set_drvdata(pdev, ao_cec);
 704
 705        ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
 706        if (ret < 0) {
 707                cec_notifier_put(ao_cec->notify);
 708                goto out_probe_core_clk;
 709        }
 710
 711        /* Setup Hardware */
 712        regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
 713
 714        cec_register_cec_notifier(ao_cec->adap, ao_cec->notify);
 715
 716        return 0;
 717
 718out_probe_core_clk:
 719        clk_disable_unprepare(ao_cec->core);
 720
 721out_probe_adapter:
 722        cec_delete_adapter(ao_cec->adap);
 723
 724out_probe_notify:
 725        cec_notifier_put(ao_cec->notify);
 726
 727        dev_err(&pdev->dev, "CEC controller registration failed\n");
 728
 729        return ret;
 730}
 731
 732static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
 733{
 734        struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
 735
 736        clk_disable_unprepare(ao_cec->core);
 737
 738        cec_unregister_adapter(ao_cec->adap);
 739
 740        cec_notifier_put(ao_cec->notify);
 741
 742        return 0;
 743}
 744
 745static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
 746        { .compatible = "amlogic,meson-g12a-ao-cec", },
 747        { /* sentinel */ }
 748};
 749MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
 750
 751static struct platform_driver meson_ao_cec_g12a_driver = {
 752        .probe   = meson_ao_cec_g12a_probe,
 753        .remove  = meson_ao_cec_g12a_remove,
 754        .driver  = {
 755                .name = "meson-ao-cec-g12a",
 756                .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
 757        },
 758};
 759
 760module_platform_driver(meson_ao_cec_g12a_driver);
 761
 762MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
 763MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
 764MODULE_LICENSE("GPL");
 765