1
2
3
4
5
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
22static 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
49
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
74void 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
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
118static 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
129 regmap_update_bits(adv7511->regmap_cec,
130 ADV7511_REG_CEC_CLK_DIV + offset,
131 0x03, 0x01);
132
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
138 regmap_update_bits(adv7511->regmap_cec,
139 ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
140
141
142
143
144
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
152 regmap_update_bits(adv7511->regmap_cec,
153 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
154 0x70, 0x00);
155
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
165static 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
202 regmap_update_bits(adv7511->regmap_cec,
203 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
204 0x10, 0x10);
205
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
212 regmap_update_bits(adv7511->regmap_cec,
213 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
214 0x20, 0x20);
215
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
222 regmap_update_bits(adv7511->regmap_cec,
223 ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
224 0x40, 0x40);
225
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
234static 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
245
246
247
248 regmap_update_bits(adv7511->regmap_cec,
249 ADV7511_REG_CEC_TX_RETRY + offset,
250 0x70, max(1, attempts - 1) << 4);
251
252
253 regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
254
255
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
262 regmap_write(adv7511->regmap_cec,
263 ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
264
265 regmap_write(adv7511->regmap_cec,
266 ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
267 return 0;
268}
269
270static 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
276static 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
290int 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
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
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
326err_cec_register:
327 cec_delete_adapter(adv7511->cec_adap);
328 adv7511->cec_adap = NULL;
329err_cec_alloc:
330 dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
331 ret);
332err_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