• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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