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