Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc6 779 lines 21 kB view raw
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 unsigned long flags; 369 int ret = 0; 370 371 spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); 372 373 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); 374 if (ret) 375 goto read_out; 376 377 ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, 378 !(reg & CECB_RW_BUS_BUSY), 379 5, 1000); 380 if (ret) 381 goto read_out; 382 383 ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg); 384 385 *data = FIELD_GET(CECB_RW_RD_DATA, reg); 386 387read_out: 388 spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); 389 390 return ret; 391} 392 393static int meson_ao_cec_g12a_write(void *context, unsigned int addr, 394 unsigned int data) 395{ 396 struct meson_ao_cec_g12a_device *ao_cec = context; 397 unsigned long flags; 398 u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | 399 FIELD_PREP(CECB_RW_WR_DATA, data) | 400 CECB_RW_WRITE_EN; 401 int ret = 0; 402 403 spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); 404 405 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); 406 407 spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); 408 409 return ret; 410} 411 412static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { 413 .reg_bits = 8, 414 .val_bits = 8, 415 .reg_read = meson_ao_cec_g12a_read, 416 .reg_write = meson_ao_cec_g12a_write, 417 .max_register = 0xffff, 418 .fast_io = true, 419}; 420 421static inline void 422meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, 423 bool enable) 424{ 425 u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | 426 CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | 427 CECB_INTR_FOLLOWER_ERR; 428 429 regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, 430 enable ? cfg : 0); 431} 432 433static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) 434{ 435 int i, ret = 0; 436 u32 val; 437 438 ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); 439 440 ao_cec->rx_msg.len = val; 441 if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) 442 ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; 443 444 for (i = 0; i < ao_cec->rx_msg.len; i++) { 445 ret |= regmap_read(ao_cec->regmap_cec, 446 CECB_RX_DATA00 + i, &val); 447 448 ao_cec->rx_msg.msg[i] = val & 0xff; 449 } 450 451 ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); 452 if (ret) 453 return; 454 455 cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); 456} 457 458static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) 459{ 460 struct meson_ao_cec_g12a_device *ao_cec = data; 461 u32 stat; 462 463 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); 464 if (stat) 465 return IRQ_WAKE_THREAD; 466 467 return IRQ_NONE; 468} 469 470static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) 471{ 472 struct meson_ao_cec_g12a_device *ao_cec = data; 473 u32 stat; 474 475 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); 476 regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); 477 478 if (stat & CECB_INTR_DONE) 479 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); 480 481 if (stat & CECB_INTR_EOM) 482 meson_ao_cec_g12a_irq_rx(ao_cec); 483 484 if (stat & CECB_INTR_NACK) 485 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); 486 487 if (stat & CECB_INTR_ARB_LOSS) { 488 regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); 489 regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, 490 CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); 491 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); 492 } 493 494 /* Initiator reports an error on the CEC bus */ 495 if (stat & CECB_INTR_INITIATOR_ERR) 496 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); 497 498 /* Follower reports a receive error, just reset RX buffer */ 499 if (stat & CECB_INTR_FOLLOWER_ERR) 500 regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); 501 502 return IRQ_HANDLED; 503} 504 505static int 506meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) 507{ 508 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; 509 int ret = 0; 510 511 if (logical_addr == CEC_LOG_ADDR_INVALID) { 512 /* Assume this will allways succeed */ 513 regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); 514 regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); 515 516 return 0; 517 } else if (logical_addr < 8) { 518 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, 519 BIT(logical_addr), 520 BIT(logical_addr)); 521 } else { 522 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, 523 BIT(logical_addr - 8), 524 BIT(logical_addr - 8)); 525 } 526 527 /* Always set Broadcast/Unregistered 15 address */ 528 ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, 529 BIT(CEC_LOG_ADDR_UNREGISTERED - 8), 530 BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); 531 532 return ret ? -EIO : 0; 533} 534 535static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, 536 u32 signal_free_time, struct cec_msg *msg) 537{ 538 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; 539 unsigned int type; 540 int ret = 0; 541 u32 val; 542 int i; 543 544 /* Check if RX is in progress */ 545 ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); 546 if (ret) 547 return ret; 548 if (val & CECB_LOCK_BUF_EN) 549 return -EBUSY; 550 551 /* Check if TX Busy */ 552 ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); 553 if (ret) 554 return ret; 555 if (val & CECB_CTRL_SEND) 556 return -EBUSY; 557 558 switch (signal_free_time) { 559 case CEC_SIGNAL_FREE_TIME_RETRY: 560 type = CECB_CTRL_TYPE_RETRY; 561 break; 562 case CEC_SIGNAL_FREE_TIME_NEXT_XFER: 563 type = CECB_CTRL_TYPE_NEXT; 564 break; 565 case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: 566 default: 567 type = CECB_CTRL_TYPE_NEW; 568 break; 569 } 570 571 for (i = 0; i < msg->len; i++) 572 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, 573 msg->msg[i]); 574 575 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); 576 if (ret) 577 return -EIO; 578 579 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, 580 CECB_CTRL_SEND | 581 CECB_CTRL_TYPE, 582 CECB_CTRL_SEND | 583 FIELD_PREP(CECB_CTRL_TYPE, type)); 584 585 return ret; 586} 587 588static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) 589{ 590 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; 591 592 meson_ao_cec_g12a_irq_setup(ao_cec, false); 593 594 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, 595 CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); 596 597 if (!enable) 598 return 0; 599 600 /* Setup Filter */ 601 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, 602 CECB_GEN_CNTL_FILTER_TICK_SEL | 603 CECB_GEN_CNTL_FILTER_DEL, 604 FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, 605 CECB_GEN_CNTL_FILTER_TICK_1US) | 606 FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); 607 608 /* Enable System Clock */ 609 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, 610 CECB_GEN_CNTL_SYS_CLK_EN, 611 CECB_GEN_CNTL_SYS_CLK_EN); 612 613 /* Enable gated clock (Normal mode). */ 614 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, 615 CECB_GEN_CNTL_CLK_CTRL_MASK, 616 FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, 617 CECB_GEN_CNTL_CLK_ENABLE)); 618 619 /* Release Reset */ 620 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, 621 CECB_GEN_CNTL_RESET, 0); 622 623 meson_ao_cec_g12a_irq_setup(ao_cec, true); 624 625 return 0; 626} 627 628static const struct cec_adap_ops meson_ao_cec_g12a_ops = { 629 .adap_enable = meson_ao_cec_g12a_adap_enable, 630 .adap_log_addr = meson_ao_cec_g12a_set_log_addr, 631 .adap_transmit = meson_ao_cec_g12a_transmit, 632}; 633 634static int meson_ao_cec_g12a_probe(struct platform_device *pdev) 635{ 636 struct meson_ao_cec_g12a_device *ao_cec; 637 struct device *hdmi_dev; 638 struct resource *res; 639 void __iomem *base; 640 int ret, irq; 641 642 hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); 643 if (IS_ERR(hdmi_dev)) 644 return PTR_ERR(hdmi_dev); 645 646 ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); 647 if (!ao_cec) 648 return -ENOMEM; 649 650 spin_lock_init(&ao_cec->cec_reg_lock); 651 ao_cec->pdev = pdev; 652 653 ao_cec->notify = cec_notifier_get(hdmi_dev); 654 if (!ao_cec->notify) 655 return -ENOMEM; 656 657 ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, 658 "meson_g12a_ao_cec", 659 CEC_CAP_DEFAULTS, 660 CEC_MAX_LOG_ADDRS); 661 if (IS_ERR(ao_cec->adap)) { 662 ret = PTR_ERR(ao_cec->adap); 663 goto out_probe_notify; 664 } 665 666 ao_cec->adap->owner = THIS_MODULE; 667 668 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 669 base = devm_ioremap_resource(&pdev->dev, res); 670 if (IS_ERR(base)) { 671 ret = PTR_ERR(base); 672 goto out_probe_adapter; 673 } 674 675 ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, 676 &meson_ao_cec_g12a_regmap_conf); 677 if (IS_ERR(ao_cec->regmap)) { 678 ret = PTR_ERR(ao_cec->regmap); 679 goto out_probe_adapter; 680 } 681 682 ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, 683 &meson_ao_cec_g12a_cec_regmap_conf); 684 if (IS_ERR(ao_cec->regmap_cec)) { 685 ret = PTR_ERR(ao_cec->regmap_cec); 686 goto out_probe_adapter; 687 } 688 689 irq = platform_get_irq(pdev, 0); 690 ret = devm_request_threaded_irq(&pdev->dev, irq, 691 meson_ao_cec_g12a_irq, 692 meson_ao_cec_g12a_irq_thread, 693 0, NULL, ao_cec); 694 if (ret) { 695 dev_err(&pdev->dev, "irq request failed\n"); 696 goto out_probe_adapter; 697 } 698 699 ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); 700 if (IS_ERR(ao_cec->oscin)) { 701 dev_err(&pdev->dev, "oscin clock request failed\n"); 702 ret = PTR_ERR(ao_cec->oscin); 703 goto out_probe_adapter; 704 } 705 706 ret = meson_ao_cec_g12a_setup_clk(ao_cec); 707 if (ret) 708 goto out_probe_adapter; 709 710 ret = clk_prepare_enable(ao_cec->core); 711 if (ret) { 712 dev_err(&pdev->dev, "core clock enable failed\n"); 713 goto out_probe_adapter; 714 } 715 716 device_reset_optional(&pdev->dev); 717 718 platform_set_drvdata(pdev, ao_cec); 719 720 ret = cec_register_adapter(ao_cec->adap, &pdev->dev); 721 if (ret < 0) { 722 cec_notifier_put(ao_cec->notify); 723 goto out_probe_core_clk; 724 } 725 726 /* Setup Hardware */ 727 regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); 728 729 cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); 730 731 return 0; 732 733out_probe_core_clk: 734 clk_disable_unprepare(ao_cec->core); 735 736out_probe_adapter: 737 cec_delete_adapter(ao_cec->adap); 738 739out_probe_notify: 740 cec_notifier_put(ao_cec->notify); 741 742 dev_err(&pdev->dev, "CEC controller registration failed\n"); 743 744 return ret; 745} 746 747static int meson_ao_cec_g12a_remove(struct platform_device *pdev) 748{ 749 struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); 750 751 clk_disable_unprepare(ao_cec->core); 752 753 cec_unregister_adapter(ao_cec->adap); 754 755 cec_notifier_put(ao_cec->notify); 756 757 return 0; 758} 759 760static const struct of_device_id meson_ao_cec_g12a_of_match[] = { 761 { .compatible = "amlogic,meson-g12a-ao-cec", }, 762 { /* sentinel */ } 763}; 764MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); 765 766static struct platform_driver meson_ao_cec_g12a_driver = { 767 .probe = meson_ao_cec_g12a_probe, 768 .remove = meson_ao_cec_g12a_remove, 769 .driver = { 770 .name = "meson-ao-cec-g12a", 771 .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), 772 }, 773}; 774 775module_platform_driver(meson_ao_cec_g12a_driver); 776 777MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); 778MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 779MODULE_LICENSE("GPL");