1
2
3
4
5
6
7
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
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
47
48
49
50
51
52
53
54
55
56
57
58
59
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
78
79
80
81
82
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
94
95
96
97
98
99
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
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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, ®0);
223 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1);
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
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
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
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
281 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
282 CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN);
283
284
285 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
286 CECB_CLK_CNTL_BYPASS_EN, 0);
287
288
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, ®);
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
480 if (stat & CECB_INTR_INITIATOR_ERR)
481 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR);
482
483
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
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
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
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
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
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
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
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
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
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 { }
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