xref: /OK3568_Linux_fs/kernel/drivers/media/pci/cx23885/altera-ci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * altera-ci.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  CI driver in conjunction with NetUp Dual DVB-T/C RF CI card
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2010,2011 NetUP Inc.
8*4882a593Smuzhiyun  * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun  * currently cx23885 GPIO's used.
13*4882a593Smuzhiyun  * GPIO-0 ~INT in
14*4882a593Smuzhiyun  * GPIO-1 TMS out
15*4882a593Smuzhiyun  * GPIO-2 ~reset chips out
16*4882a593Smuzhiyun  * GPIO-3 to GPIO-10 data/addr for CA in/out
17*4882a593Smuzhiyun  * GPIO-11 ~CS out
18*4882a593Smuzhiyun  * GPIO-12 AD_RG out
19*4882a593Smuzhiyun  * GPIO-13 ~WR out
20*4882a593Smuzhiyun  * GPIO-14 ~RD out
21*4882a593Smuzhiyun  * GPIO-15 ~RDY in
22*4882a593Smuzhiyun  * GPIO-16 TCK out
23*4882a593Smuzhiyun  * GPIO-17 TDO in
24*4882a593Smuzhiyun  * GPIO-18 TDI out
25*4882a593Smuzhiyun  */
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  *  Bit definitions for MC417_RWD and MC417_OEN registers
28*4882a593Smuzhiyun  * bits 31-16
29*4882a593Smuzhiyun  * +-----------+
30*4882a593Smuzhiyun  * | Reserved  |
31*4882a593Smuzhiyun  * +-----------+
32*4882a593Smuzhiyun  *   bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
33*4882a593Smuzhiyun  * +-------+-------+-------+-------+-------+-------+-------+-------+
34*4882a593Smuzhiyun  * |  TDI  |  TDO  |  TCK  |  RDY# |  #RD  |  #WR  | AD_RG |  #CS  |
35*4882a593Smuzhiyun  * +-------+-------+-------+-------+-------+-------+-------+-------+
36*4882a593Smuzhiyun  *  bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
37*4882a593Smuzhiyun  * +-------+-------+-------+-------+-------+-------+-------+-------+
38*4882a593Smuzhiyun  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
39*4882a593Smuzhiyun  * +-------+-------+-------+-------+-------+-------+-------+-------+
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <media/dvb_demux.h>
45*4882a593Smuzhiyun #include <media/dvb_frontend.h>
46*4882a593Smuzhiyun #include "altera-ci.h"
47*4882a593Smuzhiyun #include <media/dvb_ca_en50221.h>
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /* FPGA regs */
50*4882a593Smuzhiyun #define NETUP_CI_INT_CTRL	0x00
51*4882a593Smuzhiyun #define NETUP_CI_BUSCTRL2	0x01
52*4882a593Smuzhiyun #define NETUP_CI_ADDR0		0x04
53*4882a593Smuzhiyun #define NETUP_CI_ADDR1		0x05
54*4882a593Smuzhiyun #define NETUP_CI_DATA		0x06
55*4882a593Smuzhiyun #define NETUP_CI_BUSCTRL	0x07
56*4882a593Smuzhiyun #define NETUP_CI_PID_ADDR0	0x08
57*4882a593Smuzhiyun #define NETUP_CI_PID_ADDR1	0x09
58*4882a593Smuzhiyun #define NETUP_CI_PID_DATA	0x0a
59*4882a593Smuzhiyun #define NETUP_CI_TSA_DIV	0x0c
60*4882a593Smuzhiyun #define NETUP_CI_TSB_DIV	0x0d
61*4882a593Smuzhiyun #define NETUP_CI_REVISION	0x0f
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /* const for ci op */
64*4882a593Smuzhiyun #define NETUP_CI_FLG_CTL	1
65*4882a593Smuzhiyun #define NETUP_CI_FLG_RD		1
66*4882a593Smuzhiyun #define NETUP_CI_FLG_AD		1
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun static unsigned int ci_dbg;
69*4882a593Smuzhiyun module_param(ci_dbg, int, 0644);
70*4882a593Smuzhiyun MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun static unsigned int pid_dbg;
73*4882a593Smuzhiyun module_param(pid_dbg, int, 0644);
74*4882a593Smuzhiyun MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging");
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun MODULE_DESCRIPTION("altera FPGA CI module");
77*4882a593Smuzhiyun MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
78*4882a593Smuzhiyun MODULE_LICENSE("GPL");
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #define ci_dbg_print(fmt, args...) \
81*4882a593Smuzhiyun 	do { \
82*4882a593Smuzhiyun 		if (ci_dbg) \
83*4882a593Smuzhiyun 			printk(KERN_DEBUG pr_fmt("%s: " fmt), \
84*4882a593Smuzhiyun 			       __func__, ##args); \
85*4882a593Smuzhiyun 	} while (0)
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define pid_dbg_print(fmt, args...) \
88*4882a593Smuzhiyun 	do { \
89*4882a593Smuzhiyun 		if (pid_dbg) \
90*4882a593Smuzhiyun 			printk(KERN_DEBUG pr_fmt("%s: " fmt), \
91*4882a593Smuzhiyun 			       __func__, ##args); \
92*4882a593Smuzhiyun 	} while (0)
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun struct altera_ci_state;
95*4882a593Smuzhiyun struct netup_hw_pid_filter;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun struct fpga_internal {
98*4882a593Smuzhiyun 	void *dev;
99*4882a593Smuzhiyun 	struct mutex fpga_mutex;/* two CI's on the same fpga */
100*4882a593Smuzhiyun 	struct netup_hw_pid_filter *pid_filt[2];
101*4882a593Smuzhiyun 	struct altera_ci_state *state[2];
102*4882a593Smuzhiyun 	struct work_struct work;
103*4882a593Smuzhiyun 	int (*fpga_rw) (void *dev, int flag, int data, int rw);
104*4882a593Smuzhiyun 	int cis_used;
105*4882a593Smuzhiyun 	int filts_used;
106*4882a593Smuzhiyun 	int strt_wrk;
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /* stores all private variables for communication with CI */
110*4882a593Smuzhiyun struct altera_ci_state {
111*4882a593Smuzhiyun 	struct fpga_internal *internal;
112*4882a593Smuzhiyun 	struct dvb_ca_en50221 ca;
113*4882a593Smuzhiyun 	int status;
114*4882a593Smuzhiyun 	int nr;
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /* stores all private variables for hardware pid filtering */
118*4882a593Smuzhiyun struct netup_hw_pid_filter {
119*4882a593Smuzhiyun 	struct fpga_internal *internal;
120*4882a593Smuzhiyun 	struct dvb_demux *demux;
121*4882a593Smuzhiyun 	/* save old functions */
122*4882a593Smuzhiyun 	int (*start_feed)(struct dvb_demux_feed *feed);
123*4882a593Smuzhiyun 	int (*stop_feed)(struct dvb_demux_feed *feed);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	int status;
126*4882a593Smuzhiyun 	int nr;
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* internal params node */
130*4882a593Smuzhiyun struct fpga_inode {
131*4882a593Smuzhiyun 	/* pointer for internal params, one for each pair of CI's */
132*4882a593Smuzhiyun 	struct fpga_internal		*internal;
133*4882a593Smuzhiyun 	struct fpga_inode		*next_inode;
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /* first internal params */
137*4882a593Smuzhiyun static struct fpga_inode *fpga_first_inode;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* find chip by dev */
find_inode(void * dev)140*4882a593Smuzhiyun static struct fpga_inode *find_inode(void *dev)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	struct fpga_inode *temp_chip = fpga_first_inode;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (temp_chip == NULL)
145*4882a593Smuzhiyun 		return temp_chip;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/*
148*4882a593Smuzhiyun 	 Search for the last fpga CI chip or
149*4882a593Smuzhiyun 	 find it by dev */
150*4882a593Smuzhiyun 	while ((temp_chip != NULL) &&
151*4882a593Smuzhiyun 				(temp_chip->internal->dev != dev))
152*4882a593Smuzhiyun 		temp_chip = temp_chip->next_inode;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	return temp_chip;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun /* check demux */
check_filter(struct fpga_internal * temp_int,void * demux_dev,int filt_nr)157*4882a593Smuzhiyun static struct fpga_internal *check_filter(struct fpga_internal *temp_int,
158*4882a593Smuzhiyun 						void *demux_dev, int filt_nr)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	if (temp_int == NULL)
161*4882a593Smuzhiyun 		return NULL;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if ((temp_int->pid_filt[filt_nr]) == NULL)
164*4882a593Smuzhiyun 		return NULL;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (temp_int->pid_filt[filt_nr]->demux == demux_dev)
167*4882a593Smuzhiyun 		return temp_int;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return NULL;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /* find chip by demux */
find_dinode(void * demux_dev)173*4882a593Smuzhiyun static struct fpga_inode *find_dinode(void *demux_dev)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	struct fpga_inode *temp_chip = fpga_first_inode;
176*4882a593Smuzhiyun 	struct fpga_internal *temp_int;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/*
179*4882a593Smuzhiyun 	 * Search of the last fpga CI chip or
180*4882a593Smuzhiyun 	 * find it by demux
181*4882a593Smuzhiyun 	 */
182*4882a593Smuzhiyun 	while (temp_chip != NULL) {
183*4882a593Smuzhiyun 		if (temp_chip->internal != NULL) {
184*4882a593Smuzhiyun 			temp_int = temp_chip->internal;
185*4882a593Smuzhiyun 			if (check_filter(temp_int, demux_dev, 0))
186*4882a593Smuzhiyun 				break;
187*4882a593Smuzhiyun 			if (check_filter(temp_int, demux_dev, 1))
188*4882a593Smuzhiyun 				break;
189*4882a593Smuzhiyun 		}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		temp_chip = temp_chip->next_inode;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return temp_chip;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /* deallocating chip */
remove_inode(struct fpga_internal * internal)198*4882a593Smuzhiyun static void remove_inode(struct fpga_internal *internal)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	struct fpga_inode *prev_node = fpga_first_inode;
201*4882a593Smuzhiyun 	struct fpga_inode *del_node = find_inode(internal->dev);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (del_node != NULL) {
204*4882a593Smuzhiyun 		if (del_node == fpga_first_inode) {
205*4882a593Smuzhiyun 			fpga_first_inode = del_node->next_inode;
206*4882a593Smuzhiyun 		} else {
207*4882a593Smuzhiyun 			while (prev_node->next_inode != del_node)
208*4882a593Smuzhiyun 				prev_node = prev_node->next_inode;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 			if (del_node->next_inode == NULL)
211*4882a593Smuzhiyun 				prev_node->next_inode = NULL;
212*4882a593Smuzhiyun 			else
213*4882a593Smuzhiyun 				prev_node->next_inode =
214*4882a593Smuzhiyun 					prev_node->next_inode->next_inode;
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 		kfree(del_node);
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /* allocating new chip */
append_internal(struct fpga_internal * internal)222*4882a593Smuzhiyun static struct fpga_inode *append_internal(struct fpga_internal *internal)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct fpga_inode *new_node = fpga_first_inode;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (new_node == NULL) {
227*4882a593Smuzhiyun 		new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
228*4882a593Smuzhiyun 		fpga_first_inode = new_node;
229*4882a593Smuzhiyun 	} else {
230*4882a593Smuzhiyun 		while (new_node->next_inode != NULL)
231*4882a593Smuzhiyun 			new_node = new_node->next_inode;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		new_node->next_inode =
234*4882a593Smuzhiyun 				kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
235*4882a593Smuzhiyun 		if (new_node->next_inode != NULL)
236*4882a593Smuzhiyun 			new_node = new_node->next_inode;
237*4882a593Smuzhiyun 		else
238*4882a593Smuzhiyun 			new_node = NULL;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (new_node != NULL) {
242*4882a593Smuzhiyun 		new_node->internal = internal;
243*4882a593Smuzhiyun 		new_node->next_inode = NULL;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return new_node;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
netup_fpga_op_rw(struct fpga_internal * inter,int addr,u8 val,u8 read)249*4882a593Smuzhiyun static int netup_fpga_op_rw(struct fpga_internal *inter, int addr,
250*4882a593Smuzhiyun 							u8 val, u8 read)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0);
253*4882a593Smuzhiyun 	return inter->fpga_rw(inter->dev, 0, val, read);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun /* flag - mem/io, read - read/write */
altera_ci_op_cam(struct dvb_ca_en50221 * en50221,int slot,u8 flag,u8 read,int addr,u8 val)257*4882a593Smuzhiyun static int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
258*4882a593Smuzhiyun 				u8 flag, u8 read, int addr, u8 val)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	struct altera_ci_state *state = en50221->data;
262*4882a593Smuzhiyun 	struct fpga_internal *inter = state->internal;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	u8 store;
265*4882a593Smuzhiyun 	int mem = 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (0 != slot)
268*4882a593Smuzhiyun 		return -EINVAL;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0);
273*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0);
274*4882a593Smuzhiyun 	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	store &= 0x0f;
277*4882a593Smuzhiyun 	store |= ((state->nr << 7) | (flag << 6));
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0);
280*4882a593Smuzhiyun 	mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
285*4882a593Smuzhiyun 			(read) ? "read" : "write", addr,
286*4882a593Smuzhiyun 			(flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem",
287*4882a593Smuzhiyun 			(read) ? mem : val);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	return mem;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
altera_ci_read_attribute_mem(struct dvb_ca_en50221 * en50221,int slot,int addr)292*4882a593Smuzhiyun static int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
293*4882a593Smuzhiyun 					int slot, int addr)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
altera_ci_write_attribute_mem(struct dvb_ca_en50221 * en50221,int slot,int addr,u8 data)298*4882a593Smuzhiyun static int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
299*4882a593Smuzhiyun 					 int slot, int addr, u8 data)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	return altera_ci_op_cam(en50221, slot, 0, 0, addr, data);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
altera_ci_read_cam_ctl(struct dvb_ca_en50221 * en50221,int slot,u8 addr)304*4882a593Smuzhiyun static int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221,
305*4882a593Smuzhiyun 				  int slot, u8 addr)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL,
308*4882a593Smuzhiyun 						NETUP_CI_FLG_RD, addr, 0);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
altera_ci_write_cam_ctl(struct dvb_ca_en50221 * en50221,int slot,u8 addr,u8 data)311*4882a593Smuzhiyun static int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
312*4882a593Smuzhiyun 				   u8 addr, u8 data)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
altera_ci_slot_reset(struct dvb_ca_en50221 * en50221,int slot)317*4882a593Smuzhiyun static int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct altera_ci_state *state = en50221->data;
320*4882a593Smuzhiyun 	struct fpga_internal *inter = state->internal;
321*4882a593Smuzhiyun 	/* reasonable timeout for CI reset is 10 seconds */
322*4882a593Smuzhiyun 	unsigned long t_out = jiffies + msecs_to_jiffies(9999);
323*4882a593Smuzhiyun 	int ret;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (0 != slot)
328*4882a593Smuzhiyun 		return -EINVAL;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
333*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
334*4882a593Smuzhiyun 				(ret & 0xcf) | (1 << (5 - state->nr)), 0);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	for (;;) {
339*4882a593Smuzhiyun 		msleep(50);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		mutex_lock(&inter->fpga_mutex);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
344*4882a593Smuzhiyun 						0, NETUP_CI_FLG_RD);
345*4882a593Smuzhiyun 		mutex_unlock(&inter->fpga_mutex);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 		if ((ret & (1 << (5 - state->nr))) == 0)
348*4882a593Smuzhiyun 			break;
349*4882a593Smuzhiyun 		if (time_after(jiffies, t_out))
350*4882a593Smuzhiyun 			break;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	ci_dbg_print("%s: %d msecs\n", __func__,
355*4882a593Smuzhiyun 		jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out));
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
altera_ci_slot_shutdown(struct dvb_ca_en50221 * en50221,int slot)360*4882a593Smuzhiyun static int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	/* not implemented */
363*4882a593Smuzhiyun 	return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
altera_ci_slot_ts_ctl(struct dvb_ca_en50221 * en50221,int slot)366*4882a593Smuzhiyun static int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	struct altera_ci_state *state = en50221->data;
369*4882a593Smuzhiyun 	struct fpga_internal *inter = state->internal;
370*4882a593Smuzhiyun 	int ret;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (0 != slot)
375*4882a593Smuzhiyun 		return -EINVAL;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
380*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
381*4882a593Smuzhiyun 				(ret & 0x0f) | (1 << (3 - state->nr)), 0);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return 0;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun /* work handler */
netup_read_ci_status(struct work_struct * work)389*4882a593Smuzhiyun static void netup_read_ci_status(struct work_struct *work)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	struct fpga_internal *inter =
392*4882a593Smuzhiyun 			container_of(work, struct fpga_internal, work);
393*4882a593Smuzhiyun 	int ret;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
398*4882a593Smuzhiyun 	/* ack' irq */
399*4882a593Smuzhiyun 	ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD);
400*4882a593Smuzhiyun 	ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	if (inter->state[1] != NULL) {
405*4882a593Smuzhiyun 		inter->state[1]->status =
406*4882a593Smuzhiyun 				((ret & 1) == 0 ?
407*4882a593Smuzhiyun 				DVB_CA_EN50221_POLL_CAM_PRESENT |
408*4882a593Smuzhiyun 				DVB_CA_EN50221_POLL_CAM_READY : 0);
409*4882a593Smuzhiyun 		ci_dbg_print("%s: setting CI[1] status = 0x%x\n",
410*4882a593Smuzhiyun 				__func__, inter->state[1]->status);
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (inter->state[0] != NULL) {
414*4882a593Smuzhiyun 		inter->state[0]->status =
415*4882a593Smuzhiyun 				((ret & 2) == 0 ?
416*4882a593Smuzhiyun 				DVB_CA_EN50221_POLL_CAM_PRESENT |
417*4882a593Smuzhiyun 				DVB_CA_EN50221_POLL_CAM_READY : 0);
418*4882a593Smuzhiyun 		ci_dbg_print("%s: setting CI[0] status = 0x%x\n",
419*4882a593Smuzhiyun 				__func__, inter->state[0]->status);
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /* CI irq handler */
altera_ci_irq(void * dev)424*4882a593Smuzhiyun int altera_ci_irq(void *dev)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	struct fpga_inode *temp_int = NULL;
427*4882a593Smuzhiyun 	struct fpga_internal *inter = NULL;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (dev != NULL) {
432*4882a593Smuzhiyun 		temp_int = find_inode(dev);
433*4882a593Smuzhiyun 		if (temp_int != NULL) {
434*4882a593Smuzhiyun 			inter = temp_int->internal;
435*4882a593Smuzhiyun 			schedule_work(&inter->work);
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return 1;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun EXPORT_SYMBOL(altera_ci_irq);
442*4882a593Smuzhiyun 
altera_poll_ci_slot_status(struct dvb_ca_en50221 * en50221,int slot,int open)443*4882a593Smuzhiyun static int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
444*4882a593Smuzhiyun 				      int slot, int open)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct altera_ci_state *state = en50221->data;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (0 != slot)
449*4882a593Smuzhiyun 		return -EINVAL;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return state->status;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
altera_hw_filt_release(void * main_dev,int filt_nr)454*4882a593Smuzhiyun static void altera_hw_filt_release(void *main_dev, int filt_nr)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_inode(main_dev);
457*4882a593Smuzhiyun 	struct netup_hw_pid_filter *pid_filt = NULL;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	if (temp_int != NULL) {
462*4882a593Smuzhiyun 		pid_filt = temp_int->internal->pid_filt[filt_nr - 1];
463*4882a593Smuzhiyun 		/* stored old feed controls */
464*4882a593Smuzhiyun 		pid_filt->demux->start_feed = pid_filt->start_feed;
465*4882a593Smuzhiyun 		pid_filt->demux->stop_feed = pid_filt->stop_feed;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 		if (((--(temp_int->internal->filts_used)) <= 0) &&
468*4882a593Smuzhiyun 			 ((temp_int->internal->cis_used) <= 0)) {
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 			ci_dbg_print("%s: Actually removing\n", __func__);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 			remove_inode(temp_int->internal);
473*4882a593Smuzhiyun 			kfree(pid_filt->internal);
474*4882a593Smuzhiyun 		}
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 		kfree(pid_filt);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
altera_ci_release(void * dev,int ci_nr)482*4882a593Smuzhiyun void altera_ci_release(void *dev, int ci_nr)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_inode(dev);
485*4882a593Smuzhiyun 	struct altera_ci_state *state = NULL;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (temp_int != NULL) {
490*4882a593Smuzhiyun 		state = temp_int->internal->state[ci_nr - 1];
491*4882a593Smuzhiyun 		altera_hw_filt_release(dev, ci_nr);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 		if (((temp_int->internal->filts_used) <= 0) &&
495*4882a593Smuzhiyun 				((--(temp_int->internal->cis_used)) <= 0)) {
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 			ci_dbg_print("%s: Actually removing\n", __func__);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 			remove_inode(temp_int->internal);
500*4882a593Smuzhiyun 			kfree(state->internal);
501*4882a593Smuzhiyun 		}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 		if (state != NULL) {
504*4882a593Smuzhiyun 			if (state->ca.data != NULL)
505*4882a593Smuzhiyun 				dvb_ca_en50221_release(&state->ca);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 			kfree(state);
508*4882a593Smuzhiyun 		}
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun EXPORT_SYMBOL(altera_ci_release);
513*4882a593Smuzhiyun 
altera_pid_control(struct netup_hw_pid_filter * pid_filt,u16 pid,int onoff)514*4882a593Smuzhiyun static void altera_pid_control(struct netup_hw_pid_filter *pid_filt,
515*4882a593Smuzhiyun 		u16 pid, int onoff)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	struct fpga_internal *inter = pid_filt->internal;
518*4882a593Smuzhiyun 	u8 store = 0;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* pid 0-0x1f always enabled, don't touch them */
521*4882a593Smuzhiyun 	if ((pid == 0x2000) || (pid < 0x20))
522*4882a593Smuzhiyun 		return;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0);
527*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
528*4882a593Smuzhiyun 			((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	if (onoff)/* 0 - on, 1 - off */
533*4882a593Smuzhiyun 		store |= (1 << (pid & 7));
534*4882a593Smuzhiyun 	else
535*4882a593Smuzhiyun 		store &= ~(1 << (pid & 7));
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__,
542*4882a593Smuzhiyun 		pid_filt->nr, pid, pid, onoff ? "off" : "on");
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
altera_toggle_fullts_streaming(struct netup_hw_pid_filter * pid_filt,int filt_nr,int onoff)545*4882a593Smuzhiyun static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt,
546*4882a593Smuzhiyun 					int filt_nr, int onoff)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct fpga_internal *inter = pid_filt->internal;
549*4882a593Smuzhiyun 	u8 store = 0;
550*4882a593Smuzhiyun 	int i;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	pid_dbg_print("%s: pid_filt->nr[%d]  now %s\n", __func__, pid_filt->nr,
553*4882a593Smuzhiyun 			onoff ? "off" : "on");
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	if (onoff)/* 0 - on, 1 - off */
556*4882a593Smuzhiyun 		store = 0xff;/* ignore pid */
557*4882a593Smuzhiyun 	else
558*4882a593Smuzhiyun 		store = 0;/* enable pid */
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	for (i = 0; i < 1024; i++) {
563*4882a593Smuzhiyun 		netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 		netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
566*4882a593Smuzhiyun 				((i >> 8) & 0x03) | (pid_filt->nr << 2), 0);
567*4882a593Smuzhiyun 		/* pid 0-0x1f always enabled */
568*4882a593Smuzhiyun 		netup_fpga_op_rw(inter, NETUP_CI_PID_DATA,
569*4882a593Smuzhiyun 				(i > 3 ? store : 0), 0);
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
altera_pid_feed_control(void * demux_dev,int filt_nr,struct dvb_demux_feed * feed,int onoff)575*4882a593Smuzhiyun static int altera_pid_feed_control(void *demux_dev, int filt_nr,
576*4882a593Smuzhiyun 		struct dvb_demux_feed *feed, int onoff)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_dinode(demux_dev);
579*4882a593Smuzhiyun 	struct fpga_internal *inter = temp_int->internal;
580*4882a593Smuzhiyun 	struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1];
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1);
583*4882a593Smuzhiyun 	/* call old feed proc's */
584*4882a593Smuzhiyun 	if (onoff)
585*4882a593Smuzhiyun 		pid_filt->start_feed(feed);
586*4882a593Smuzhiyun 	else
587*4882a593Smuzhiyun 		pid_filt->stop_feed(feed);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (feed->pid == 0x2000)
590*4882a593Smuzhiyun 		altera_toggle_fullts_streaming(pid_filt, filt_nr,
591*4882a593Smuzhiyun 						onoff ? 0 : 1);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	return 0;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun 
altera_ci_start_feed(struct dvb_demux_feed * feed,int num)596*4882a593Smuzhiyun static int altera_ci_start_feed(struct dvb_demux_feed *feed, int num)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun 	altera_pid_feed_control(feed->demux, num, feed, 1);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
altera_ci_stop_feed(struct dvb_demux_feed * feed,int num)603*4882a593Smuzhiyun static int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	altera_pid_feed_control(feed->demux, num, feed, 0);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	return 0;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
altera_ci_start_feed_1(struct dvb_demux_feed * feed)610*4882a593Smuzhiyun static int altera_ci_start_feed_1(struct dvb_demux_feed *feed)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	return altera_ci_start_feed(feed, 1);
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
altera_ci_stop_feed_1(struct dvb_demux_feed * feed)615*4882a593Smuzhiyun static int altera_ci_stop_feed_1(struct dvb_demux_feed *feed)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	return altera_ci_stop_feed(feed, 1);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun 
altera_ci_start_feed_2(struct dvb_demux_feed * feed)620*4882a593Smuzhiyun static int altera_ci_start_feed_2(struct dvb_demux_feed *feed)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	return altera_ci_start_feed(feed, 2);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
altera_ci_stop_feed_2(struct dvb_demux_feed * feed)625*4882a593Smuzhiyun static int altera_ci_stop_feed_2(struct dvb_demux_feed *feed)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun 	return altera_ci_stop_feed(feed, 2);
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
altera_hw_filt_init(struct altera_ci_config * config,int hw_filt_nr)630*4882a593Smuzhiyun static int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	struct netup_hw_pid_filter *pid_filt = NULL;
633*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_inode(config->dev);
634*4882a593Smuzhiyun 	struct fpga_internal *inter = NULL;
635*4882a593Smuzhiyun 	int ret = 0;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	if (!pid_filt) {
642*4882a593Smuzhiyun 		ret = -ENOMEM;
643*4882a593Smuzhiyun 		goto err;
644*4882a593Smuzhiyun 	}
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	if (temp_int != NULL) {
647*4882a593Smuzhiyun 		inter = temp_int->internal;
648*4882a593Smuzhiyun 		(inter->filts_used)++;
649*4882a593Smuzhiyun 		ci_dbg_print("%s: Find Internal Structure!\n", __func__);
650*4882a593Smuzhiyun 	} else {
651*4882a593Smuzhiyun 		inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
652*4882a593Smuzhiyun 		if (!inter) {
653*4882a593Smuzhiyun 			ret = -ENOMEM;
654*4882a593Smuzhiyun 			goto err;
655*4882a593Smuzhiyun 		}
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 		temp_int = append_internal(inter);
658*4882a593Smuzhiyun 		if (!temp_int) {
659*4882a593Smuzhiyun 			ret = -ENOMEM;
660*4882a593Smuzhiyun 			goto err;
661*4882a593Smuzhiyun 		}
662*4882a593Smuzhiyun 		inter->filts_used = 1;
663*4882a593Smuzhiyun 		inter->dev = config->dev;
664*4882a593Smuzhiyun 		inter->fpga_rw = config->fpga_rw;
665*4882a593Smuzhiyun 		mutex_init(&inter->fpga_mutex);
666*4882a593Smuzhiyun 		inter->strt_wrk = 1;
667*4882a593Smuzhiyun 		ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__,
671*4882a593Smuzhiyun 						pid_filt, hw_filt_nr - 1);
672*4882a593Smuzhiyun 	inter->pid_filt[hw_filt_nr - 1] = pid_filt;
673*4882a593Smuzhiyun 	pid_filt->demux = config->demux;
674*4882a593Smuzhiyun 	pid_filt->internal = inter;
675*4882a593Smuzhiyun 	pid_filt->nr = hw_filt_nr - 1;
676*4882a593Smuzhiyun 	/* store old feed controls */
677*4882a593Smuzhiyun 	pid_filt->start_feed = config->demux->start_feed;
678*4882a593Smuzhiyun 	pid_filt->stop_feed = config->demux->stop_feed;
679*4882a593Smuzhiyun 	/* replace with new feed controls */
680*4882a593Smuzhiyun 	if (hw_filt_nr == 1) {
681*4882a593Smuzhiyun 		pid_filt->demux->start_feed = altera_ci_start_feed_1;
682*4882a593Smuzhiyun 		pid_filt->demux->stop_feed = altera_ci_stop_feed_1;
683*4882a593Smuzhiyun 	} else if (hw_filt_nr == 2) {
684*4882a593Smuzhiyun 		pid_filt->demux->start_feed = altera_ci_start_feed_2;
685*4882a593Smuzhiyun 		pid_filt->demux->stop_feed = altera_ci_stop_feed_2;
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	altera_toggle_fullts_streaming(pid_filt, 0, 1);
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	return 0;
691*4882a593Smuzhiyun err:
692*4882a593Smuzhiyun 	ci_dbg_print("%s: Can't init hardware filter: Error %d\n",
693*4882a593Smuzhiyun 		     __func__, ret);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	kfree(pid_filt);
696*4882a593Smuzhiyun 	kfree(inter);
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	return ret;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun 
altera_ci_init(struct altera_ci_config * config,int ci_nr)701*4882a593Smuzhiyun int altera_ci_init(struct altera_ci_config *config, int ci_nr)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	struct altera_ci_state *state;
704*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_inode(config->dev);
705*4882a593Smuzhiyun 	struct fpga_internal *inter = NULL;
706*4882a593Smuzhiyun 	int ret = 0;
707*4882a593Smuzhiyun 	u8 store = 0;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	if (!state) {
714*4882a593Smuzhiyun 		ret = -ENOMEM;
715*4882a593Smuzhiyun 		goto err;
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	if (temp_int != NULL) {
719*4882a593Smuzhiyun 		inter = temp_int->internal;
720*4882a593Smuzhiyun 		(inter->cis_used)++;
721*4882a593Smuzhiyun 		inter->fpga_rw = config->fpga_rw;
722*4882a593Smuzhiyun 		ci_dbg_print("%s: Find Internal Structure!\n", __func__);
723*4882a593Smuzhiyun 	} else {
724*4882a593Smuzhiyun 		inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
725*4882a593Smuzhiyun 		if (!inter) {
726*4882a593Smuzhiyun 			ret = -ENOMEM;
727*4882a593Smuzhiyun 			goto err;
728*4882a593Smuzhiyun 		}
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 		temp_int = append_internal(inter);
731*4882a593Smuzhiyun 		if (!temp_int) {
732*4882a593Smuzhiyun 			ret = -ENOMEM;
733*4882a593Smuzhiyun 			goto err;
734*4882a593Smuzhiyun 		}
735*4882a593Smuzhiyun 		inter->cis_used = 1;
736*4882a593Smuzhiyun 		inter->dev = config->dev;
737*4882a593Smuzhiyun 		inter->fpga_rw = config->fpga_rw;
738*4882a593Smuzhiyun 		mutex_init(&inter->fpga_mutex);
739*4882a593Smuzhiyun 		inter->strt_wrk = 1;
740*4882a593Smuzhiyun 		ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__,
744*4882a593Smuzhiyun 						state, ci_nr - 1);
745*4882a593Smuzhiyun 	state->internal = inter;
746*4882a593Smuzhiyun 	state->nr = ci_nr - 1;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	state->ca.owner = THIS_MODULE;
749*4882a593Smuzhiyun 	state->ca.read_attribute_mem = altera_ci_read_attribute_mem;
750*4882a593Smuzhiyun 	state->ca.write_attribute_mem = altera_ci_write_attribute_mem;
751*4882a593Smuzhiyun 	state->ca.read_cam_control = altera_ci_read_cam_ctl;
752*4882a593Smuzhiyun 	state->ca.write_cam_control = altera_ci_write_cam_ctl;
753*4882a593Smuzhiyun 	state->ca.slot_reset = altera_ci_slot_reset;
754*4882a593Smuzhiyun 	state->ca.slot_shutdown = altera_ci_slot_shutdown;
755*4882a593Smuzhiyun 	state->ca.slot_ts_enable = altera_ci_slot_ts_ctl;
756*4882a593Smuzhiyun 	state->ca.poll_slot_status = altera_poll_ci_slot_status;
757*4882a593Smuzhiyun 	state->ca.data = state;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	ret = dvb_ca_en50221_init(config->adapter,
760*4882a593Smuzhiyun 				   &state->ca,
761*4882a593Smuzhiyun 				   /* flags */ 0,
762*4882a593Smuzhiyun 				   /* n_slots */ 1);
763*4882a593Smuzhiyun 	if (0 != ret)
764*4882a593Smuzhiyun 		goto err;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	inter->state[ci_nr - 1] = state;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	altera_hw_filt_init(config, ci_nr);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (inter->strt_wrk) {
771*4882a593Smuzhiyun 		INIT_WORK(&inter->work, netup_read_ci_status);
772*4882a593Smuzhiyun 		inter->strt_wrk = 0;
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	ci_dbg_print("%s: CI initialized!\n", __func__);
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	/* Enable div */
780*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0);
781*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	/* enable TS out */
784*4882a593Smuzhiyun 	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
785*4882a593Smuzhiyun 	store |= (3 << 4);
786*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD);
789*4882a593Smuzhiyun 	/* enable irq */
790*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret);
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	schedule_work(&inter->work);
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	return 0;
799*4882a593Smuzhiyun err:
800*4882a593Smuzhiyun 	ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	kfree(state);
803*4882a593Smuzhiyun 	kfree(inter);
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	return ret;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun EXPORT_SYMBOL(altera_ci_init);
808*4882a593Smuzhiyun 
altera_ci_tuner_reset(void * dev,int ci_nr)809*4882a593Smuzhiyun int altera_ci_tuner_reset(void *dev, int ci_nr)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun 	struct fpga_inode *temp_int = find_inode(dev);
812*4882a593Smuzhiyun 	struct fpga_internal *inter = NULL;
813*4882a593Smuzhiyun 	u8 store;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	ci_dbg_print("%s\n", __func__);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	if (temp_int == NULL)
818*4882a593Smuzhiyun 		return -1;
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	if (temp_int->internal == NULL)
821*4882a593Smuzhiyun 		return -1;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	inter = temp_int->internal;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	mutex_lock(&inter->fpga_mutex);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
828*4882a593Smuzhiyun 	store &= ~(4 << (2 - ci_nr));
829*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
830*4882a593Smuzhiyun 	msleep(100);
831*4882a593Smuzhiyun 	store |= (4 << (2 - ci_nr));
832*4882a593Smuzhiyun 	netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	mutex_unlock(&inter->fpga_mutex);
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	return 0;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun EXPORT_SYMBOL(altera_ci_tuner_reset);
839