0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/module.h>
0010 #include <linux/of_device.h>
0011 #include <linux/slab.h>
0012 #include <linux/clk.h>
0013
0014 #include <media/cec.h>
0015
0016 #include "adv7511.h"
0017
0018 static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = {
0019 ADV7511_REG_CEC_RX1_FRAME_HDR,
0020 ADV7511_REG_CEC_RX2_FRAME_HDR,
0021 ADV7511_REG_CEC_RX3_FRAME_HDR,
0022 };
0023
0024 static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = {
0025 ADV7511_REG_CEC_RX1_FRAME_LEN,
0026 ADV7511_REG_CEC_RX2_FRAME_LEN,
0027 ADV7511_REG_CEC_RX3_FRAME_LEN,
0028 };
0029
0030 #define ADV7511_INT1_CEC_MASK \
0031 (ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
0032 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \
0033 ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3)
0034
0035 static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
0036 {
0037 unsigned int offset = adv7511->reg_cec_offset;
0038 unsigned int val;
0039
0040 if (regmap_read(adv7511->regmap_cec,
0041 ADV7511_REG_CEC_TX_ENABLE + offset, &val))
0042 return;
0043
0044 if ((val & 0x01) == 0)
0045 return;
0046
0047 if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
0048 cec_transmit_attempt_done(adv7511->cec_adap,
0049 CEC_TX_STATUS_ARB_LOST);
0050 return;
0051 }
0052 if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
0053 u8 status;
0054 u8 err_cnt = 0;
0055 u8 nack_cnt = 0;
0056 u8 low_drive_cnt = 0;
0057 unsigned int cnt;
0058
0059
0060
0061
0062
0063 status = CEC_TX_STATUS_MAX_RETRIES;
0064 if (regmap_read(adv7511->regmap_cec,
0065 ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {
0066 err_cnt = 1;
0067 status |= CEC_TX_STATUS_ERROR;
0068 } else {
0069 nack_cnt = cnt & 0xf;
0070 if (nack_cnt)
0071 status |= CEC_TX_STATUS_NACK;
0072 low_drive_cnt = cnt >> 4;
0073 if (low_drive_cnt)
0074 status |= CEC_TX_STATUS_LOW_DRIVE;
0075 }
0076 cec_transmit_done(adv7511->cec_adap, status,
0077 0, nack_cnt, low_drive_cnt, err_cnt);
0078 return;
0079 }
0080 if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
0081 cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
0082 return;
0083 }
0084 }
0085
0086 static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)
0087 {
0088 unsigned int offset = adv7511->reg_cec_offset;
0089 struct cec_msg msg = {};
0090 unsigned int len;
0091 unsigned int val;
0092 u8 i;
0093
0094 if (regmap_read(adv7511->regmap_cec,
0095 ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, &len))
0096 return;
0097
0098 msg.len = len & 0x1f;
0099
0100 if (msg.len > 16)
0101 msg.len = 16;
0102
0103 if (!msg.len)
0104 return;
0105
0106 for (i = 0; i < msg.len; i++) {
0107 regmap_read(adv7511->regmap_cec,
0108 i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset,
0109 &val);
0110 msg.msg[i] = val;
0111 }
0112
0113
0114 regmap_update_bits(adv7511->regmap_cec,
0115 ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf),
0116 BIT(rx_buf));
0117 regmap_update_bits(adv7511->regmap_cec,
0118 ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);
0119
0120 cec_received_msg(adv7511->cec_adap, &msg);
0121 }
0122
0123 void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
0124 {
0125 unsigned int offset = adv7511->reg_cec_offset;
0126 const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
0127 ADV7511_INT1_CEC_TX_ARBIT_LOST |
0128 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
0129 const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 |
0130 ADV7511_INT1_CEC_RX_READY2 |
0131 ADV7511_INT1_CEC_RX_READY3;
0132 unsigned int rx_status;
0133 int rx_order[3] = { -1, -1, -1 };
0134 int i;
0135
0136 if (irq1 & irq_tx_mask)
0137 adv_cec_tx_raw_status(adv7511, irq1);
0138
0139 if (!(irq1 & irq_rx_mask))
0140 return;
0141
0142 if (regmap_read(adv7511->regmap_cec,
0143 ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))
0144 return;
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 for (i = 0; i < 3; i++) {
0161 unsigned int timestamp = (rx_status >> (2 * i)) & 0x3;
0162
0163 if (timestamp)
0164 rx_order[timestamp - 1] = i;
0165 }
0166
0167
0168 for (i = 0; i < 3; i++) {
0169 int rx_buf = rx_order[i];
0170
0171 if (rx_buf < 0)
0172 break;
0173
0174 adv7511_cec_rx(adv7511, rx_buf);
0175 }
0176 }
0177
0178 static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
0179 {
0180 struct adv7511 *adv7511 = cec_get_drvdata(adap);
0181 unsigned int offset = adv7511->reg_cec_offset;
0182
0183 if (adv7511->i2c_cec == NULL)
0184 return -EIO;
0185
0186 if (!adv7511->cec_enabled_adap && enable) {
0187
0188 regmap_update_bits(adv7511->regmap_cec,
0189 ADV7511_REG_CEC_CLK_DIV + offset,
0190 0x03, 0x01);
0191
0192 regmap_write(adv7511->regmap_cec,
0193 ADV7511_REG_CEC_RX_BUFFERS + offset, 0x0f);
0194 regmap_write(adv7511->regmap_cec,
0195 ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
0196
0197 regmap_update_bits(adv7511->regmap_cec,
0198 ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
0199
0200
0201
0202
0203
0204 regmap_update_bits(adv7511->regmap,
0205 ADV7511_REG_INT_ENABLE(1), 0x3f,
0206 ADV7511_INT1_CEC_MASK);
0207 } else if (adv7511->cec_enabled_adap && !enable) {
0208 regmap_update_bits(adv7511->regmap,
0209 ADV7511_REG_INT_ENABLE(1), 0x3f, 0);
0210
0211 regmap_update_bits(adv7511->regmap_cec,
0212 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
0213 0x70, 0x00);
0214
0215 regmap_update_bits(adv7511->regmap_cec,
0216 ADV7511_REG_CEC_CLK_DIV + offset,
0217 0x03, 0x00);
0218 adv7511->cec_valid_addrs = 0;
0219 }
0220 adv7511->cec_enabled_adap = enable;
0221 return 0;
0222 }
0223
0224 static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
0225 {
0226 struct adv7511 *adv7511 = cec_get_drvdata(adap);
0227 unsigned int offset = adv7511->reg_cec_offset;
0228 unsigned int i, free_idx = ADV7511_MAX_ADDRS;
0229
0230 if (!adv7511->cec_enabled_adap)
0231 return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
0232
0233 if (addr == CEC_LOG_ADDR_INVALID) {
0234 regmap_update_bits(adv7511->regmap_cec,
0235 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
0236 0x70, 0);
0237 adv7511->cec_valid_addrs = 0;
0238 return 0;
0239 }
0240
0241 for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
0242 bool is_valid = adv7511->cec_valid_addrs & (1 << i);
0243
0244 if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
0245 free_idx = i;
0246 if (is_valid && adv7511->cec_addr[i] == addr)
0247 return 0;
0248 }
0249 if (i == ADV7511_MAX_ADDRS) {
0250 i = free_idx;
0251 if (i == ADV7511_MAX_ADDRS)
0252 return -ENXIO;
0253 }
0254 adv7511->cec_addr[i] = addr;
0255 adv7511->cec_valid_addrs |= 1 << i;
0256
0257 switch (i) {
0258 case 0:
0259
0260 regmap_update_bits(adv7511->regmap_cec,
0261 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
0262 0x10, 0x10);
0263
0264 regmap_update_bits(adv7511->regmap_cec,
0265 ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
0266 0x0f, addr);
0267 break;
0268 case 1:
0269
0270 regmap_update_bits(adv7511->regmap_cec,
0271 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
0272 0x20, 0x20);
0273
0274 regmap_update_bits(adv7511->regmap_cec,
0275 ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
0276 0xf0, addr << 4);
0277 break;
0278 case 2:
0279
0280 regmap_update_bits(adv7511->regmap_cec,
0281 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
0282 0x40, 0x40);
0283
0284 regmap_update_bits(adv7511->regmap_cec,
0285 ADV7511_REG_CEC_LOG_ADDR_2 + offset,
0286 0x0f, addr);
0287 break;
0288 }
0289 return 0;
0290 }
0291
0292 static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
0293 u32 signal_free_time, struct cec_msg *msg)
0294 {
0295 struct adv7511 *adv7511 = cec_get_drvdata(adap);
0296 unsigned int offset = adv7511->reg_cec_offset;
0297 u8 len = msg->len;
0298 unsigned int i;
0299
0300
0301
0302
0303
0304
0305 regmap_update_bits(adv7511->regmap_cec,
0306 ADV7511_REG_CEC_TX_RETRY + offset,
0307 0x70, max(1, attempts - 1) << 4);
0308
0309
0310 regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
0311
0312
0313 for (i = 0; i < len; i++)
0314 regmap_write(adv7511->regmap_cec,
0315 i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,
0316 msg->msg[i]);
0317
0318
0319 regmap_write(adv7511->regmap_cec,
0320 ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
0321
0322 regmap_write(adv7511->regmap_cec,
0323 ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
0324 return 0;
0325 }
0326
0327 static const struct cec_adap_ops adv7511_cec_adap_ops = {
0328 .adap_enable = adv7511_cec_adap_enable,
0329 .adap_log_addr = adv7511_cec_adap_log_addr,
0330 .adap_transmit = adv7511_cec_adap_transmit,
0331 };
0332
0333 static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
0334 {
0335 adv7511->cec_clk = devm_clk_get(dev, "cec");
0336 if (IS_ERR(adv7511->cec_clk)) {
0337 int ret = PTR_ERR(adv7511->cec_clk);
0338
0339 adv7511->cec_clk = NULL;
0340 return ret;
0341 }
0342 clk_prepare_enable(adv7511->cec_clk);
0343 adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
0344 return 0;
0345 }
0346
0347 int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
0348 {
0349 unsigned int offset = adv7511->reg_cec_offset;
0350 int ret = adv7511_cec_parse_dt(dev, adv7511);
0351
0352 if (ret)
0353 goto err_cec_parse_dt;
0354
0355 adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
0356 adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
0357 if (IS_ERR(adv7511->cec_adap)) {
0358 ret = PTR_ERR(adv7511->cec_adap);
0359 goto err_cec_alloc;
0360 }
0361
0362 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
0363
0364 regmap_write(adv7511->regmap_cec,
0365 ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
0366 regmap_write(adv7511->regmap_cec,
0367 ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
0368
0369
0370 regmap_write(adv7511->regmap_cec,
0371 ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
0372
0373 regmap_write(adv7511->regmap_cec,
0374 ADV7511_REG_CEC_CLK_DIV + offset,
0375 ((adv7511->cec_clk_freq / 750000) - 1) << 2);
0376
0377 ret = cec_register_adapter(adv7511->cec_adap, dev);
0378 if (ret)
0379 goto err_cec_register;
0380 return 0;
0381
0382 err_cec_register:
0383 cec_delete_adapter(adv7511->cec_adap);
0384 adv7511->cec_adap = NULL;
0385 err_cec_alloc:
0386 dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
0387 ret);
0388 err_cec_parse_dt:
0389 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
0390 ADV7511_CEC_CTRL_POWER_DOWN);
0391 return ret == -EPROBE_DEFER ? ret : 0;
0392 }