1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * adv7511_cec.c - Analog Devices ADV7511/33 cec driver
4 *
5 * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 */
7
8 #include <linux/device.h>
9 #include <linux/module.h>
10 #include <linux/of_device.h>
11 #include <linux/slab.h>
12 #include <linux/clk.h>
13
14 #include <media/cec.h>
15
16 #include "adv7511.h"
17
18 #define ADV7511_INT1_CEC_MASK \
19 (ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
20 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1)
21
adv_cec_tx_raw_status(struct adv7511 * adv7511,u8 tx_raw_status)22 static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
23 {
24 unsigned int offset = adv7511->type == ADV7533 ?
25 ADV7533_REG_CEC_OFFSET : 0;
26 unsigned int val;
27
28 if (regmap_read(adv7511->regmap_cec,
29 ADV7511_REG_CEC_TX_ENABLE + offset, &val))
30 return;
31
32 if ((val & 0x01) == 0)
33 return;
34
35 if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
36 cec_transmit_attempt_done(adv7511->cec_adap,
37 CEC_TX_STATUS_ARB_LOST);
38 return;
39 }
40 if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
41 u8 status;
42 u8 err_cnt = 0;
43 u8 nack_cnt = 0;
44 u8 low_drive_cnt = 0;
45 unsigned int cnt;
46
47 /*
48 * We set this status bit since this hardware performs
49 * retransmissions.
50 */
51 status = CEC_TX_STATUS_MAX_RETRIES;
52 if (regmap_read(adv7511->regmap_cec,
53 ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {
54 err_cnt = 1;
55 status |= CEC_TX_STATUS_ERROR;
56 } else {
57 nack_cnt = cnt & 0xf;
58 if (nack_cnt)
59 status |= CEC_TX_STATUS_NACK;
60 low_drive_cnt = cnt >> 4;
61 if (low_drive_cnt)
62 status |= CEC_TX_STATUS_LOW_DRIVE;
63 }
64 cec_transmit_done(adv7511->cec_adap, status,
65 0, nack_cnt, low_drive_cnt, err_cnt);
66 return;
67 }
68 if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
69 cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
70 return;
71 }
72 }
73
adv7511_cec_irq_process(struct adv7511 * adv7511,unsigned int irq1)74 void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
75 {
76 unsigned int offset = adv7511->type == ADV7533 ?
77 ADV7533_REG_CEC_OFFSET : 0;
78 const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
79 ADV7511_INT1_CEC_TX_ARBIT_LOST |
80 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
81 struct cec_msg msg = {};
82 unsigned int len;
83 unsigned int val;
84 u8 i;
85
86 if (irq1 & irq_tx_mask)
87 adv_cec_tx_raw_status(adv7511, irq1);
88
89 if (!(irq1 & ADV7511_INT1_CEC_RX_READY1))
90 return;
91
92 if (regmap_read(adv7511->regmap_cec,
93 ADV7511_REG_CEC_RX_FRAME_LEN + offset, &len))
94 return;
95
96 msg.len = len & 0x1f;
97
98 if (msg.len > 16)
99 msg.len = 16;
100
101 if (!msg.len)
102 return;
103
104 for (i = 0; i < msg.len; i++) {
105 regmap_read(adv7511->regmap_cec,
106 i + ADV7511_REG_CEC_RX_FRAME_HDR + offset, &val);
107 msg.msg[i] = val;
108 }
109
110 /* toggle to re-enable rx 1 */
111 regmap_write(adv7511->regmap_cec,
112 ADV7511_REG_CEC_RX_BUFFERS + offset, 1);
113 regmap_write(adv7511->regmap_cec,
114 ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
115 cec_received_msg(adv7511->cec_adap, &msg);
116 }
117
adv7511_cec_adap_enable(struct cec_adapter * adap,bool enable)118 static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
119 {
120 struct adv7511 *adv7511 = cec_get_drvdata(adap);
121 unsigned int offset = adv7511->type == ADV7533 ?
122 ADV7533_REG_CEC_OFFSET : 0;
123
124 if (adv7511->i2c_cec == NULL)
125 return -EIO;
126
127 if (!adv7511->cec_enabled_adap && enable) {
128 /* power up cec section */
129 regmap_update_bits(adv7511->regmap_cec,
130 ADV7511_REG_CEC_CLK_DIV + offset,
131 0x03, 0x01);
132 /* legacy mode and clear all rx buffers */
133 regmap_write(adv7511->regmap_cec,
134 ADV7511_REG_CEC_RX_BUFFERS + offset, 0x07);
135 regmap_write(adv7511->regmap_cec,
136 ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
137 /* initially disable tx */
138 regmap_update_bits(adv7511->regmap_cec,
139 ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
140 /* enabled irqs: */
141 /* tx: ready */
142 /* tx: arbitration lost */
143 /* tx: retry timeout */
144 /* rx: ready 1 */
145 regmap_update_bits(adv7511->regmap,
146 ADV7511_REG_INT_ENABLE(1), 0x3f,
147 ADV7511_INT1_CEC_MASK);
148 } else if (adv7511->cec_enabled_adap && !enable) {
149 regmap_update_bits(adv7511->regmap,
150 ADV7511_REG_INT_ENABLE(1), 0x3f, 0);
151 /* disable address mask 1-3 */
152 regmap_update_bits(adv7511->regmap_cec,
153 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
154 0x70, 0x00);
155 /* power down cec section */
156 regmap_update_bits(adv7511->regmap_cec,
157 ADV7511_REG_CEC_CLK_DIV + offset,
158 0x03, 0x00);
159 adv7511->cec_valid_addrs = 0;
160 }
161 adv7511->cec_enabled_adap = enable;
162 return 0;
163 }
164
adv7511_cec_adap_log_addr(struct cec_adapter * adap,u8 addr)165 static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
166 {
167 struct adv7511 *adv7511 = cec_get_drvdata(adap);
168 unsigned int offset = adv7511->type == ADV7533 ?
169 ADV7533_REG_CEC_OFFSET : 0;
170 unsigned int i, free_idx = ADV7511_MAX_ADDRS;
171
172 if (!adv7511->cec_enabled_adap)
173 return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
174
175 if (addr == CEC_LOG_ADDR_INVALID) {
176 regmap_update_bits(adv7511->regmap_cec,
177 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
178 0x70, 0);
179 adv7511->cec_valid_addrs = 0;
180 return 0;
181 }
182
183 for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
184 bool is_valid = adv7511->cec_valid_addrs & (1 << i);
185
186 if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
187 free_idx = i;
188 if (is_valid && adv7511->cec_addr[i] == addr)
189 return 0;
190 }
191 if (i == ADV7511_MAX_ADDRS) {
192 i = free_idx;
193 if (i == ADV7511_MAX_ADDRS)
194 return -ENXIO;
195 }
196 adv7511->cec_addr[i] = addr;
197 adv7511->cec_valid_addrs |= 1 << i;
198
199 switch (i) {
200 case 0:
201 /* enable address mask 0 */
202 regmap_update_bits(adv7511->regmap_cec,
203 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
204 0x10, 0x10);
205 /* set address for mask 0 */
206 regmap_update_bits(adv7511->regmap_cec,
207 ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
208 0x0f, addr);
209 break;
210 case 1:
211 /* enable address mask 1 */
212 regmap_update_bits(adv7511->regmap_cec,
213 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
214 0x20, 0x20);
215 /* set address for mask 1 */
216 regmap_update_bits(adv7511->regmap_cec,
217 ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
218 0xf0, addr << 4);
219 break;
220 case 2:
221 /* enable address mask 2 */
222 regmap_update_bits(adv7511->regmap_cec,
223 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
224 0x40, 0x40);
225 /* set address for mask 1 */
226 regmap_update_bits(adv7511->regmap_cec,
227 ADV7511_REG_CEC_LOG_ADDR_2 + offset,
228 0x0f, addr);
229 break;
230 }
231 return 0;
232 }
233
adv7511_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)234 static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
235 u32 signal_free_time, struct cec_msg *msg)
236 {
237 struct adv7511 *adv7511 = cec_get_drvdata(adap);
238 unsigned int offset = adv7511->type == ADV7533 ?
239 ADV7533_REG_CEC_OFFSET : 0;
240 u8 len = msg->len;
241 unsigned int i;
242
243 /*
244 * The number of retries is the number of attempts - 1, but retry
245 * at least once. It's not clear if a value of 0 is allowed, so
246 * let's do at least one retry.
247 */
248 regmap_update_bits(adv7511->regmap_cec,
249 ADV7511_REG_CEC_TX_RETRY + offset,
250 0x70, max(1, attempts - 1) << 4);
251
252 /* blocking, clear cec tx irq status */
253 regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
254
255 /* write data */
256 for (i = 0; i < len; i++)
257 regmap_write(adv7511->regmap_cec,
258 i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,
259 msg->msg[i]);
260
261 /* set length (data + header) */
262 regmap_write(adv7511->regmap_cec,
263 ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
264 /* start transmit, enable tx */
265 regmap_write(adv7511->regmap_cec,
266 ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
267 return 0;
268 }
269
270 static const struct cec_adap_ops adv7511_cec_adap_ops = {
271 .adap_enable = adv7511_cec_adap_enable,
272 .adap_log_addr = adv7511_cec_adap_log_addr,
273 .adap_transmit = adv7511_cec_adap_transmit,
274 };
275
adv7511_cec_parse_dt(struct device * dev,struct adv7511 * adv7511)276 static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
277 {
278 adv7511->cec_clk = devm_clk_get(dev, "cec");
279 if (IS_ERR(adv7511->cec_clk)) {
280 int ret = PTR_ERR(adv7511->cec_clk);
281
282 adv7511->cec_clk = NULL;
283 return ret;
284 }
285 clk_prepare_enable(adv7511->cec_clk);
286 adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
287 return 0;
288 }
289
adv7511_cec_init(struct device * dev,struct adv7511 * adv7511)290 int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
291 {
292 unsigned int offset = adv7511->type == ADV7533 ?
293 ADV7533_REG_CEC_OFFSET : 0;
294 int ret = adv7511_cec_parse_dt(dev, adv7511);
295
296 if (ret)
297 goto err_cec_parse_dt;
298
299 adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
300 adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
301 if (IS_ERR(adv7511->cec_adap)) {
302 ret = PTR_ERR(adv7511->cec_adap);
303 goto err_cec_alloc;
304 }
305
306 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
307 /* cec soft reset */
308 regmap_write(adv7511->regmap_cec,
309 ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
310 regmap_write(adv7511->regmap_cec,
311 ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
312
313 /* legacy mode */
314 regmap_write(adv7511->regmap_cec,
315 ADV7511_REG_CEC_RX_BUFFERS + offset, 0x00);
316
317 regmap_write(adv7511->regmap_cec,
318 ADV7511_REG_CEC_CLK_DIV + offset,
319 ((adv7511->cec_clk_freq / 750000) - 1) << 2);
320
321 ret = cec_register_adapter(adv7511->cec_adap, dev);
322 if (ret)
323 goto err_cec_register;
324 return 0;
325
326 err_cec_register:
327 cec_delete_adapter(adv7511->cec_adap);
328 adv7511->cec_adap = NULL;
329 err_cec_alloc:
330 dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
331 ret);
332 err_cec_parse_dt:
333 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
334 ADV7511_CEC_CTRL_POWER_DOWN);
335 return ret == -EPROBE_DEFER ? ret : 0;
336 }
337