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
7 * Author: Neil Armstrong <narmstrong@baylibre.com>
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
125 #define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0)
127 #define CECB_INTR_MASK 0x02
128 #define CECB_LADD_LOW 0x05
129 #define CECB_LADD_HIGH 0x06
130 #define CECB_TX_CNT 0x07
131 #define CECB_RX_CNT 0x08
132 #define CECB_STAT0 0x09
133 #define CECB_TX_DATA00 0x10
134 #define CECB_TX_DATA01 0x11
135 #define CECB_TX_DATA02 0x12
136 #define CECB_TX_DATA03 0x13
137 #define CECB_TX_DATA04 0x14
138 #define CECB_TX_DATA05 0x15
139 #define CECB_TX_DATA06 0x16
140 #define CECB_TX_DATA07 0x17
141 #define CECB_TX_DATA08 0x18
142 #define CECB_TX_DATA09 0x19
143 #define CECB_TX_DATA10 0x1A
144 #define CECB_TX_DATA11 0x1B
145 #define CECB_TX_DATA12 0x1C
146 #define CECB_TX_DATA13 0x1D
147 #define CECB_TX_DATA14 0x1E
148 #define CECB_TX_DATA15 0x1F
149 #define CECB_RX_DATA00 0x20
150 #define CECB_RX_DATA01 0x21
151 #define CECB_RX_DATA02 0x22
152 #define CECB_RX_DATA03 0x23
153 #define CECB_RX_DATA04 0x24
154 #define CECB_RX_DATA05 0x25
155 #define CECB_RX_DATA06 0x26
156 #define CECB_RX_DATA07 0x27
157 #define CECB_RX_DATA08 0x28
158 #define CECB_RX_DATA09 0x29
159 #define CECB_RX_DATA10 0x2A
160 #define CECB_RX_DATA11 0x2B
161 #define CECB_RX_DATA12 0x2C
162 #define CECB_RX_DATA13 0x2D
163 #define CECB_RX_DATA14 0x2E
164 #define CECB_RX_DATA15 0x2F
165 #define CECB_LOCK_BUF 0x30
167 #define CECB_LOCK_BUF_EN BIT(0)
169 #define CECB_WAKEUPCTRL 0x31
171 struct meson_ao_cec_g12a_data
{
172 /* Setup the internal CECB_CTRL2 register */
176 struct meson_ao_cec_g12a_device
{
177 struct platform_device
*pdev
;
178 struct regmap
*regmap
;
179 struct regmap
*regmap_cec
;
180 spinlock_t cec_reg_lock
;
181 struct cec_notifier
*notify
;
182 struct cec_adapter
*adap
;
183 struct cec_msg rx_msg
;
186 const struct meson_ao_cec_g12a_data
*data
;
189 static const struct regmap_config meson_ao_cec_g12a_regmap_conf
= {
193 .max_register
= CECB_INTR_STAT_REG
,
197 * The AO-CECB embeds a dual/divider to generate a more precise
198 * 32,768KHz clock for CEC core clock.
201 * ______ | Div1 |-| Cnt1 | ______
202 * | | /|______| |______|\ | |
203 * Xtal-->| Gate |---| ______ ______ X-X--| Gate |-->
204 * |______| | \| | | |/ | |______|
205 * | | Div2 |-| Cnt2 | |
206 * | |______| |______| |
207 * |_______________________|
209 * The dividing can be switched to single or dual, with a counter
210 * for each divider to set when the switching is done.
211 * The entire dividing mechanism can be also bypassed.
214 struct meson_ao_cec_g12a_dualdiv_clk
{
216 struct regmap
*regmap
;
219 #define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \
220 container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \
223 meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw
*hw
,
224 unsigned long parent_rate
)
226 struct meson_ao_cec_g12a_dualdiv_clk
*dualdiv_clk
=
227 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw
);
231 regmap_read(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
, ®0
);
232 regmap_read(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
, ®1
);
234 if (reg1
& CECB_CLK_CNTL_BYPASS_EN
)
237 if (reg0
& CECB_CLK_CNTL_DUAL_EN
) {
238 unsigned long n2
, m1
, m2
, f1
, f2
, p1
, p2
;
240 n1
= FIELD_GET(CECB_CLK_CNTL_N1
, reg0
) + 1;
241 n2
= FIELD_GET(CECB_CLK_CNTL_N2
, reg0
) + 1;
243 m1
= FIELD_GET(CECB_CLK_CNTL_M1
, reg1
) + 1;
244 m2
= FIELD_GET(CECB_CLK_CNTL_M1
, reg1
) + 1;
246 f1
= DIV_ROUND_CLOSEST(parent_rate
, n1
);
247 f2
= DIV_ROUND_CLOSEST(parent_rate
, n2
);
249 p1
= DIV_ROUND_CLOSEST(100000000 * m1
, f1
* (m1
+ m2
));
250 p2
= DIV_ROUND_CLOSEST(100000000 * m2
, f2
* (m1
+ m2
));
252 return DIV_ROUND_UP(100000000, p1
+ p2
);
255 n1
= FIELD_GET(CECB_CLK_CNTL_N1
, reg0
) + 1;
257 return DIV_ROUND_CLOSEST(parent_rate
, n1
);
260 static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw
*hw
)
262 struct meson_ao_cec_g12a_dualdiv_clk
*dualdiv_clk
=
263 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw
);
266 /* Disable Input & Output */
267 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
268 CECB_CLK_CNTL_INPUT_EN
| CECB_CLK_CNTL_OUTPUT_EN
,
272 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
274 FIELD_PREP(CECB_CLK_CNTL_N1
, 733 - 1));
276 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
278 FIELD_PREP(CECB_CLK_CNTL_N2
, 732 - 1));
281 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG1
,
283 FIELD_PREP(CECB_CLK_CNTL_M1
, 8 - 1));
285 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG1
,
287 FIELD_PREP(CECB_CLK_CNTL_M2
, 11 - 1));
289 /* Enable Dual divisor */
290 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
291 CECB_CLK_CNTL_DUAL_EN
, CECB_CLK_CNTL_DUAL_EN
);
293 /* Disable divisor bypass */
294 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG1
,
295 CECB_CLK_CNTL_BYPASS_EN
, 0);
297 /* Enable Input & Output */
298 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
299 CECB_CLK_CNTL_INPUT_EN
| CECB_CLK_CNTL_OUTPUT_EN
,
300 CECB_CLK_CNTL_INPUT_EN
| CECB_CLK_CNTL_OUTPUT_EN
);
305 static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw
*hw
)
307 struct meson_ao_cec_g12a_dualdiv_clk
*dualdiv_clk
=
308 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw
);
310 regmap_update_bits(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
,
311 CECB_CLK_CNTL_INPUT_EN
| CECB_CLK_CNTL_OUTPUT_EN
,
315 static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw
*hw
)
317 struct meson_ao_cec_g12a_dualdiv_clk
*dualdiv_clk
=
318 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw
);
321 regmap_read(dualdiv_clk
->regmap
, CECB_CLK_CNTL_REG0
, &val
);
323 return !!(val
& (CECB_CLK_CNTL_INPUT_EN
| CECB_CLK_CNTL_OUTPUT_EN
));
326 static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops
= {
327 .recalc_rate
= meson_ao_cec_g12a_dualdiv_clk_recalc_rate
,
328 .is_enabled
= meson_ao_cec_g12a_dualdiv_clk_is_enabled
,
329 .enable
= meson_ao_cec_g12a_dualdiv_clk_enable
,
330 .disable
= meson_ao_cec_g12a_dualdiv_clk_disable
,
333 static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device
*ao_cec
)
335 struct meson_ao_cec_g12a_dualdiv_clk
*dualdiv_clk
;
336 struct device
*dev
= &ao_cec
->pdev
->dev
;
337 struct clk_init_data init
;
338 const char *parent_name
;
342 dualdiv_clk
= devm_kzalloc(dev
, sizeof(*dualdiv_clk
), GFP_KERNEL
);
346 name
= kasprintf(GFP_KERNEL
, "%s#dualdiv_clk", dev_name(dev
));
350 parent_name
= __clk_get_name(ao_cec
->oscin
);
353 init
.ops
= &meson_ao_cec_g12a_dualdiv_clk_ops
;
355 init
.parent_names
= &parent_name
;
356 init
.num_parents
= 1;
357 dualdiv_clk
->regmap
= ao_cec
->regmap
;
358 dualdiv_clk
->hw
.init
= &init
;
360 clk
= devm_clk_register(dev
, &dualdiv_clk
->hw
);
363 dev_err(dev
, "failed to register clock\n");
372 static int meson_ao_cec_g12a_read(void *context
, unsigned int addr
,
375 struct meson_ao_cec_g12a_device
*ao_cec
= context
;
376 u32 reg
= FIELD_PREP(CECB_RW_ADDR
, addr
);
379 ret
= regmap_write(ao_cec
->regmap
, CECB_RW_REG
, reg
);
383 ret
= regmap_read_poll_timeout(ao_cec
->regmap
, CECB_RW_REG
, reg
,
384 !(reg
& CECB_RW_BUS_BUSY
),
389 ret
= regmap_read(ao_cec
->regmap
, CECB_RW_REG
, ®
);
391 *data
= FIELD_GET(CECB_RW_RD_DATA
, reg
);
396 static int meson_ao_cec_g12a_write(void *context
, unsigned int addr
,
399 struct meson_ao_cec_g12a_device
*ao_cec
= context
;
400 u32 reg
= FIELD_PREP(CECB_RW_ADDR
, addr
) |
401 FIELD_PREP(CECB_RW_WR_DATA
, data
) |
404 return regmap_write(ao_cec
->regmap
, CECB_RW_REG
, reg
);
407 static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf
= {
410 .reg_read
= meson_ao_cec_g12a_read
,
411 .reg_write
= meson_ao_cec_g12a_write
,
412 .max_register
= 0xffff,
416 meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device
*ao_cec
,
419 u32 cfg
= CECB_INTR_DONE
| CECB_INTR_EOM
| CECB_INTR_NACK
|
420 CECB_INTR_ARB_LOSS
| CECB_INTR_INITIATOR_ERR
|
421 CECB_INTR_FOLLOWER_ERR
;
423 regmap_write(ao_cec
->regmap
, CECB_INTR_MASKN_REG
,
427 static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device
*ao_cec
)
432 ret
= regmap_read(ao_cec
->regmap_cec
, CECB_RX_CNT
, &val
);
434 ao_cec
->rx_msg
.len
= val
;
435 if (ao_cec
->rx_msg
.len
> CEC_MAX_MSG_SIZE
)
436 ao_cec
->rx_msg
.len
= CEC_MAX_MSG_SIZE
;
438 for (i
= 0; i
< ao_cec
->rx_msg
.len
; i
++) {
439 ret
|= regmap_read(ao_cec
->regmap_cec
,
440 CECB_RX_DATA00
+ i
, &val
);
442 ao_cec
->rx_msg
.msg
[i
] = val
& 0xff;
445 ret
|= regmap_write(ao_cec
->regmap_cec
, CECB_LOCK_BUF
, 0);
449 cec_received_msg(ao_cec
->adap
, &ao_cec
->rx_msg
);
452 static irqreturn_t
meson_ao_cec_g12a_irq(int irq
, void *data
)
454 struct meson_ao_cec_g12a_device
*ao_cec
= data
;
457 regmap_read(ao_cec
->regmap
, CECB_INTR_STAT_REG
, &stat
);
459 return IRQ_WAKE_THREAD
;
464 static irqreturn_t
meson_ao_cec_g12a_irq_thread(int irq
, void *data
)
466 struct meson_ao_cec_g12a_device
*ao_cec
= data
;
469 regmap_read(ao_cec
->regmap
, CECB_INTR_STAT_REG
, &stat
);
470 regmap_write(ao_cec
->regmap
, CECB_INTR_CLR_REG
, stat
);
472 if (stat
& CECB_INTR_DONE
)
473 cec_transmit_attempt_done(ao_cec
->adap
, CEC_TX_STATUS_OK
);
475 if (stat
& CECB_INTR_EOM
)
476 meson_ao_cec_g12a_irq_rx(ao_cec
);
478 if (stat
& CECB_INTR_NACK
)
479 cec_transmit_attempt_done(ao_cec
->adap
, CEC_TX_STATUS_NACK
);
481 if (stat
& CECB_INTR_ARB_LOSS
) {
482 regmap_write(ao_cec
->regmap_cec
, CECB_TX_CNT
, 0);
483 regmap_update_bits(ao_cec
->regmap_cec
, CECB_CTRL
,
484 CECB_CTRL_SEND
| CECB_CTRL_TYPE
, 0);
485 cec_transmit_attempt_done(ao_cec
->adap
, CEC_TX_STATUS_ARB_LOST
);
488 /* Initiator reports an error on the CEC bus */
489 if (stat
& CECB_INTR_INITIATOR_ERR
)
490 cec_transmit_attempt_done(ao_cec
->adap
, CEC_TX_STATUS_ERROR
);
492 /* Follower reports a receive error, just reset RX buffer */
493 if (stat
& CECB_INTR_FOLLOWER_ERR
)
494 regmap_write(ao_cec
->regmap_cec
, CECB_LOCK_BUF
, 0);
500 meson_ao_cec_g12a_set_log_addr(struct cec_adapter
*adap
, u8 logical_addr
)
502 struct meson_ao_cec_g12a_device
*ao_cec
= adap
->priv
;
505 if (logical_addr
== CEC_LOG_ADDR_INVALID
) {
506 /* Assume this will allways succeed */
507 regmap_write(ao_cec
->regmap_cec
, CECB_LADD_LOW
, 0);
508 regmap_write(ao_cec
->regmap_cec
, CECB_LADD_HIGH
, 0);
511 } else if (logical_addr
< 8) {
512 ret
= regmap_update_bits(ao_cec
->regmap_cec
, CECB_LADD_LOW
,
516 ret
= regmap_update_bits(ao_cec
->regmap_cec
, CECB_LADD_HIGH
,
517 BIT(logical_addr
- 8),
518 BIT(logical_addr
- 8));
521 /* Always set Broadcast/Unregistered 15 address */
522 ret
|= regmap_update_bits(ao_cec
->regmap_cec
, CECB_LADD_HIGH
,
523 BIT(CEC_LOG_ADDR_UNREGISTERED
- 8),
524 BIT(CEC_LOG_ADDR_UNREGISTERED
- 8));
526 return ret
? -EIO
: 0;
529 static int meson_ao_cec_g12a_transmit(struct cec_adapter
*adap
, u8 attempts
,
530 u32 signal_free_time
, struct cec_msg
*msg
)
532 struct meson_ao_cec_g12a_device
*ao_cec
= adap
->priv
;
538 /* Check if RX is in progress */
539 ret
= regmap_read(ao_cec
->regmap_cec
, CECB_LOCK_BUF
, &val
);
542 if (val
& CECB_LOCK_BUF_EN
)
545 /* Check if TX Busy */
546 ret
= regmap_read(ao_cec
->regmap_cec
, CECB_CTRL
, &val
);
549 if (val
& CECB_CTRL_SEND
)
552 switch (signal_free_time
) {
553 case CEC_SIGNAL_FREE_TIME_RETRY
:
554 type
= CECB_CTRL_TYPE_RETRY
;
556 case CEC_SIGNAL_FREE_TIME_NEXT_XFER
:
557 type
= CECB_CTRL_TYPE_NEXT
;
559 case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR
:
561 type
= CECB_CTRL_TYPE_NEW
;
565 for (i
= 0; i
< msg
->len
; i
++)
566 ret
|= regmap_write(ao_cec
->regmap_cec
, CECB_TX_DATA00
+ i
,
569 ret
|= regmap_write(ao_cec
->regmap_cec
, CECB_TX_CNT
, msg
->len
);
573 ret
= regmap_update_bits(ao_cec
->regmap_cec
, CECB_CTRL
,
577 FIELD_PREP(CECB_CTRL_TYPE
, type
));
582 static int meson_ao_cec_g12a_adap_enable(struct cec_adapter
*adap
, bool enable
)
584 struct meson_ao_cec_g12a_device
*ao_cec
= adap
->priv
;
586 meson_ao_cec_g12a_irq_setup(ao_cec
, false);
588 regmap_update_bits(ao_cec
->regmap
, CECB_GEN_CNTL_REG
,
589 CECB_GEN_CNTL_RESET
, CECB_GEN_CNTL_RESET
);
595 regmap_update_bits(ao_cec
->regmap
, CECB_GEN_CNTL_REG
,
596 CECB_GEN_CNTL_FILTER_TICK_SEL
|
597 CECB_GEN_CNTL_FILTER_DEL
,
598 FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL
,
599 CECB_GEN_CNTL_FILTER_TICK_1US
) |
600 FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL
, 7));
602 /* Enable System Clock */
603 regmap_update_bits(ao_cec
->regmap
, CECB_GEN_CNTL_REG
,
604 CECB_GEN_CNTL_SYS_CLK_EN
,
605 CECB_GEN_CNTL_SYS_CLK_EN
);
607 /* Enable gated clock (Normal mode). */
608 regmap_update_bits(ao_cec
->regmap
, CECB_GEN_CNTL_REG
,
609 CECB_GEN_CNTL_CLK_CTRL_MASK
,
610 FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK
,
611 CECB_GEN_CNTL_CLK_ENABLE
));
614 regmap_update_bits(ao_cec
->regmap
, CECB_GEN_CNTL_REG
,
615 CECB_GEN_CNTL_RESET
, 0);
617 if (ao_cec
->data
->ctrl2_setup
)
618 regmap_write(ao_cec
->regmap_cec
, CECB_CTRL2
,
619 FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX
, 2));
621 meson_ao_cec_g12a_irq_setup(ao_cec
, true);
626 static const struct cec_adap_ops meson_ao_cec_g12a_ops
= {
627 .adap_enable
= meson_ao_cec_g12a_adap_enable
,
628 .adap_log_addr
= meson_ao_cec_g12a_set_log_addr
,
629 .adap_transmit
= meson_ao_cec_g12a_transmit
,
632 static int meson_ao_cec_g12a_probe(struct platform_device
*pdev
)
634 struct meson_ao_cec_g12a_device
*ao_cec
;
635 struct device
*hdmi_dev
;
636 struct resource
*res
;
640 hdmi_dev
= cec_notifier_parse_hdmi_phandle(&pdev
->dev
);
641 if (IS_ERR(hdmi_dev
))
642 return PTR_ERR(hdmi_dev
);
644 ao_cec
= devm_kzalloc(&pdev
->dev
, sizeof(*ao_cec
), GFP_KERNEL
);
648 ao_cec
->data
= of_device_get_match_data(&pdev
->dev
);
650 dev_err(&pdev
->dev
, "failed to get match data\n");
654 spin_lock_init(&ao_cec
->cec_reg_lock
);
657 ao_cec
->adap
= cec_allocate_adapter(&meson_ao_cec_g12a_ops
, ao_cec
,
660 CEC_CAP_CONNECTOR_INFO
,
662 if (IS_ERR(ao_cec
->adap
))
663 return PTR_ERR(ao_cec
->adap
);
665 ao_cec
->adap
->owner
= THIS_MODULE
;
667 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
668 base
= devm_ioremap_resource(&pdev
->dev
, res
);
671 goto out_probe_adapter
;
674 ao_cec
->regmap
= devm_regmap_init_mmio(&pdev
->dev
, base
,
675 &meson_ao_cec_g12a_regmap_conf
);
676 if (IS_ERR(ao_cec
->regmap
)) {
677 ret
= PTR_ERR(ao_cec
->regmap
);
678 goto out_probe_adapter
;
681 ao_cec
->regmap_cec
= devm_regmap_init(&pdev
->dev
, NULL
, ao_cec
,
682 &meson_ao_cec_g12a_cec_regmap_conf
);
683 if (IS_ERR(ao_cec
->regmap_cec
)) {
684 ret
= PTR_ERR(ao_cec
->regmap_cec
);
685 goto out_probe_adapter
;
688 irq
= platform_get_irq(pdev
, 0);
689 ret
= devm_request_threaded_irq(&pdev
->dev
, irq
,
690 meson_ao_cec_g12a_irq
,
691 meson_ao_cec_g12a_irq_thread
,
694 dev_err(&pdev
->dev
, "irq request failed\n");
695 goto out_probe_adapter
;
698 ao_cec
->oscin
= devm_clk_get(&pdev
->dev
, "oscin");
699 if (IS_ERR(ao_cec
->oscin
)) {
700 dev_err(&pdev
->dev
, "oscin clock request failed\n");
701 ret
= PTR_ERR(ao_cec
->oscin
);
702 goto out_probe_adapter
;
705 ret
= meson_ao_cec_g12a_setup_clk(ao_cec
);
707 goto out_probe_adapter
;
709 ret
= clk_prepare_enable(ao_cec
->core
);
711 dev_err(&pdev
->dev
, "core clock enable failed\n");
712 goto out_probe_adapter
;
715 device_reset_optional(&pdev
->dev
);
717 platform_set_drvdata(pdev
, ao_cec
);
719 ao_cec
->notify
= cec_notifier_cec_adap_register(hdmi_dev
, NULL
,
721 if (!ao_cec
->notify
) {
723 goto out_probe_core_clk
;
726 ret
= cec_register_adapter(ao_cec
->adap
, &pdev
->dev
);
728 goto out_probe_notify
;
731 regmap_write(ao_cec
->regmap
, CECB_GEN_CNTL_REG
, CECB_GEN_CNTL_RESET
);
736 cec_notifier_cec_adap_unregister(ao_cec
->notify
, ao_cec
->adap
);
739 clk_disable_unprepare(ao_cec
->core
);
742 cec_delete_adapter(ao_cec
->adap
);
744 dev_err(&pdev
->dev
, "CEC controller registration failed\n");
749 static int meson_ao_cec_g12a_remove(struct platform_device
*pdev
)
751 struct meson_ao_cec_g12a_device
*ao_cec
= platform_get_drvdata(pdev
);
753 clk_disable_unprepare(ao_cec
->core
);
755 cec_notifier_cec_adap_unregister(ao_cec
->notify
, ao_cec
->adap
);
757 cec_unregister_adapter(ao_cec
->adap
);
762 static const struct meson_ao_cec_g12a_data ao_cec_g12a_data
= {
763 .ctrl2_setup
= false,
766 static const struct meson_ao_cec_g12a_data ao_cec_sm1_data
= {
770 static const struct of_device_id meson_ao_cec_g12a_of_match
[] = {
772 .compatible
= "amlogic,meson-g12a-ao-cec",
773 .data
= &ao_cec_g12a_data
,
776 .compatible
= "amlogic,meson-sm1-ao-cec",
777 .data
= &ao_cec_sm1_data
,
781 MODULE_DEVICE_TABLE(of
, meson_ao_cec_g12a_of_match
);
783 static struct platform_driver meson_ao_cec_g12a_driver
= {
784 .probe
= meson_ao_cec_g12a_probe
,
785 .remove
= meson_ao_cec_g12a_remove
,
787 .name
= "meson-ao-cec-g12a",
788 .of_match_table
= of_match_ptr(meson_ao_cec_g12a_of_match
),
792 module_platform_driver(meson_ao_cec_g12a_driver
);
794 MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
795 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
796 MODULE_LICENSE("GPL");