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