0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/bitfield.h>
0011 #include <linux/clk.h>
0012 #include <linux/device.h>
0013 #include <linux/io.h>
0014 #include <linux/delay.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/types.h>
0021 #include <linux/interrupt.h>
0022 #include <linux/reset.h>
0023 #include <linux/slab.h>
0024 #include <linux/regmap.h>
0025 #include <media/cec.h>
0026 #include <media/cec-notifier.h>
0027 #include <linux/clk-provider.h>
0028
0029
0030
0031 #define CECB_CLK_CNTL_REG0 0x00
0032
0033 #define CECB_CLK_CNTL_N1 GENMASK(11, 0)
0034 #define CECB_CLK_CNTL_N2 GENMASK(23, 12)
0035 #define CECB_CLK_CNTL_DUAL_EN BIT(28)
0036 #define CECB_CLK_CNTL_OUTPUT_EN BIT(30)
0037 #define CECB_CLK_CNTL_INPUT_EN BIT(31)
0038
0039 #define CECB_CLK_CNTL_REG1 0x04
0040
0041 #define CECB_CLK_CNTL_M1 GENMASK(11, 0)
0042 #define CECB_CLK_CNTL_M2 GENMASK(23, 12)
0043 #define CECB_CLK_CNTL_BYPASS_EN BIT(24)
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 #define CECB_GEN_CNTL_REG 0x08
0062
0063 #define CECB_GEN_CNTL_RESET BIT(0)
0064 #define CECB_GEN_CNTL_CLK_DISABLE 0
0065 #define CECB_GEN_CNTL_CLK_ENABLE 1
0066 #define CECB_GEN_CNTL_CLK_ENABLE_DBG 2
0067 #define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1)
0068 #define CECB_GEN_CNTL_SYS_CLK_EN BIT(3)
0069 #define CECB_GEN_CNTL_FILTER_TICK_125NS 0
0070 #define CECB_GEN_CNTL_FILTER_TICK_1US 1
0071 #define CECB_GEN_CNTL_FILTER_TICK_10US 2
0072 #define CECB_GEN_CNTL_FILTER_TICK_100US 3
0073 #define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8)
0074 #define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12)
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 #define CECB_RW_REG 0x0c
0085
0086 #define CECB_RW_ADDR GENMASK(7, 0)
0087 #define CECB_RW_WR_DATA GENMASK(15, 8)
0088 #define CECB_RW_WRITE_EN BIT(16)
0089 #define CECB_RW_BUS_BUSY BIT(23)
0090 #define CECB_RW_RD_DATA GENMASK(31, 24)
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 #define CECB_INTR_MASKN_REG 0x10
0102 #define CECB_INTR_CLR_REG 0x14
0103 #define CECB_INTR_STAT_REG 0x18
0104
0105 #define CECB_INTR_DONE BIT(0)
0106 #define CECB_INTR_EOM BIT(1)
0107 #define CECB_INTR_NACK BIT(2)
0108 #define CECB_INTR_ARB_LOSS BIT(3)
0109 #define CECB_INTR_INITIATOR_ERR BIT(4)
0110 #define CECB_INTR_FOLLOWER_ERR BIT(5)
0111 #define CECB_INTR_WAKE_UP BIT(6)
0112
0113
0114
0115 #define CECB_CTRL 0x00
0116
0117 #define CECB_CTRL_SEND BIT(0)
0118 #define CECB_CTRL_TYPE GENMASK(2, 1)
0119 #define CECB_CTRL_TYPE_RETRY 0
0120 #define CECB_CTRL_TYPE_NEW 1
0121 #define CECB_CTRL_TYPE_NEXT 2
0122
0123 #define CECB_CTRL2 0x01
0124
0125 #define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0)
0126
0127 #define CECB_INTR_MASK 0x02
0128 #define CECB_LADD_LOW 0x05
0129 #define CECB_LADD_HIGH 0x06
0130 #define CECB_TX_CNT 0x07
0131 #define CECB_RX_CNT 0x08
0132 #define CECB_STAT0 0x09
0133 #define CECB_TX_DATA00 0x10
0134 #define CECB_TX_DATA01 0x11
0135 #define CECB_TX_DATA02 0x12
0136 #define CECB_TX_DATA03 0x13
0137 #define CECB_TX_DATA04 0x14
0138 #define CECB_TX_DATA05 0x15
0139 #define CECB_TX_DATA06 0x16
0140 #define CECB_TX_DATA07 0x17
0141 #define CECB_TX_DATA08 0x18
0142 #define CECB_TX_DATA09 0x19
0143 #define CECB_TX_DATA10 0x1A
0144 #define CECB_TX_DATA11 0x1B
0145 #define CECB_TX_DATA12 0x1C
0146 #define CECB_TX_DATA13 0x1D
0147 #define CECB_TX_DATA14 0x1E
0148 #define CECB_TX_DATA15 0x1F
0149 #define CECB_RX_DATA00 0x20
0150 #define CECB_RX_DATA01 0x21
0151 #define CECB_RX_DATA02 0x22
0152 #define CECB_RX_DATA03 0x23
0153 #define CECB_RX_DATA04 0x24
0154 #define CECB_RX_DATA05 0x25
0155 #define CECB_RX_DATA06 0x26
0156 #define CECB_RX_DATA07 0x27
0157 #define CECB_RX_DATA08 0x28
0158 #define CECB_RX_DATA09 0x29
0159 #define CECB_RX_DATA10 0x2A
0160 #define CECB_RX_DATA11 0x2B
0161 #define CECB_RX_DATA12 0x2C
0162 #define CECB_RX_DATA13 0x2D
0163 #define CECB_RX_DATA14 0x2E
0164 #define CECB_RX_DATA15 0x2F
0165 #define CECB_LOCK_BUF 0x30
0166
0167 #define CECB_LOCK_BUF_EN BIT(0)
0168
0169 #define CECB_WAKEUPCTRL 0x31
0170
0171 struct meson_ao_cec_g12a_data {
0172
0173 bool ctrl2_setup;
0174 };
0175
0176 struct meson_ao_cec_g12a_device {
0177 struct platform_device *pdev;
0178 struct regmap *regmap;
0179 struct regmap *regmap_cec;
0180 spinlock_t cec_reg_lock;
0181 struct cec_notifier *notify;
0182 struct cec_adapter *adap;
0183 struct cec_msg rx_msg;
0184 struct clk *oscin;
0185 struct clk *core;
0186 const struct meson_ao_cec_g12a_data *data;
0187 };
0188
0189 static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
0190 .reg_bits = 8,
0191 .val_bits = 32,
0192 .reg_stride = 4,
0193 .max_register = CECB_INTR_STAT_REG,
0194 };
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 struct meson_ao_cec_g12a_dualdiv_clk {
0215 struct clk_hw hw;
0216 struct regmap *regmap;
0217 };
0218
0219 #define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \
0220 container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \
0221
0222 static unsigned long
0223 meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw,
0224 unsigned long parent_rate)
0225 {
0226 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
0227 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
0228 unsigned long n1;
0229 u32 reg0, reg1;
0230
0231 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0);
0232 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1);
0233
0234 if (reg1 & CECB_CLK_CNTL_BYPASS_EN)
0235 return parent_rate;
0236
0237 if (reg0 & CECB_CLK_CNTL_DUAL_EN) {
0238 unsigned long n2, m1, m2, f1, f2, p1, p2;
0239
0240 n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
0241 n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1;
0242
0243 m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
0244 m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
0245
0246 f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
0247 f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
0248
0249 p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
0250 p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
0251
0252 return DIV_ROUND_UP(100000000, p1 + p2);
0253 }
0254
0255 n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
0256
0257 return DIV_ROUND_CLOSEST(parent_rate, n1);
0258 }
0259
0260 static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw)
0261 {
0262 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
0263 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
0264
0265
0266
0267 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0268 CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
0269 0);
0270
0271
0272 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0273 CECB_CLK_CNTL_N1,
0274 FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1));
0275
0276 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0277 CECB_CLK_CNTL_N2,
0278 FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1));
0279
0280
0281 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
0282 CECB_CLK_CNTL_M1,
0283 FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1));
0284
0285 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
0286 CECB_CLK_CNTL_M2,
0287 FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1));
0288
0289
0290 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0291 CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN);
0292
0293
0294 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
0295 CECB_CLK_CNTL_BYPASS_EN, 0);
0296
0297
0298 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0299 CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
0300 CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN);
0301
0302 return 0;
0303 }
0304
0305 static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw)
0306 {
0307 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
0308 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
0309
0310 regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
0311 CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
0312 0);
0313 }
0314
0315 static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw)
0316 {
0317 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
0318 hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
0319 int val;
0320
0321 regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val);
0322
0323 return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN));
0324 }
0325
0326 static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = {
0327 .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate,
0328 .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled,
0329 .enable = meson_ao_cec_g12a_dualdiv_clk_enable,
0330 .disable = meson_ao_cec_g12a_dualdiv_clk_disable,
0331 };
0332
0333 static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec)
0334 {
0335 struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk;
0336 struct device *dev = &ao_cec->pdev->dev;
0337 struct clk_init_data init;
0338 const char *parent_name;
0339 struct clk *clk;
0340 char *name;
0341
0342 dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL);
0343 if (!dualdiv_clk)
0344 return -ENOMEM;
0345
0346 name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev));
0347 if (!name)
0348 return -ENOMEM;
0349
0350 parent_name = __clk_get_name(ao_cec->oscin);
0351
0352 init.name = name;
0353 init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops;
0354 init.flags = 0;
0355 init.parent_names = &parent_name;
0356 init.num_parents = 1;
0357 dualdiv_clk->regmap = ao_cec->regmap;
0358 dualdiv_clk->hw.init = &init;
0359
0360 clk = devm_clk_register(dev, &dualdiv_clk->hw);
0361 kfree(name);
0362 if (IS_ERR(clk)) {
0363 dev_err(dev, "failed to register clock\n");
0364 return PTR_ERR(clk);
0365 }
0366
0367 ao_cec->core = clk;
0368
0369 return 0;
0370 }
0371
0372 static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
0373 unsigned int *data)
0374 {
0375 struct meson_ao_cec_g12a_device *ao_cec = context;
0376 u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
0377 int ret = 0;
0378
0379 ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
0380 if (ret)
0381 return ret;
0382
0383 ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
0384 !(reg & CECB_RW_BUS_BUSY),
0385 5, 1000);
0386 if (ret)
0387 return ret;
0388
0389 ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®);
0390
0391 *data = FIELD_GET(CECB_RW_RD_DATA, reg);
0392
0393 return ret;
0394 }
0395
0396 static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
0397 unsigned int data)
0398 {
0399 struct meson_ao_cec_g12a_device *ao_cec = context;
0400 u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
0401 FIELD_PREP(CECB_RW_WR_DATA, data) |
0402 CECB_RW_WRITE_EN;
0403
0404 return regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
0405 }
0406
0407 static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
0408 .reg_bits = 8,
0409 .val_bits = 8,
0410 .reg_read = meson_ao_cec_g12a_read,
0411 .reg_write = meson_ao_cec_g12a_write,
0412 .max_register = 0xffff,
0413 };
0414
0415 static inline void
0416 meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec,
0417 bool enable)
0418 {
0419 u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK |
0420 CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR |
0421 CECB_INTR_FOLLOWER_ERR;
0422
0423 regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG,
0424 enable ? cfg : 0);
0425 }
0426
0427 static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec)
0428 {
0429 int i, ret = 0;
0430 u32 val;
0431
0432 ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val);
0433
0434 ao_cec->rx_msg.len = val;
0435 if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE)
0436 ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE;
0437
0438 for (i = 0; i < ao_cec->rx_msg.len; i++) {
0439 ret |= regmap_read(ao_cec->regmap_cec,
0440 CECB_RX_DATA00 + i, &val);
0441
0442 ao_cec->rx_msg.msg[i] = val & 0xff;
0443 }
0444
0445 ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
0446 if (ret)
0447 return;
0448
0449 cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
0450 }
0451
0452 static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data)
0453 {
0454 struct meson_ao_cec_g12a_device *ao_cec = data;
0455 u32 stat;
0456
0457 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
0458 if (stat)
0459 return IRQ_WAKE_THREAD;
0460
0461 return IRQ_NONE;
0462 }
0463
0464 static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data)
0465 {
0466 struct meson_ao_cec_g12a_device *ao_cec = data;
0467 u32 stat;
0468
0469 regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
0470 regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat);
0471
0472 if (stat & CECB_INTR_DONE)
0473 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK);
0474
0475 if (stat & CECB_INTR_EOM)
0476 meson_ao_cec_g12a_irq_rx(ao_cec);
0477
0478 if (stat & CECB_INTR_NACK)
0479 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK);
0480
0481 if (stat & CECB_INTR_ARB_LOSS) {
0482 regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0);
0483 regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
0484 CECB_CTRL_SEND | CECB_CTRL_TYPE, 0);
0485 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST);
0486 }
0487
0488
0489 if (stat & CECB_INTR_INITIATOR_ERR)
0490 cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR);
0491
0492
0493 if (stat & CECB_INTR_FOLLOWER_ERR)
0494 regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
0495
0496 return IRQ_HANDLED;
0497 }
0498
0499 static int
0500 meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
0501 {
0502 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
0503 int ret = 0;
0504
0505 if (logical_addr == CEC_LOG_ADDR_INVALID) {
0506
0507 regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0);
0508 regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0);
0509
0510 return 0;
0511 } else if (logical_addr < 8) {
0512 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW,
0513 BIT(logical_addr),
0514 BIT(logical_addr));
0515 } else {
0516 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
0517 BIT(logical_addr - 8),
0518 BIT(logical_addr - 8));
0519 }
0520
0521
0522 ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
0523 BIT(CEC_LOG_ADDR_UNREGISTERED - 8),
0524 BIT(CEC_LOG_ADDR_UNREGISTERED - 8));
0525
0526 return ret ? -EIO : 0;
0527 }
0528
0529 static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts,
0530 u32 signal_free_time, struct cec_msg *msg)
0531 {
0532 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
0533 unsigned int type;
0534 int ret = 0;
0535 u32 val;
0536 int i;
0537
0538
0539 ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val);
0540 if (ret)
0541 return ret;
0542 if (val & CECB_LOCK_BUF_EN)
0543 return -EBUSY;
0544
0545
0546 ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val);
0547 if (ret)
0548 return ret;
0549 if (val & CECB_CTRL_SEND)
0550 return -EBUSY;
0551
0552 switch (signal_free_time) {
0553 case CEC_SIGNAL_FREE_TIME_RETRY:
0554 type = CECB_CTRL_TYPE_RETRY;
0555 break;
0556 case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
0557 type = CECB_CTRL_TYPE_NEXT;
0558 break;
0559 case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
0560 default:
0561 type = CECB_CTRL_TYPE_NEW;
0562 break;
0563 }
0564
0565 for (i = 0; i < msg->len; i++)
0566 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i,
0567 msg->msg[i]);
0568
0569 ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len);
0570 if (ret)
0571 return -EIO;
0572
0573 ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
0574 CECB_CTRL_SEND |
0575 CECB_CTRL_TYPE,
0576 CECB_CTRL_SEND |
0577 FIELD_PREP(CECB_CTRL_TYPE, type));
0578
0579 return ret;
0580 }
0581
0582 static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
0583 {
0584 struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
0585
0586 meson_ao_cec_g12a_irq_setup(ao_cec, false);
0587
0588 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
0589 CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET);
0590
0591 if (!enable)
0592 return 0;
0593
0594
0595 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
0596 CECB_GEN_CNTL_FILTER_TICK_SEL |
0597 CECB_GEN_CNTL_FILTER_DEL,
0598 FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL,
0599 CECB_GEN_CNTL_FILTER_TICK_1US) |
0600 FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7));
0601
0602
0603 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
0604 CECB_GEN_CNTL_SYS_CLK_EN,
0605 CECB_GEN_CNTL_SYS_CLK_EN);
0606
0607
0608 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
0609 CECB_GEN_CNTL_CLK_CTRL_MASK,
0610 FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK,
0611 CECB_GEN_CNTL_CLK_ENABLE));
0612
0613
0614 regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
0615 CECB_GEN_CNTL_RESET, 0);
0616
0617 if (ao_cec->data->ctrl2_setup)
0618 regmap_write(ao_cec->regmap_cec, CECB_CTRL2,
0619 FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2));
0620
0621 meson_ao_cec_g12a_irq_setup(ao_cec, true);
0622
0623 return 0;
0624 }
0625
0626 static const struct cec_adap_ops meson_ao_cec_g12a_ops = {
0627 .adap_enable = meson_ao_cec_g12a_adap_enable,
0628 .adap_log_addr = meson_ao_cec_g12a_set_log_addr,
0629 .adap_transmit = meson_ao_cec_g12a_transmit,
0630 };
0631
0632 static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
0633 {
0634 struct meson_ao_cec_g12a_device *ao_cec;
0635 struct device *hdmi_dev;
0636 void __iomem *base;
0637 int ret, irq;
0638
0639 hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
0640 if (IS_ERR(hdmi_dev))
0641 return PTR_ERR(hdmi_dev);
0642
0643 ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
0644 if (!ao_cec)
0645 return -ENOMEM;
0646
0647 ao_cec->data = of_device_get_match_data(&pdev->dev);
0648 if (!ao_cec->data) {
0649 dev_err(&pdev->dev, "failed to get match data\n");
0650 return -ENODEV;
0651 }
0652
0653 spin_lock_init(&ao_cec->cec_reg_lock);
0654 ao_cec->pdev = pdev;
0655
0656 ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec,
0657 "meson_g12a_ao_cec",
0658 CEC_CAP_DEFAULTS |
0659 CEC_CAP_CONNECTOR_INFO,
0660 CEC_MAX_LOG_ADDRS);
0661 if (IS_ERR(ao_cec->adap))
0662 return PTR_ERR(ao_cec->adap);
0663
0664 ao_cec->adap->owner = THIS_MODULE;
0665
0666 base = devm_platform_ioremap_resource(pdev, 0);
0667 if (IS_ERR(base)) {
0668 ret = PTR_ERR(base);
0669 goto out_probe_adapter;
0670 }
0671
0672 ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
0673 &meson_ao_cec_g12a_regmap_conf);
0674 if (IS_ERR(ao_cec->regmap)) {
0675 ret = PTR_ERR(ao_cec->regmap);
0676 goto out_probe_adapter;
0677 }
0678
0679 ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec,
0680 &meson_ao_cec_g12a_cec_regmap_conf);
0681 if (IS_ERR(ao_cec->regmap_cec)) {
0682 ret = PTR_ERR(ao_cec->regmap_cec);
0683 goto out_probe_adapter;
0684 }
0685
0686 irq = platform_get_irq(pdev, 0);
0687 ret = devm_request_threaded_irq(&pdev->dev, irq,
0688 meson_ao_cec_g12a_irq,
0689 meson_ao_cec_g12a_irq_thread,
0690 0, NULL, ao_cec);
0691 if (ret) {
0692 dev_err(&pdev->dev, "irq request failed\n");
0693 goto out_probe_adapter;
0694 }
0695
0696 ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
0697 if (IS_ERR(ao_cec->oscin)) {
0698 dev_err(&pdev->dev, "oscin clock request failed\n");
0699 ret = PTR_ERR(ao_cec->oscin);
0700 goto out_probe_adapter;
0701 }
0702
0703 ret = meson_ao_cec_g12a_setup_clk(ao_cec);
0704 if (ret)
0705 goto out_probe_adapter;
0706
0707 ret = clk_prepare_enable(ao_cec->core);
0708 if (ret) {
0709 dev_err(&pdev->dev, "core clock enable failed\n");
0710 goto out_probe_adapter;
0711 }
0712
0713 device_reset_optional(&pdev->dev);
0714
0715 platform_set_drvdata(pdev, ao_cec);
0716
0717 ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
0718 ao_cec->adap);
0719 if (!ao_cec->notify) {
0720 ret = -ENOMEM;
0721 goto out_probe_core_clk;
0722 }
0723
0724 ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
0725 if (ret < 0)
0726 goto out_probe_notify;
0727
0728
0729 regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
0730
0731 return 0;
0732
0733 out_probe_notify:
0734 cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
0735
0736 out_probe_core_clk:
0737 clk_disable_unprepare(ao_cec->core);
0738
0739 out_probe_adapter:
0740 cec_delete_adapter(ao_cec->adap);
0741
0742 dev_err(&pdev->dev, "CEC controller registration failed\n");
0743
0744 return ret;
0745 }
0746
0747 static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
0748 {
0749 struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
0750
0751 clk_disable_unprepare(ao_cec->core);
0752
0753 cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
0754
0755 cec_unregister_adapter(ao_cec->adap);
0756
0757 return 0;
0758 }
0759
0760 static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = {
0761 .ctrl2_setup = false,
0762 };
0763
0764 static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = {
0765 .ctrl2_setup = true,
0766 };
0767
0768 static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
0769 {
0770 .compatible = "amlogic,meson-g12a-ao-cec",
0771 .data = &ao_cec_g12a_data,
0772 },
0773 {
0774 .compatible = "amlogic,meson-sm1-ao-cec",
0775 .data = &ao_cec_sm1_data,
0776 },
0777 { }
0778 };
0779 MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
0780
0781 static struct platform_driver meson_ao_cec_g12a_driver = {
0782 .probe = meson_ao_cec_g12a_probe,
0783 .remove = meson_ao_cec_g12a_remove,
0784 .driver = {
0785 .name = "meson-ao-cec-g12a",
0786 .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
0787 },
0788 };
0789
0790 module_platform_driver(meson_ao_cec_g12a_driver);
0791
0792 MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
0793 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0794 MODULE_LICENSE("GPL");