Lines Matching +full:ao +full:- +full:cec

1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Amlogic Meson AO CEC G12A Controller
25 #include <media/cec.h>
26 #include <media/cec-notifier.h>
27 #include <linux/clk-provider.h>
29 /* CEC Registers */
46 * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal
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.
56 * - 0 = Disable clk (Power-off mode)
57 * - 1 = Enable gated clock (Normal mode)
58 * - 2 = Enable free-run clk (Debug mode)
80 * - 0 = Read
81 * - 1 = Write
99 * [6] Wake-Up Interrupt
113 /* CEC Commands */
197 * The AO-CECB embeds a dual/divider to generate a more precise
198 * 32,768KHz clock for CEC core clock.
201 * ______ | Div1 |-| Cnt1 | ______
203 * Xtal-->| Gate |---| ______ ______ X-X--| Gate |-->
205 * | | Div2 |-| Cnt2 | |
231 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg0); in meson_ao_cec_g12a_dualdiv_clk_recalc_rate()
232 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg1); in meson_ao_cec_g12a_dualdiv_clk_recalc_rate()
267 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_enable()
272 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_enable()
274 FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); in meson_ao_cec_g12a_dualdiv_clk_enable()
276 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_enable()
278 FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); in meson_ao_cec_g12a_dualdiv_clk_enable()
281 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, in meson_ao_cec_g12a_dualdiv_clk_enable()
283 FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); in meson_ao_cec_g12a_dualdiv_clk_enable()
285 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, in meson_ao_cec_g12a_dualdiv_clk_enable()
287 FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); in meson_ao_cec_g12a_dualdiv_clk_enable()
290 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_enable()
294 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, in meson_ao_cec_g12a_dualdiv_clk_enable()
298 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_enable()
310 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, in meson_ao_cec_g12a_dualdiv_clk_disable()
321 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); in meson_ao_cec_g12a_dualdiv_clk_is_enabled()
336 struct device *dev = &ao_cec->pdev->dev; in meson_ao_cec_g12a_setup_clk()
344 return -ENOMEM; in meson_ao_cec_g12a_setup_clk()
348 return -ENOMEM; in meson_ao_cec_g12a_setup_clk()
350 parent_name = __clk_get_name(ao_cec->oscin); in meson_ao_cec_g12a_setup_clk()
357 dualdiv_clk->regmap = ao_cec->regmap; in meson_ao_cec_g12a_setup_clk()
358 dualdiv_clk->hw.init = &init; in meson_ao_cec_g12a_setup_clk()
360 clk = devm_clk_register(dev, &dualdiv_clk->hw); in meson_ao_cec_g12a_setup_clk()
367 ao_cec->core = clk; in meson_ao_cec_g12a_setup_clk()
379 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); in meson_ao_cec_g12a_read()
383 ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, in meson_ao_cec_g12a_read()
389 ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg); in meson_ao_cec_g12a_read()
404 return regmap_write(ao_cec->regmap, CECB_RW_REG, reg); in meson_ao_cec_g12a_write()
423 regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, in meson_ao_cec_g12a_irq_setup()
432 ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); in meson_ao_cec_g12a_irq_rx()
434 ao_cec->rx_msg.len = val; in meson_ao_cec_g12a_irq_rx()
435 if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) in meson_ao_cec_g12a_irq_rx()
436 ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; in meson_ao_cec_g12a_irq_rx()
438 for (i = 0; i < ao_cec->rx_msg.len; i++) { in meson_ao_cec_g12a_irq_rx()
439 ret |= regmap_read(ao_cec->regmap_cec, in meson_ao_cec_g12a_irq_rx()
442 ao_cec->rx_msg.msg[i] = val & 0xff; in meson_ao_cec_g12a_irq_rx()
445 ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); in meson_ao_cec_g12a_irq_rx()
449 cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); in meson_ao_cec_g12a_irq_rx()
457 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); in meson_ao_cec_g12a_irq()
469 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); in meson_ao_cec_g12a_irq_thread()
470 regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); in meson_ao_cec_g12a_irq_thread()
473 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); in meson_ao_cec_g12a_irq_thread()
479 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); in meson_ao_cec_g12a_irq_thread()
482 regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); in meson_ao_cec_g12a_irq_thread()
483 regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, in meson_ao_cec_g12a_irq_thread()
485 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); in meson_ao_cec_g12a_irq_thread()
488 /* Initiator reports an error on the CEC bus */ in meson_ao_cec_g12a_irq_thread()
490 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); in meson_ao_cec_g12a_irq_thread()
494 regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); in meson_ao_cec_g12a_irq_thread()
502 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; in meson_ao_cec_g12a_set_log_addr()
507 regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); in meson_ao_cec_g12a_set_log_addr()
508 regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); in meson_ao_cec_g12a_set_log_addr()
512 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, in meson_ao_cec_g12a_set_log_addr()
516 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, in meson_ao_cec_g12a_set_log_addr()
517 BIT(logical_addr - 8), in meson_ao_cec_g12a_set_log_addr()
518 BIT(logical_addr - 8)); in meson_ao_cec_g12a_set_log_addr()
522 ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, in meson_ao_cec_g12a_set_log_addr()
523 BIT(CEC_LOG_ADDR_UNREGISTERED - 8), in meson_ao_cec_g12a_set_log_addr()
524 BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); in meson_ao_cec_g12a_set_log_addr()
526 return ret ? -EIO : 0; in meson_ao_cec_g12a_set_log_addr()
532 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; in meson_ao_cec_g12a_transmit()
539 ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); in meson_ao_cec_g12a_transmit()
543 return -EBUSY; in meson_ao_cec_g12a_transmit()
546 ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); in meson_ao_cec_g12a_transmit()
550 return -EBUSY; in meson_ao_cec_g12a_transmit()
565 for (i = 0; i < msg->len; i++) in meson_ao_cec_g12a_transmit()
566 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, in meson_ao_cec_g12a_transmit()
567 msg->msg[i]); in meson_ao_cec_g12a_transmit()
569 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); in meson_ao_cec_g12a_transmit()
571 return -EIO; in meson_ao_cec_g12a_transmit()
573 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, in meson_ao_cec_g12a_transmit()
584 struct meson_ao_cec_g12a_device *ao_cec = adap->priv; in meson_ao_cec_g12a_adap_enable()
588 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, in meson_ao_cec_g12a_adap_enable()
595 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, in meson_ao_cec_g12a_adap_enable()
603 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, in meson_ao_cec_g12a_adap_enable()
608 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, in meson_ao_cec_g12a_adap_enable()
614 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, in meson_ao_cec_g12a_adap_enable()
617 if (ao_cec->data->ctrl2_setup) in meson_ao_cec_g12a_adap_enable()
618 regmap_write(ao_cec->regmap_cec, CECB_CTRL2, in meson_ao_cec_g12a_adap_enable()
639 hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); in meson_ao_cec_g12a_probe()
643 ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); in meson_ao_cec_g12a_probe()
645 return -ENOMEM; in meson_ao_cec_g12a_probe()
647 ao_cec->data = of_device_get_match_data(&pdev->dev); in meson_ao_cec_g12a_probe()
648 if (!ao_cec->data) { in meson_ao_cec_g12a_probe()
649 dev_err(&pdev->dev, "failed to get match data\n"); in meson_ao_cec_g12a_probe()
650 return -ENODEV; in meson_ao_cec_g12a_probe()
653 spin_lock_init(&ao_cec->cec_reg_lock); in meson_ao_cec_g12a_probe()
654 ao_cec->pdev = pdev; in meson_ao_cec_g12a_probe()
656 ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, in meson_ao_cec_g12a_probe()
661 if (IS_ERR(ao_cec->adap)) in meson_ao_cec_g12a_probe()
662 return PTR_ERR(ao_cec->adap); in meson_ao_cec_g12a_probe()
664 ao_cec->adap->owner = THIS_MODULE; in meson_ao_cec_g12a_probe()
672 ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, in meson_ao_cec_g12a_probe()
674 if (IS_ERR(ao_cec->regmap)) { in meson_ao_cec_g12a_probe()
675 ret = PTR_ERR(ao_cec->regmap); in meson_ao_cec_g12a_probe()
679 ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, in meson_ao_cec_g12a_probe()
681 if (IS_ERR(ao_cec->regmap_cec)) { in meson_ao_cec_g12a_probe()
682 ret = PTR_ERR(ao_cec->regmap_cec); in meson_ao_cec_g12a_probe()
687 ret = devm_request_threaded_irq(&pdev->dev, irq, in meson_ao_cec_g12a_probe()
692 dev_err(&pdev->dev, "irq request failed\n"); in meson_ao_cec_g12a_probe()
696 ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); in meson_ao_cec_g12a_probe()
697 if (IS_ERR(ao_cec->oscin)) { in meson_ao_cec_g12a_probe()
698 dev_err(&pdev->dev, "oscin clock request failed\n"); in meson_ao_cec_g12a_probe()
699 ret = PTR_ERR(ao_cec->oscin); in meson_ao_cec_g12a_probe()
707 ret = clk_prepare_enable(ao_cec->core); in meson_ao_cec_g12a_probe()
709 dev_err(&pdev->dev, "core clock enable failed\n"); in meson_ao_cec_g12a_probe()
713 device_reset_optional(&pdev->dev); in meson_ao_cec_g12a_probe()
717 ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, in meson_ao_cec_g12a_probe()
718 ao_cec->adap); in meson_ao_cec_g12a_probe()
719 if (!ao_cec->notify) { in meson_ao_cec_g12a_probe()
720 ret = -ENOMEM; in meson_ao_cec_g12a_probe()
724 ret = cec_register_adapter(ao_cec->adap, &pdev->dev); in meson_ao_cec_g12a_probe()
729 regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); in meson_ao_cec_g12a_probe()
734 cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); in meson_ao_cec_g12a_probe()
737 clk_disable_unprepare(ao_cec->core); in meson_ao_cec_g12a_probe()
740 cec_delete_adapter(ao_cec->adap); in meson_ao_cec_g12a_probe()
742 dev_err(&pdev->dev, "CEC controller registration failed\n"); in meson_ao_cec_g12a_probe()
751 clk_disable_unprepare(ao_cec->core); in meson_ao_cec_g12a_remove()
753 cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); in meson_ao_cec_g12a_remove()
755 cec_unregister_adapter(ao_cec->adap); in meson_ao_cec_g12a_remove()
768 .compatible = "amlogic,meson-g12a-ao-cec",
772 .compatible = "amlogic,meson-sm1-ao-cec",
783 .name = "meson-ao-cec-g12a",
790 MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");