1 /*
2 * linux-5.4/drivers/media/platform/sunxi-vin/vin-cci/bsp_cci.c
3 *
4 * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17 #include "bsp_cci.h"
18 #include "../platform/platform_cfg.h"
19 #include <linux/delay.h>
20 #include <linux/sched.h>
21 #include <linux/mutex.h>
22 #include <linux/semaphore.h>
23
24 wait_queue_head_t wait[MAX_CSIC_CCI_NUM];
25 bool status_err_flag[MAX_CSIC_CCI_NUM] = { 0 };
26 bool register_flag[MAX_CSIC_CCI_NUM] = { 0 };
27 struct mutex cci_mutex[MAX_CSIC_CCI_NUM];
28 struct semaphore cci_sema[MAX_CSIC_CCI_NUM];
29
bsp_csi_cci_set_base_addr(unsigned int sel,unsigned long addr)30 int bsp_csi_cci_set_base_addr(unsigned int sel, unsigned long addr)
31 {
32 register_flag[sel] = 1;
33 init_waitqueue_head(&wait[sel]);
34 mutex_init(&cci_mutex[sel]);
35 sema_init(&cci_sema[sel], 1);
36 return csi_cci_set_base_addr(sel, addr);
37 }
38
cci_cal_div(unsigned int clk,unsigned char * div_coef)39 static void cci_cal_div(unsigned int clk, unsigned char *div_coef)
40 {
41 unsigned char clk_m = 0;
42 unsigned char clk_n = 0;
43 unsigned int src_clk = CCI_HCLK / 10;
44 unsigned int sclk_req = clk;
45 unsigned char _2_pow_clk_n = 1;
46 unsigned int sclk_real = 0;
47 unsigned int divider = src_clk / sclk_req;
48
49 if (divider == 0) {
50 clk_m = 1;
51 goto out;
52 }
53
54 while (clk_n < 8) {
55 clk_m = (divider / _2_pow_clk_n) - 1;
56 while (clk_m < 16) {
57 sclk_real = src_clk / (clk_m + 1) / _2_pow_clk_n;
58 if (sclk_real <= sclk_req)
59 goto out;
60 else
61 clk_m++;
62 }
63
64 clk_n++;
65 _2_pow_clk_n *= 2;
66 }
67
68 out:
69 div_coef[0] = clk_m;
70 div_coef[1] = clk_n;
71 }
72
bsp_csi_cci_init(unsigned int sel)73 void bsp_csi_cci_init(unsigned int sel)
74 {
75 unsigned char div_coef[2];
76
77 csi_cci_reset(sel);
78 csi_cci_enable(sel);
79 cci_cal_div(400 * 1000, div_coef);
80 csi_cci_set_clk_div(sel, div_coef);
81 csi_cci_set_pkt_interval(sel, 16);
82 csi_cci_set_ack_timeout(sel, 16);
83 csi_cci_set_trig_dly(sel, 0);
84 cci_pad_en(sel);
85 }
86
bsp_csi_cci_exit(unsigned int sel)87 void bsp_csi_cci_exit(unsigned int sel)
88 {
89 cci_int_disable(sel, CCI_INT_ALL);
90 csi_cci_reset(sel);
91 csi_cci_disable(sel);
92 }
93
bsp_cci_tx_start(unsigned int sel,struct cci_msg * msg)94 void bsp_cci_tx_start(unsigned int sel, struct cci_msg *msg)
95 {
96 unsigned int i, j, pkt_len, max_pkt_num, pkt_num;
97 unsigned char *buf;
98
99 csi_cci_set_bus_fmt(sel, &msg->bus_fmt);
100
101 buf = msg->pkt_buf;
102 pkt_num = msg->pkt_num;
103 pkt_len = msg->bus_fmt.addr_len + msg->bus_fmt.data_len;
104 if (pkt_len != 0)
105 max_pkt_num = FIFO_DEPTH / pkt_len;
106
107 while (pkt_num != 0) {
108 if (pkt_num < max_pkt_num || pkt_len == 0) {
109 j = pkt_num;
110 pkt_num = 0;
111 } else {
112 j = max_pkt_num;
113 pkt_num = pkt_num - max_pkt_num;
114 }
115
116 for (i = 0; i < j; i++) {
117 csi_cci_wr_tx_buf(sel, buf, pkt_len);
118 buf += pkt_len;
119 }
120 csi_cci_trans_start(sel, SINGLE);
121 }
122 }
123
bsp_cci_tx_data_rb(unsigned int sel,struct cci_msg * msg)124 void bsp_cci_tx_data_rb(unsigned int sel, struct cci_msg *msg)
125 {
126 unsigned int i, j, pkt_len, max_pkt_num, pkt_num;
127 unsigned char *buf;
128
129 csi_cci_set_bus_fmt(sel, &msg->bus_fmt);
130 buf = msg->pkt_buf;
131 pkt_num = msg->pkt_num;
132 pkt_len = msg->bus_fmt.addr_len + msg->bus_fmt.data_len;
133 max_pkt_num = FIFO_DEPTH / pkt_len;
134
135 while (pkt_num != 0) {
136 if (pkt_num < max_pkt_num) {
137 j = pkt_num;
138 pkt_num = 0;
139 } else {
140 j = max_pkt_num;
141 pkt_num = pkt_num - max_pkt_num;
142 }
143
144 for (i = 0; i < j; i++) {
145 csi_cci_fifo_pt_add(sel, msg->bus_fmt.addr_len);
146 csi_cci_rd_tx_buf(sel, buf + msg->bus_fmt.addr_len,
147 msg->bus_fmt.data_len);
148 buf += pkt_len;
149 }
150 }
151 csi_cci_fifo_pt_reset(sel);
152 }
bsp_cci_error_process(unsigned int sel)153 static void bsp_cci_error_process(unsigned int sel)
154 {
155 cci_int_clear_status(sel, CCI_INT_ERROR);
156 cci_stop(sel);
157 cci_sck_cycles(sel, 16);
158 bsp_csi_cci_exit(sel);
159 bsp_csi_cci_init_helper(sel);
160 }
bsp_cci_tx_start_wait_done_unlocked(unsigned int sel,struct cci_msg * msg)161 static int bsp_cci_tx_start_wait_done_unlocked(unsigned int sel,
162 struct cci_msg *msg)
163 {
164 int ret = 0;
165 unsigned long timeout = 0;
166
167 bsp_cci_tx_start(sel, msg);
168 #ifdef FPGA_VER
169 timeout = wait_event_timeout(wait[sel], csi_cci_get_trans_done(sel) == 0, HZ / 50);
170 #else
171 timeout = wait_event_timeout(wait[sel], csi_cci_get_trans_done(sel) == 0, HZ);
172 if (timeout == 0) {
173 pr_err("[VIN CCI_%d ERR] timeout error at addr_8bit = %x, wr_flag = %d, val = %x\n",
174 sel, msg->bus_fmt.saddr_7bit << 1, msg->bus_fmt.wr_flag, *(int *)msg->pkt_buf);
175 ret = -1;
176 }
177 #endif
178 if (status_err_flag[sel] == 1) {
179 pr_err("[VIN CCI_%d ERR] Status error at addr_8bit = %x, wr_flag = %d, val = %x\n",
180 sel, msg->bus_fmt.saddr_7bit << 1, msg->bus_fmt.wr_flag, *(int *)msg->pkt_buf);
181 ret = -1;
182 }
183 if (msg->bus_fmt.wr_flag == 1)
184 bsp_cci_tx_data_rb(sel, msg);
185 return ret;
186 }
187
bsp_cci_tx_start_wait_done(unsigned int sel,struct cci_msg * msg)188 int bsp_cci_tx_start_wait_done(unsigned int sel, struct cci_msg *msg)
189 {
190 int ret = -1;
191
192 if (!register_flag[sel])
193 return ret;
194
195 mutex_lock(&cci_mutex[sel]);
196 if (down_trylock(&cci_sema[sel])) {
197 pr_info("down_trylock fail!\n");
198 return -1;
199 }
200 ret = bsp_cci_tx_start_wait_done_unlocked(sel, msg);
201 up(&cci_sema[sel]);
202 mutex_unlock(&cci_mutex[sel]);
203 return ret;
204 }
205
bsp_cci_irq_process(unsigned int sel)206 int bsp_cci_irq_process(unsigned int sel)
207 {
208 struct cci_int_status status;
209 unsigned int ret = 0;
210
211 cci_int_get_status(sel, &status);
212 if (status.error) {
213 bsp_cci_error_process(sel);
214 status_err_flag[sel] = 1;
215 ret = -1;
216 }
217 if (status.complete) {
218 status_err_flag[sel] = 0;
219 cci_int_clear_status(sel, CCI_INT_FINISH);
220 }
221 wake_up(&wait[sel]);
222 return ret;
223 }
224
bsp_csi_cci_init_helper(unsigned int sel)225 void bsp_csi_cci_init_helper(unsigned int sel)
226 {
227 struct cci_tx_mode tx_mode;
228
229 bsp_csi_cci_init(sel);
230 tx_mode.tx_buf_mode.buf_src = FIFO;
231 tx_mode.tx_buf_mode.pkt_mode = COMPACT;
232 tx_mode.tx_buf_mode.pkt_cnt = 1;
233 tx_mode.tx_trig_mode.trig_src = NO_TRIG;
234 tx_mode.tx_trig_mode.trig_con = TRIG_DEFAULT;
235 tx_mode.tx_trig_line_cnt = 0;
236 csi_cci_set_tx_buf_mode(sel, &tx_mode.tx_buf_mode);
237 csi_cci_set_trig_mode(sel, &tx_mode.tx_trig_mode);
238 csi_cci_set_trig_line_cnt(sel, tx_mode.tx_trig_line_cnt);
239 cci_int_clear_status(sel, CCI_INT_ALL);
240 cci_int_enable(sel, CCI_INT_ALL);
241 }
242
cci_wr_8_8(unsigned int sel,unsigned char reg,unsigned char data,unsigned char slv)243 int cci_wr_8_8(unsigned int sel, unsigned char reg, unsigned char data,
244 unsigned char slv)
245 {
246 struct cci_msg msg;
247 unsigned char buf[2];
248
249 buf[0] = reg;
250 buf[1] = data;
251
252 msg.bus_fmt.saddr_7bit = slv;
253 msg.bus_fmt.wr_flag = 0;
254 msg.bus_fmt.rs_start = START_WITH_ID_W;
255 msg.bus_fmt.rs_mode = STOP_START;
256 msg.bus_fmt.addr_len = 1;
257 msg.bus_fmt.data_len = 1;
258 msg.pkt_buf = buf;
259 msg.pkt_num = 1;
260
261 return bsp_cci_tx_start_wait_done(sel, &msg);
262 }
263
cci_wr_16_8(unsigned int sel,unsigned short reg,unsigned char data,unsigned char slv)264 int cci_wr_16_8(unsigned int sel, unsigned short reg, unsigned char data,
265 unsigned char slv)
266 {
267 struct cci_msg msg;
268 unsigned char buf[3];
269
270 buf[0] = (reg & 0xff00) >> 8;
271 buf[1] = (reg & 0x00ff);
272 buf[2] = data;
273
274 msg.bus_fmt.saddr_7bit = slv;
275 msg.bus_fmt.wr_flag = 0;
276 msg.bus_fmt.rs_start = START_WITH_ID_W;
277 msg.bus_fmt.rs_mode = STOP_START;
278 msg.bus_fmt.addr_len = 2;
279 msg.bus_fmt.data_len = 1;
280 msg.pkt_buf = buf;
281 msg.pkt_num = 1;
282
283 return bsp_cci_tx_start_wait_done(sel, &msg);
284 }
285
cci_wr_16_16(unsigned int sel,unsigned short reg,unsigned short data,unsigned char slv)286 int cci_wr_16_16(unsigned int sel, unsigned short reg, unsigned short data,
287 unsigned char slv)
288 {
289 struct cci_msg msg;
290 unsigned char buf[4];
291
292 buf[0] = (reg & 0xff00) >> 8;
293 buf[1] = (reg & 0x00ff);
294 buf[2] = (data & 0xff00) >> 8;
295 buf[3] = (data & 0x00ff);
296
297 msg.bus_fmt.saddr_7bit = slv;
298 msg.bus_fmt.wr_flag = 0;
299 msg.bus_fmt.rs_start = START_WITH_ID_W;
300 msg.bus_fmt.rs_mode = STOP_START;
301 msg.bus_fmt.addr_len = 2;
302 msg.bus_fmt.data_len = 2;
303 msg.pkt_buf = buf;
304 msg.pkt_num = 1;
305
306 return bsp_cci_tx_start_wait_done(sel, &msg);
307 }
308
cci_wr_8_16(unsigned int sel,unsigned char reg,unsigned short data,unsigned char slv)309 int cci_wr_8_16(unsigned int sel, unsigned char reg, unsigned short data,
310 unsigned char slv)
311 {
312 struct cci_msg msg;
313 unsigned char buf[3];
314
315 buf[0] = reg;
316 buf[1] = (data & 0xff00) >> 8;
317 buf[2] = (data & 0x00ff);
318
319 msg.bus_fmt.saddr_7bit = slv;
320 msg.bus_fmt.wr_flag = 0;
321 msg.bus_fmt.rs_start = START_WITH_ID_W;
322 msg.bus_fmt.rs_mode = STOP_START;
323 msg.bus_fmt.addr_len = 1;
324 msg.bus_fmt.data_len = 2;
325 msg.pkt_buf = buf;
326 msg.pkt_num = 1;
327
328 return bsp_cci_tx_start_wait_done(sel, &msg);
329 }
330
cci_wr_0_16(unsigned int sel,unsigned short data,unsigned char slv)331 int cci_wr_0_16(unsigned int sel, unsigned short data, unsigned char slv)
332 {
333 struct cci_msg msg;
334 unsigned char buf[2];
335
336 buf[0] = (data & 0xff00) >> 8;
337 buf[1] = (data & 0x00ff);
338
339 msg.bus_fmt.saddr_7bit = slv;
340 msg.bus_fmt.wr_flag = 0;
341 msg.bus_fmt.rs_start = START_WITHOUT_ID_W;
342 msg.bus_fmt.rs_mode = STOP_START;
343 msg.bus_fmt.addr_len = 0;
344 msg.bus_fmt.data_len = 2;
345 msg.pkt_buf = buf;
346 msg.pkt_num = 1;
347
348 return bsp_cci_tx_start_wait_done(sel, &msg);
349 }
350
cci_rd_8_8(unsigned int sel,unsigned char reg,unsigned char * data,unsigned char slv)351 int cci_rd_8_8(unsigned int sel, unsigned char reg, unsigned char *data,
352 unsigned char slv)
353 {
354 struct cci_msg msg;
355 unsigned char buf[2];
356 int ret;
357
358 buf[0] = reg;
359
360 msg.bus_fmt.saddr_7bit = slv;
361 msg.bus_fmt.wr_flag = 1;
362 msg.bus_fmt.rs_start = START_WITH_ID_W;
363 msg.bus_fmt.rs_mode = STOP_START;
364 msg.bus_fmt.addr_len = 1;
365 msg.bus_fmt.data_len = 1;
366 msg.pkt_buf = buf;
367 msg.pkt_num = 1;
368
369 ret = bsp_cci_tx_start_wait_done(sel, &msg);
370 *data = buf[1];
371 return ret;
372 }
373
cci_rd_16_8(unsigned int sel,unsigned short reg,unsigned char * data,unsigned char slv)374 int cci_rd_16_8(unsigned int sel, unsigned short reg, unsigned char *data,
375 unsigned char slv)
376 {
377 struct cci_msg msg;
378 unsigned char buf[3];
379 int ret;
380
381 buf[0] = (reg & 0xff00) >> 8;
382 buf[1] = (reg & 0x00ff);
383
384 msg.bus_fmt.saddr_7bit = slv;
385 msg.bus_fmt.wr_flag = 1;
386 msg.bus_fmt.rs_start = START_WITH_ID_W;
387 msg.bus_fmt.rs_mode = STOP_START;
388 msg.bus_fmt.addr_len = 2;
389 msg.bus_fmt.data_len = 1;
390 msg.pkt_buf = buf;
391 msg.pkt_num = 1;
392
393 ret = bsp_cci_tx_start_wait_done(sel, &msg);
394 *data = buf[2];
395 return ret;
396 }
397
cci_rd_16_16(unsigned int sel,unsigned short reg,unsigned short * data,unsigned char slv)398 int cci_rd_16_16(unsigned int sel, unsigned short reg, unsigned short *data,
399 unsigned char slv)
400 {
401 struct cci_msg msg;
402 unsigned char buf[4];
403 int ret;
404
405 buf[0] = (reg & 0xff00) >> 8;
406 buf[1] = (reg & 0x00ff);
407
408 msg.bus_fmt.saddr_7bit = slv;
409 msg.bus_fmt.wr_flag = 1;
410 msg.bus_fmt.rs_start = START_WITH_ID_W;
411 msg.bus_fmt.rs_mode = STOP_START;
412 msg.bus_fmt.addr_len = 2;
413 msg.bus_fmt.data_len = 2;
414 msg.pkt_buf = buf;
415 msg.pkt_num = 1;
416
417 ret = bsp_cci_tx_start_wait_done(sel, &msg);
418 *data = buf[2] * 256 + buf[3];
419 return ret;
420 }
421
cci_rd_8_16(unsigned int sel,unsigned char reg,unsigned short * data,unsigned char slv)422 int cci_rd_8_16(unsigned int sel, unsigned char reg, unsigned short *data,
423 unsigned char slv)
424 {
425 struct cci_msg msg;
426 unsigned char buf[3];
427 int ret;
428
429 buf[0] = reg;
430
431 msg.bus_fmt.saddr_7bit = slv;
432 msg.bus_fmt.wr_flag = 1;
433 msg.bus_fmt.rs_start = START_WITH_ID_W;
434 msg.bus_fmt.rs_mode = STOP_START;
435 msg.bus_fmt.addr_len = 1;
436 msg.bus_fmt.data_len = 2;
437 msg.pkt_buf = buf;
438 msg.pkt_num = 1;
439
440 ret = bsp_cci_tx_start_wait_done(sel, &msg);
441 *data = buf[1] * 256 + buf[2];
442 return ret;
443 }
444
cci_rd_0_16(unsigned int sel,unsigned short * data,unsigned char slv)445 int cci_rd_0_16(unsigned int sel, unsigned short *data, unsigned char slv)
446 {
447 struct cci_msg msg;
448 unsigned char buf[2];
449 int ret;
450
451 msg.bus_fmt.saddr_7bit = slv;
452 msg.bus_fmt.wr_flag = 1;
453 msg.bus_fmt.rs_start = START_WITHOUT_ID_W;
454 msg.bus_fmt.rs_mode = STOP_START;
455 msg.bus_fmt.addr_len = 0;
456 msg.bus_fmt.data_len = 2;
457 msg.pkt_buf = buf;
458 msg.pkt_num = 1;
459
460 ret = bsp_cci_tx_start_wait_done(sel, &msg);
461 *data = buf[0] * 256 + buf[1];
462 return ret;
463 }
464
465 #define CCI_MAX_MSG_LEN 12
466
cci_wr_a16_d8_continuous(unsigned int sel,unsigned short reg,unsigned char * data,unsigned char slv,int size)467 int cci_wr_a16_d8_continuous(unsigned int sel, unsigned short reg,
468 unsigned char *data, unsigned char slv, int size)
469 {
470 struct cci_msg msg;
471 unsigned char buf[2 + CCI_MAX_MSG_LEN];
472 int ret = 0, i;
473
474 while (size > 0) {
475 int len = size > CCI_MAX_MSG_LEN ? CCI_MAX_MSG_LEN : size;
476
477 buf[0] = (reg & 0xff00) >> 8;
478 buf[1] = (reg & 0x00ff);
479 for (i = 2; i < 2 + len; i++)
480 buf[i] = *data++;
481
482 msg.bus_fmt.saddr_7bit = slv;
483 msg.bus_fmt.wr_flag = 0;
484 msg.bus_fmt.rs_start = START_WITH_ID_W;
485 msg.bus_fmt.rs_mode = STOP_START;
486 msg.bus_fmt.addr_len = 2;
487 msg.bus_fmt.data_len = len;
488 msg.pkt_buf = buf;
489 msg.pkt_num = 1;
490 ret = bsp_cci_tx_start_wait_done(sel, &msg);
491 if (ret >= 0) {
492 ret = 0;
493 } else if (ret < 0) {
494 pr_info("[CCI] sensor_write error!\n");
495 break;
496 }
497 reg += len;
498 size -= len;
499 }
500 return ret;
501 }
502
503