1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Amlogic Meson AO CEC G12A Controller
5 * Copyright (C) 2017 Amlogic, Inc. All rights reserved
6 * Copyright (C) 2019 BayLibre, SAS
10 #include <linux/bitfield.h>
11 #include <linux/clk.h>
12 #include <linux/device.h>
14 #include <linux/delay.h>
15 #include <linux/kernel.h>
16 #include <linux/module.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>
31 #define CECB_CLK_CNTL_REG0 0x00
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)
39 #define CECB_CLK_CNTL_REG1 0x04
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)
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.
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.
61 #define CECB_GEN_CNTL_REG 0x08
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)
78 * [15:8] cec_reg_wrdata
82 * [31:24] cec_reg_rddata
84 #define CECB_RW_REG 0x0c
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)
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
101 #define CECB_INTR_MASKN_REG 0x10
102 #define CECB_INTR_CLR_REG 0x14
103 #define CECB_INTR_STAT_REG 0x18
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)
115 #define CECB_CTRL 0x00
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
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
164 #define CECB_LOCK_BUF_EN BIT(0)
166 #define CECB_WAKEUPCTRL 0x31
168 struct 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;
180 static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
184 .max_register = CECB_INTR_STAT_REG,
188 * The AO-CECB embeds a dual/divider to generate a more precise
189 * 32,768KHz clock for CEC core clock.
192 * ______ | Div1 |-| Cnt1 | ______
193 * | | /|______| |______|\ | |
194 * Xtal-->| Gate |---| ______ ______ X-X--| Gate |-->
195 * |______| | \| | | |/ | |______|
196 * | | Div2 |-| Cnt2 | |
197 * | |______| |______| |
198 * |_______________________|
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.
205 struct meson_ao_cec_g12a_dualdiv_clk {
207 struct regmap *regmap;
210 #define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \
211 container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \
214 meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw,
215 unsigned long parent_rate)
217 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
218 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
222 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0);
223 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1);
225 if (reg1 & CECB_CLK_CNTL_BYPASS_EN)
228 if (reg0 & CECB_CLK_CNTL_DUAL_EN) {
229 unsigned long n2, m1, m2, f1, f2, p1, p2;
231 n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
232 n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1;
234 m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
235 m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
237 f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
238 f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
240 p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
241 p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
243 return DIV_ROUND_UP(100000000, p1 + p2);
246 n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
248 return DIV_ROUND_CLOSEST(parent_rate, n1);
251 static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw)
253 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
254 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
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,
263 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
265 FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1));
267 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
269 FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1));
272 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
274 FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1));
276 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
278 FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1));
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);
284 /* Disable divisor bypass */
285 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
286 CECB_CLK_CNTL_BYPASS_EN, 0);
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);
296 static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw)
298 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
299 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
301 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
302 CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
306 static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw)
308 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
309 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
312 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val);
314 return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN));
317 static 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,
324 static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec)
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;
333 dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL);
337 name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev));
341 parent_name = __clk_get_name(ao_cec->oscin);
344 init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops;
346 init.parent_names = &parent_name;
347 init.num_parents = 1;
348 dualdiv_clk->regmap = ao_cec->regmap;
349 dualdiv_clk->hw.init = &init;
351 clk = devm_clk_register(dev, &dualdiv_clk->hw);
354 dev_err(dev, "failed to register clock\n");
363 static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
366 struct meson_ao_cec_g12a_device *ao_cec = context;
367 u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
371 spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
373 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
377 ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
378 !(reg & CECB_RW_BUS_BUSY),
383 ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®);
385 *data = FIELD_GET(CECB_RW_RD_DATA, reg);
388 spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
393 static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
396 struct meson_ao_cec_g12a_device *ao_cec = context;
398 u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
399 FIELD_PREP(CECB_RW_WR_DATA, data) |
403 spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
405 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
407 spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
412 static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
415 .reg_read = meson_ao_cec_g12a_read,
416 .reg_write = meson_ao_cec_g12a_write,
417 .max_register = 0xffff,
422 meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec,
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;
429 regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG,
433 static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec)
438 ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val);
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;
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);
448 ao_cec->rx_msg.msg[i] = val & 0xff;
451 ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
455 cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
458 static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data)
460 struct meson_ao_cec_g12a_device *ao_cec = data;
463 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
465 return IRQ_WAKE_THREAD;
470 static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data)
472 struct meson_ao_cec_g12a_device *ao_cec = data;
475 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
476 regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat);
478 if (stat & CECB_INTR_DONE)
479 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK);
481 if (stat & CECB_INTR_EOM)
482 meson_ao_cec_g12a_irq_rx(ao_cec);
484 if (stat & CECB_INTR_NACK)
485 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK);
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);
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);
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);
506 meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
508 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
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);
517 } else if (logical_addr < 8) {
518 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW,
522 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
523 BIT(logical_addr - 8),
524 BIT(logical_addr - 8));
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));
532 return ret ? -EIO : 0;
535 static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts,
536 u32 signal_free_time, struct cec_msg *msg)
538 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
544 /* Check if RX is in progress */
545 ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val);
548 if (val & CECB_LOCK_BUF_EN)
551 /* Check if TX Busy */
552 ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val);
555 if (val & CECB_CTRL_SEND)
558 switch (signal_free_time) {
559 case CEC_SIGNAL_FREE_TIME_RETRY:
560 type = CECB_CTRL_TYPE_RETRY;
562 case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
563 type = CECB_CTRL_TYPE_NEXT;
565 case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
567 type = CECB_CTRL_TYPE_NEW;
571 for (i = 0; i < msg->len; i++)
572 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i,
575 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len);
579 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
583 FIELD_PREP(CECB_CTRL_TYPE, type));
588 static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
590 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
592 meson_ao_cec_g12a_irq_setup(ao_cec, false);
594 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
595 CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET);
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));
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);
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));
620 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
621 CECB_GEN_CNTL_RESET, 0);
623 meson_ao_cec_g12a_irq_setup(ao_cec, true);
628 static 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,
634 static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
636 struct meson_ao_cec_g12a_device *ao_cec;
637 struct device *hdmi_dev;
638 struct resource *res;
642 hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
643 if (IS_ERR(hdmi_dev))
644 return PTR_ERR(hdmi_dev);
646 ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
650 spin_lock_init(&ao_cec->cec_reg_lock);
653 ao_cec->notify = cec_notifier_get(hdmi_dev);
657 ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec,
661 if (IS_ERR(ao_cec->adap)) {
662 ret = PTR_ERR(ao_cec->adap);
663 goto out_probe_notify;
666 ao_cec->adap->owner = THIS_MODULE;
668 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
669 base = devm_ioremap_resource(&pdev->dev, res);
672 goto out_probe_adapter;
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;
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;
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,
695 dev_err(&pdev->dev, "irq request failed\n");
696 goto out_probe_adapter;
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;
706 ret = meson_ao_cec_g12a_setup_clk(ao_cec);
708 goto out_probe_adapter;
710 ret = clk_prepare_enable(ao_cec->core);
712 dev_err(&pdev->dev, "core clock enable failed\n");
713 goto out_probe_adapter;
716 device_reset_optional(&pdev->dev);
718 platform_set_drvdata(pdev, ao_cec);
720 ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
722 cec_notifier_put(ao_cec->notify);
723 goto out_probe_core_clk;
727 regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
729 cec_register_cec_notifier(ao_cec->adap, ao_cec->notify);
734 clk_disable_unprepare(ao_cec->core);
737 cec_delete_adapter(ao_cec->adap);
740 cec_notifier_put(ao_cec->notify);
742 dev_err(&pdev->dev, "CEC controller registration failed\n");
747 static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
749 struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
751 clk_disable_unprepare(ao_cec->core);
753 cec_unregister_adapter(ao_cec->adap);
755 cec_notifier_put(ao_cec->notify);
760 static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
761 { .compatible = "amlogic,meson-g12a-ao-cec", },
764 MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
766 static struct platform_driver meson_ao_cec_g12a_driver = {
767 .probe = meson_ao_cec_g12a_probe,
768 .remove = meson_ao_cec_g12a_remove,
770 .name = "meson-ao-cec-g12a",
771 .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
775 module_platform_driver(meson_ao_cec_g12a_driver);
777 MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
779 MODULE_LICENSE("GPL");