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/slab.h> |
11 | #include <linux/clk.h> |
12 | |
13 | #include <media/cec.h> |
14 | |
15 | #include "adv7511.h" |
16 | |
17 | static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = { |
18 | ADV7511_REG_CEC_RX1_FRAME_HDR, |
19 | ADV7511_REG_CEC_RX2_FRAME_HDR, |
20 | ADV7511_REG_CEC_RX3_FRAME_HDR, |
21 | }; |
22 | |
23 | static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = { |
24 | ADV7511_REG_CEC_RX1_FRAME_LEN, |
25 | ADV7511_REG_CEC_RX2_FRAME_LEN, |
26 | ADV7511_REG_CEC_RX3_FRAME_LEN, |
27 | }; |
28 | |
29 | #define ADV7511_INT1_CEC_MASK \ |
30 | (ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \ |
31 | ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \ |
32 | ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3) |
33 | |
34 | static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status) |
35 | { |
36 | unsigned int offset = adv7511->info->reg_cec_offset; |
37 | unsigned int val; |
38 | |
39 | if (regmap_read(map: adv7511->regmap_cec, |
40 | ADV7511_REG_CEC_TX_ENABLE + offset, val: &val)) |
41 | return; |
42 | |
43 | if ((val & 0x01) == 0) |
44 | return; |
45 | |
46 | if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) { |
47 | cec_transmit_attempt_done(adap: adv7511->cec_adap, |
48 | CEC_TX_STATUS_ARB_LOST); |
49 | return; |
50 | } |
51 | if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) { |
52 | u8 status; |
53 | u8 err_cnt = 0; |
54 | u8 nack_cnt = 0; |
55 | u8 low_drive_cnt = 0; |
56 | unsigned int cnt; |
57 | |
58 | /* |
59 | * We set this status bit since this hardware performs |
60 | * retransmissions. |
61 | */ |
62 | status = CEC_TX_STATUS_MAX_RETRIES; |
63 | if (regmap_read(map: adv7511->regmap_cec, |
64 | ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, val: &cnt)) { |
65 | err_cnt = 1; |
66 | status |= CEC_TX_STATUS_ERROR; |
67 | } else { |
68 | nack_cnt = cnt & 0xf; |
69 | if (nack_cnt) |
70 | status |= CEC_TX_STATUS_NACK; |
71 | low_drive_cnt = cnt >> 4; |
72 | if (low_drive_cnt) |
73 | status |= CEC_TX_STATUS_LOW_DRIVE; |
74 | } |
75 | cec_transmit_done(adap: adv7511->cec_adap, status, |
76 | arb_lost_cnt: 0, nack_cnt, low_drive_cnt, error_cnt: err_cnt); |
77 | return; |
78 | } |
79 | if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) { |
80 | cec_transmit_attempt_done(adap: adv7511->cec_adap, CEC_TX_STATUS_OK); |
81 | return; |
82 | } |
83 | } |
84 | |
85 | static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf) |
86 | { |
87 | unsigned int offset = adv7511->info->reg_cec_offset; |
88 | struct cec_msg msg = {}; |
89 | unsigned int len; |
90 | unsigned int val; |
91 | u8 i; |
92 | |
93 | if (regmap_read(map: adv7511->regmap_cec, |
94 | reg: ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, val: &len)) |
95 | return; |
96 | |
97 | msg.len = len & 0x1f; |
98 | |
99 | if (msg.len > 16) |
100 | msg.len = 16; |
101 | |
102 | if (!msg.len) |
103 | return; |
104 | |
105 | for (i = 0; i < msg.len; i++) { |
106 | regmap_read(map: adv7511->regmap_cec, |
107 | reg: i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset, |
108 | val: &val); |
109 | msg.msg[i] = val; |
110 | } |
111 | |
112 | /* Toggle RX Ready Clear bit to re-enable this RX buffer */ |
113 | regmap_update_bits(map: adv7511->regmap_cec, |
114 | ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), |
115 | BIT(rx_buf)); |
116 | regmap_update_bits(map: adv7511->regmap_cec, |
117 | ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), val: 0); |
118 | |
119 | cec_received_msg(adap: adv7511->cec_adap, msg: &msg); |
120 | } |
121 | |
122 | void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1) |
123 | { |
124 | unsigned int offset = adv7511->info->reg_cec_offset; |
125 | const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY | |
126 | ADV7511_INT1_CEC_TX_ARBIT_LOST | |
127 | ADV7511_INT1_CEC_TX_RETRY_TIMEOUT; |
128 | const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 | |
129 | ADV7511_INT1_CEC_RX_READY2 | |
130 | ADV7511_INT1_CEC_RX_READY3; |
131 | unsigned int rx_status; |
132 | int rx_order[3] = { -1, -1, -1 }; |
133 | int i; |
134 | |
135 | if (irq1 & irq_tx_mask) |
136 | adv_cec_tx_raw_status(adv7511, tx_raw_status: irq1); |
137 | |
138 | if (!(irq1 & irq_rx_mask)) |
139 | return; |
140 | |
141 | if (regmap_read(map: adv7511->regmap_cec, |
142 | ADV7511_REG_CEC_RX_STATUS + offset, val: &rx_status)) |
143 | return; |
144 | |
145 | /* |
146 | * ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX |
147 | * buffers 0, 1, and 2 in bits [1:0], [3:2], and [5:4] respectively. |
148 | * The values are to be interpreted as follows: |
149 | * |
150 | * 0 = buffer unused |
151 | * 1 = buffer contains oldest received frame (if applicable) |
152 | * 2 = buffer contains second oldest received frame (if applicable) |
153 | * 3 = buffer contains third oldest received frame (if applicable) |
154 | * |
155 | * Fill rx_order with the sequence of RX buffer indices to |
156 | * read from in order, where -1 indicates that there are no |
157 | * more buffers to process. |
158 | */ |
159 | for (i = 0; i < 3; i++) { |
160 | unsigned int timestamp = (rx_status >> (2 * i)) & 0x3; |
161 | |
162 | if (timestamp) |
163 | rx_order[timestamp - 1] = i; |
164 | } |
165 | |
166 | /* Read CEC RX buffers in the appropriate order as prescribed above */ |
167 | for (i = 0; i < 3; i++) { |
168 | int rx_buf = rx_order[i]; |
169 | |
170 | if (rx_buf < 0) |
171 | break; |
172 | |
173 | adv7511_cec_rx(adv7511, rx_buf); |
174 | } |
175 | } |
176 | |
177 | static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) |
178 | { |
179 | struct adv7511 *adv7511 = cec_get_drvdata(adap); |
180 | unsigned int offset = adv7511->info->reg_cec_offset; |
181 | |
182 | if (adv7511->i2c_cec == NULL) |
183 | return -EIO; |
184 | |
185 | if (!adv7511->cec_enabled_adap && enable) { |
186 | /* power up cec section */ |
187 | regmap_update_bits(map: adv7511->regmap_cec, |
188 | ADV7511_REG_CEC_CLK_DIV + offset, |
189 | mask: 0x03, val: 0x01); |
190 | /* non-legacy mode and clear all rx buffers */ |
191 | regmap_write(map: adv7511->regmap_cec, |
192 | ADV7511_REG_CEC_RX_BUFFERS + offset, val: 0x0f); |
193 | regmap_write(map: adv7511->regmap_cec, |
194 | ADV7511_REG_CEC_RX_BUFFERS + offset, val: 0x08); |
195 | /* initially disable tx */ |
196 | regmap_update_bits(map: adv7511->regmap_cec, |
197 | ADV7511_REG_CEC_TX_ENABLE + offset, mask: 1, val: 0); |
198 | /* enabled irqs: */ |
199 | /* tx: ready */ |
200 | /* tx: arbitration lost */ |
201 | /* tx: retry timeout */ |
202 | /* rx: ready 1-3 */ |
203 | regmap_update_bits(map: adv7511->regmap, |
204 | ADV7511_REG_INT_ENABLE(1), mask: 0x3f, |
205 | ADV7511_INT1_CEC_MASK); |
206 | } else if (adv7511->cec_enabled_adap && !enable) { |
207 | regmap_update_bits(map: adv7511->regmap, |
208 | ADV7511_REG_INT_ENABLE(1), mask: 0x3f, val: 0); |
209 | /* disable address mask 1-3 */ |
210 | regmap_update_bits(map: adv7511->regmap_cec, |
211 | ADV7511_REG_CEC_LOG_ADDR_MASK + offset, |
212 | mask: 0x70, val: 0x00); |
213 | /* power down cec section */ |
214 | regmap_update_bits(map: adv7511->regmap_cec, |
215 | ADV7511_REG_CEC_CLK_DIV + offset, |
216 | mask: 0x03, val: 0x00); |
217 | adv7511->cec_valid_addrs = 0; |
218 | } |
219 | adv7511->cec_enabled_adap = enable; |
220 | return 0; |
221 | } |
222 | |
223 | static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) |
224 | { |
225 | struct adv7511 *adv7511 = cec_get_drvdata(adap); |
226 | unsigned int offset = adv7511->info->reg_cec_offset; |
227 | unsigned int i, free_idx = ADV7511_MAX_ADDRS; |
228 | |
229 | if (!adv7511->cec_enabled_adap) |
230 | return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; |
231 | |
232 | if (addr == CEC_LOG_ADDR_INVALID) { |
233 | regmap_update_bits(map: adv7511->regmap_cec, |
234 | ADV7511_REG_CEC_LOG_ADDR_MASK + offset, |
235 | mask: 0x70, val: 0); |
236 | adv7511->cec_valid_addrs = 0; |
237 | return 0; |
238 | } |
239 | |
240 | for (i = 0; i < ADV7511_MAX_ADDRS; i++) { |
241 | bool is_valid = adv7511->cec_valid_addrs & (1 << i); |
242 | |
243 | if (free_idx == ADV7511_MAX_ADDRS && !is_valid) |
244 | free_idx = i; |
245 | if (is_valid && adv7511->cec_addr[i] == addr) |
246 | return 0; |
247 | } |
248 | if (i == ADV7511_MAX_ADDRS) { |
249 | i = free_idx; |
250 | if (i == ADV7511_MAX_ADDRS) |
251 | return -ENXIO; |
252 | } |
253 | adv7511->cec_addr[i] = addr; |
254 | adv7511->cec_valid_addrs |= 1 << i; |
255 | |
256 | switch (i) { |
257 | case 0: |
258 | /* enable address mask 0 */ |
259 | regmap_update_bits(map: adv7511->regmap_cec, |
260 | ADV7511_REG_CEC_LOG_ADDR_MASK + offset, |
261 | mask: 0x10, val: 0x10); |
262 | /* set address for mask 0 */ |
263 | regmap_update_bits(map: adv7511->regmap_cec, |
264 | ADV7511_REG_CEC_LOG_ADDR_0_1 + offset, |
265 | mask: 0x0f, val: addr); |
266 | break; |
267 | case 1: |
268 | /* enable address mask 1 */ |
269 | regmap_update_bits(map: adv7511->regmap_cec, |
270 | ADV7511_REG_CEC_LOG_ADDR_MASK + offset, |
271 | mask: 0x20, val: 0x20); |
272 | /* set address for mask 1 */ |
273 | regmap_update_bits(map: adv7511->regmap_cec, |
274 | ADV7511_REG_CEC_LOG_ADDR_0_1 + offset, |
275 | mask: 0xf0, val: addr << 4); |
276 | break; |
277 | case 2: |
278 | /* enable address mask 2 */ |
279 | regmap_update_bits(map: adv7511->regmap_cec, |
280 | ADV7511_REG_CEC_LOG_ADDR_MASK + offset, |
281 | mask: 0x40, val: 0x40); |
282 | /* set address for mask 1 */ |
283 | regmap_update_bits(map: adv7511->regmap_cec, |
284 | ADV7511_REG_CEC_LOG_ADDR_2 + offset, |
285 | mask: 0x0f, val: addr); |
286 | break; |
287 | } |
288 | return 0; |
289 | } |
290 | |
291 | static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
292 | u32 signal_free_time, struct cec_msg *msg) |
293 | { |
294 | struct adv7511 *adv7511 = cec_get_drvdata(adap); |
295 | unsigned int offset = adv7511->info->reg_cec_offset; |
296 | u8 len = msg->len; |
297 | unsigned int i; |
298 | |
299 | /* |
300 | * The number of retries is the number of attempts - 1, but retry |
301 | * at least once. It's not clear if a value of 0 is allowed, so |
302 | * let's do at least one retry. |
303 | */ |
304 | regmap_update_bits(map: adv7511->regmap_cec, |
305 | ADV7511_REG_CEC_TX_RETRY + offset, |
306 | mask: 0x70, max(1, attempts - 1) << 4); |
307 | |
308 | /* blocking, clear cec tx irq status */ |
309 | regmap_update_bits(map: adv7511->regmap, ADV7511_REG_INT(1), mask: 0x38, val: 0x38); |
310 | |
311 | /* write data */ |
312 | for (i = 0; i < len; i++) |
313 | regmap_write(map: adv7511->regmap_cec, |
314 | reg: i + ADV7511_REG_CEC_TX_FRAME_HDR + offset, |
315 | val: msg->msg[i]); |
316 | |
317 | /* set length (data + header) */ |
318 | regmap_write(map: adv7511->regmap_cec, |
319 | ADV7511_REG_CEC_TX_FRAME_LEN + offset, val: len); |
320 | /* start transmit, enable tx */ |
321 | regmap_write(map: adv7511->regmap_cec, |
322 | ADV7511_REG_CEC_TX_ENABLE + offset, val: 0x01); |
323 | return 0; |
324 | } |
325 | |
326 | static const struct cec_adap_ops adv7511_cec_adap_ops = { |
327 | .adap_enable = adv7511_cec_adap_enable, |
328 | .adap_log_addr = adv7511_cec_adap_log_addr, |
329 | .adap_transmit = adv7511_cec_adap_transmit, |
330 | }; |
331 | |
332 | static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511) |
333 | { |
334 | adv7511->cec_clk = devm_clk_get(dev, id: "cec" ); |
335 | if (IS_ERR(ptr: adv7511->cec_clk)) { |
336 | int ret = PTR_ERR(ptr: adv7511->cec_clk); |
337 | |
338 | adv7511->cec_clk = NULL; |
339 | return ret; |
340 | } |
341 | clk_prepare_enable(clk: adv7511->cec_clk); |
342 | adv7511->cec_clk_freq = clk_get_rate(clk: adv7511->cec_clk); |
343 | return 0; |
344 | } |
345 | |
346 | int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) |
347 | { |
348 | unsigned int offset = adv7511->info->reg_cec_offset; |
349 | int ret = adv7511_cec_parse_dt(dev, adv7511); |
350 | |
351 | if (ret) |
352 | goto err_cec_parse_dt; |
353 | |
354 | adv7511->cec_adap = cec_allocate_adapter(ops: &adv7511_cec_adap_ops, |
355 | priv: adv7511, name: dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS); |
356 | if (IS_ERR(ptr: adv7511->cec_adap)) { |
357 | ret = PTR_ERR(ptr: adv7511->cec_adap); |
358 | goto err_cec_alloc; |
359 | } |
360 | |
361 | regmap_write(map: adv7511->regmap, ADV7511_REG_CEC_CTRL, val: 0); |
362 | /* cec soft reset */ |
363 | regmap_write(map: adv7511->regmap_cec, |
364 | ADV7511_REG_CEC_SOFT_RESET + offset, val: 0x01); |
365 | regmap_write(map: adv7511->regmap_cec, |
366 | ADV7511_REG_CEC_SOFT_RESET + offset, val: 0x00); |
367 | |
368 | /* non-legacy mode - use all three RX buffers */ |
369 | regmap_write(map: adv7511->regmap_cec, |
370 | ADV7511_REG_CEC_RX_BUFFERS + offset, val: 0x08); |
371 | |
372 | regmap_write(map: adv7511->regmap_cec, |
373 | ADV7511_REG_CEC_CLK_DIV + offset, |
374 | val: ((adv7511->cec_clk_freq / 750000) - 1) << 2); |
375 | |
376 | ret = cec_register_adapter(adap: adv7511->cec_adap, parent: dev); |
377 | if (ret) |
378 | goto err_cec_register; |
379 | return 0; |
380 | |
381 | err_cec_register: |
382 | cec_delete_adapter(adap: adv7511->cec_adap); |
383 | adv7511->cec_adap = NULL; |
384 | err_cec_alloc: |
385 | dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n" , |
386 | ret); |
387 | err_cec_parse_dt: |
388 | regmap_write(map: adv7511->regmap, ADV7511_REG_CEC_CTRL, |
389 | ADV7511_CEC_CTRL_POWER_DOWN); |
390 | return ret == -EPROBE_DEFER ? ret : 0; |
391 | } |
392 | |