1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ddbridge-ci.c: Digital Devices bridge CI (DuoFlex, CI Bridge) support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2010-2017 Digital Devices GmbH
6*4882a593Smuzhiyun * Marcus Metzler <mocm@metzlerbros.de>
7*4882a593Smuzhiyun * Ralph Metzler <rjkm@metzlerbros.de>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License
11*4882a593Smuzhiyun * version 2 only, as published by the Free Software Foundation.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun * GNU General Public License for more details.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "ddbridge.h"
20*4882a593Smuzhiyun #include "ddbridge-regs.h"
21*4882a593Smuzhiyun #include "ddbridge-ci.h"
22*4882a593Smuzhiyun #include "ddbridge-io.h"
23*4882a593Smuzhiyun #include "ddbridge-i2c.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "cxd2099.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* Octopus CI internal CI interface */
28*4882a593Smuzhiyun
wait_ci_ready(struct ddb_ci * ci)29*4882a593Smuzhiyun static int wait_ci_ready(struct ddb_ci *ci)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun u32 count = 10;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun ndelay(500);
34*4882a593Smuzhiyun do {
35*4882a593Smuzhiyun if (ddbreadl(ci->port->dev,
36*4882a593Smuzhiyun CI_CONTROL(ci->nr)) & CI_READY)
37*4882a593Smuzhiyun break;
38*4882a593Smuzhiyun usleep_range(1, 2);
39*4882a593Smuzhiyun if ((--count) == 0)
40*4882a593Smuzhiyun return -1;
41*4882a593Smuzhiyun } while (1);
42*4882a593Smuzhiyun return 0;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
read_attribute_mem(struct dvb_ca_en50221 * ca,int slot,int address)45*4882a593Smuzhiyun static int read_attribute_mem(struct dvb_ca_en50221 *ca,
46*4882a593Smuzhiyun int slot, int address)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
49*4882a593Smuzhiyun u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (address > CI_BUFFER_SIZE)
52*4882a593Smuzhiyun return -1;
53*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
54*4882a593Smuzhiyun CI_DO_READ_ATTRIBUTES(ci->nr));
55*4882a593Smuzhiyun wait_ci_ready(ci);
56*4882a593Smuzhiyun val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);
57*4882a593Smuzhiyun return val;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
write_attribute_mem(struct dvb_ca_en50221 * ca,int slot,int address,u8 value)60*4882a593Smuzhiyun static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
61*4882a593Smuzhiyun int address, u8 value)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
66*4882a593Smuzhiyun CI_DO_ATTRIBUTE_RW(ci->nr));
67*4882a593Smuzhiyun wait_ci_ready(ci);
68*4882a593Smuzhiyun return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
read_cam_control(struct dvb_ca_en50221 * ca,int slot,u8 address)71*4882a593Smuzhiyun static int read_cam_control(struct dvb_ca_en50221 *ca,
72*4882a593Smuzhiyun int slot, u8 address)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun u32 count = 100;
75*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
76*4882a593Smuzhiyun u32 res;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_READ_CMD | address,
79*4882a593Smuzhiyun CI_DO_IO_RW(ci->nr));
80*4882a593Smuzhiyun ndelay(500);
81*4882a593Smuzhiyun do {
82*4882a593Smuzhiyun res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));
83*4882a593Smuzhiyun if (res & CI_READY)
84*4882a593Smuzhiyun break;
85*4882a593Smuzhiyun usleep_range(1, 2);
86*4882a593Smuzhiyun if ((--count) == 0)
87*4882a593Smuzhiyun return -1;
88*4882a593Smuzhiyun } while (1);
89*4882a593Smuzhiyun return 0xff & res;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
write_cam_control(struct dvb_ca_en50221 * ca,int slot,u8 address,u8 value)92*4882a593Smuzhiyun static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
93*4882a593Smuzhiyun u8 address, u8 value)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
98*4882a593Smuzhiyun CI_DO_IO_RW(ci->nr));
99*4882a593Smuzhiyun wait_ci_ready(ci);
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
slot_reset(struct dvb_ca_en50221 * ca,int slot)103*4882a593Smuzhiyun static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_POWER_ON,
108*4882a593Smuzhiyun CI_CONTROL(ci->nr));
109*4882a593Smuzhiyun msleep(100);
110*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
111*4882a593Smuzhiyun CI_CONTROL(ci->nr));
112*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
113*4882a593Smuzhiyun CI_CONTROL(ci->nr));
114*4882a593Smuzhiyun usleep_range(20, 25);
115*4882a593Smuzhiyun ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
116*4882a593Smuzhiyun CI_CONTROL(ci->nr));
117*4882a593Smuzhiyun return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
slot_shutdown(struct dvb_ca_en50221 * ca,int slot)120*4882a593Smuzhiyun static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr));
125*4882a593Smuzhiyun msleep(300);
126*4882a593Smuzhiyun return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
slot_ts_enable(struct dvb_ca_en50221 * ca,int slot)129*4882a593Smuzhiyun static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
132*4882a593Smuzhiyun u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
135*4882a593Smuzhiyun CI_CONTROL(ci->nr));
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
poll_slot_status(struct dvb_ca_en50221 * ca,int slot,int open)139*4882a593Smuzhiyun static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
142*4882a593Smuzhiyun u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
143*4882a593Smuzhiyun int stat = 0;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (val & CI_CAM_DETECT)
146*4882a593Smuzhiyun stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
147*4882a593Smuzhiyun if (val & CI_CAM_READY)
148*4882a593Smuzhiyun stat |= DVB_CA_EN50221_POLL_CAM_READY;
149*4882a593Smuzhiyun return stat;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static struct dvb_ca_en50221 en_templ = {
153*4882a593Smuzhiyun .read_attribute_mem = read_attribute_mem,
154*4882a593Smuzhiyun .write_attribute_mem = write_attribute_mem,
155*4882a593Smuzhiyun .read_cam_control = read_cam_control,
156*4882a593Smuzhiyun .write_cam_control = write_cam_control,
157*4882a593Smuzhiyun .slot_reset = slot_reset,
158*4882a593Smuzhiyun .slot_shutdown = slot_shutdown,
159*4882a593Smuzhiyun .slot_ts_enable = slot_ts_enable,
160*4882a593Smuzhiyun .poll_slot_status = poll_slot_status,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun
ci_attach(struct ddb_port * port)163*4882a593Smuzhiyun static void ci_attach(struct ddb_port *port)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct ddb_ci *ci;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun ci = kzalloc(sizeof(*ci), GFP_KERNEL);
168*4882a593Smuzhiyun if (!ci)
169*4882a593Smuzhiyun return;
170*4882a593Smuzhiyun memcpy(&ci->en, &en_templ, sizeof(en_templ));
171*4882a593Smuzhiyun ci->en.data = ci;
172*4882a593Smuzhiyun port->en = &ci->en;
173*4882a593Smuzhiyun port->en_freedata = 1;
174*4882a593Smuzhiyun ci->port = port;
175*4882a593Smuzhiyun ci->nr = port->nr - 2;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* DuoFlex Dual CI support */
179*4882a593Smuzhiyun
write_creg(struct ddb_ci * ci,u8 data,u8 mask)180*4882a593Smuzhiyun static int write_creg(struct ddb_ci *ci, u8 data, u8 mask)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
183*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun ci->port->creg = (ci->port->creg & ~mask) | data;
186*4882a593Smuzhiyun return i2c_write_reg(i2c, adr, 0x02, ci->port->creg);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
read_attribute_mem_xo2(struct dvb_ca_en50221 * ca,int slot,int address)189*4882a593Smuzhiyun static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca,
190*4882a593Smuzhiyun int slot, int address)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
193*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
194*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
195*4882a593Smuzhiyun int res;
196*4882a593Smuzhiyun u8 val;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val);
199*4882a593Smuzhiyun return res ? res : val;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
write_attribute_mem_xo2(struct dvb_ca_en50221 * ca,int slot,int address,u8 value)202*4882a593Smuzhiyun static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot,
203*4882a593Smuzhiyun int address, u8 value)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
206*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
207*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun return i2c_write_reg16(i2c, adr, 0x8000 | address, value);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
read_cam_control_xo2(struct dvb_ca_en50221 * ca,int slot,u8 address)212*4882a593Smuzhiyun static int read_cam_control_xo2(struct dvb_ca_en50221 *ca,
213*4882a593Smuzhiyun int slot, u8 address)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
216*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
217*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
218*4882a593Smuzhiyun u8 val;
219*4882a593Smuzhiyun int res;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val);
222*4882a593Smuzhiyun return res ? res : val;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
write_cam_control_xo2(struct dvb_ca_en50221 * ca,int slot,u8 address,u8 value)225*4882a593Smuzhiyun static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot,
226*4882a593Smuzhiyun u8 address, u8 value)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
229*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
230*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
slot_reset_xo2(struct dvb_ca_en50221 * ca,int slot)235*4882a593Smuzhiyun static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun dev_dbg(ci->port->dev->dev, "%s\n", __func__);
240*4882a593Smuzhiyun write_creg(ci, 0x01, 0x01);
241*4882a593Smuzhiyun write_creg(ci, 0x04, 0x04);
242*4882a593Smuzhiyun msleep(20);
243*4882a593Smuzhiyun write_creg(ci, 0x02, 0x02);
244*4882a593Smuzhiyun write_creg(ci, 0x00, 0x04);
245*4882a593Smuzhiyun write_creg(ci, 0x18, 0x18);
246*4882a593Smuzhiyun return 0;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
slot_shutdown_xo2(struct dvb_ca_en50221 * ca,int slot)249*4882a593Smuzhiyun static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun dev_dbg(ci->port->dev->dev, "%s\n", __func__);
254*4882a593Smuzhiyun write_creg(ci, 0x10, 0xff);
255*4882a593Smuzhiyun write_creg(ci, 0x08, 0x08);
256*4882a593Smuzhiyun return 0;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
slot_ts_enable_xo2(struct dvb_ca_en50221 * ca,int slot)259*4882a593Smuzhiyun static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun dev_dbg(ci->port->dev->dev, "%s\n", __func__);
264*4882a593Smuzhiyun write_creg(ci, 0x00, 0x10);
265*4882a593Smuzhiyun return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
poll_slot_status_xo2(struct dvb_ca_en50221 * ca,int slot,int open)268*4882a593Smuzhiyun static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun struct ddb_ci *ci = ca->data;
271*4882a593Smuzhiyun struct i2c_adapter *i2c = &ci->port->i2c->adap;
272*4882a593Smuzhiyun u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
273*4882a593Smuzhiyun u8 val = 0;
274*4882a593Smuzhiyun int stat = 0;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun i2c_read_reg(i2c, adr, 0x01, &val);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (val & 2)
279*4882a593Smuzhiyun stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
280*4882a593Smuzhiyun if (val & 1)
281*4882a593Smuzhiyun stat |= DVB_CA_EN50221_POLL_CAM_READY;
282*4882a593Smuzhiyun return stat;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun static struct dvb_ca_en50221 en_xo2_templ = {
286*4882a593Smuzhiyun .read_attribute_mem = read_attribute_mem_xo2,
287*4882a593Smuzhiyun .write_attribute_mem = write_attribute_mem_xo2,
288*4882a593Smuzhiyun .read_cam_control = read_cam_control_xo2,
289*4882a593Smuzhiyun .write_cam_control = write_cam_control_xo2,
290*4882a593Smuzhiyun .slot_reset = slot_reset_xo2,
291*4882a593Smuzhiyun .slot_shutdown = slot_shutdown_xo2,
292*4882a593Smuzhiyun .slot_ts_enable = slot_ts_enable_xo2,
293*4882a593Smuzhiyun .poll_slot_status = poll_slot_status_xo2,
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun
ci_xo2_attach(struct ddb_port * port)296*4882a593Smuzhiyun static void ci_xo2_attach(struct ddb_port *port)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct ddb_ci *ci;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun ci = kzalloc(sizeof(*ci), GFP_KERNEL);
301*4882a593Smuzhiyun if (!ci)
302*4882a593Smuzhiyun return;
303*4882a593Smuzhiyun memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));
304*4882a593Smuzhiyun ci->en.data = ci;
305*4882a593Smuzhiyun port->en = &ci->en;
306*4882a593Smuzhiyun port->en_freedata = 1;
307*4882a593Smuzhiyun ci->port = port;
308*4882a593Smuzhiyun ci->nr = port->nr - 2;
309*4882a593Smuzhiyun ci->port->creg = 0;
310*4882a593Smuzhiyun write_creg(ci, 0x10, 0xff);
311*4882a593Smuzhiyun write_creg(ci, 0x08, 0x08);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun static const struct cxd2099_cfg cxd_cfgtmpl = {
315*4882a593Smuzhiyun .bitrate = 72000,
316*4882a593Smuzhiyun .polarity = 1,
317*4882a593Smuzhiyun .clock_mode = 1,
318*4882a593Smuzhiyun .max_i2c = 512,
319*4882a593Smuzhiyun };
320*4882a593Smuzhiyun
ci_cxd2099_attach(struct ddb_port * port,u32 bitrate)321*4882a593Smuzhiyun static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;
324*4882a593Smuzhiyun struct i2c_client *client;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun cxd_cfg.bitrate = bitrate;
327*4882a593Smuzhiyun cxd_cfg.en = &port->en;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap,
330*4882a593Smuzhiyun 0x40, &cxd_cfg);
331*4882a593Smuzhiyun if (!client)
332*4882a593Smuzhiyun goto err;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun port->dvb[0].i2c_client[0] = client;
335*4882a593Smuzhiyun port->en_freedata = 0;
336*4882a593Smuzhiyun return 0;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun err:
339*4882a593Smuzhiyun dev_err(port->dev->dev, "CXD2099AR attach failed\n");
340*4882a593Smuzhiyun return -ENODEV;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
ddb_ci_attach(struct ddb_port * port,u32 bitrate)343*4882a593Smuzhiyun int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun int ret;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun switch (port->type) {
348*4882a593Smuzhiyun case DDB_CI_EXTERNAL_SONY:
349*4882a593Smuzhiyun ret = ci_cxd2099_attach(port, bitrate);
350*4882a593Smuzhiyun if (ret)
351*4882a593Smuzhiyun return -ENODEV;
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun case DDB_CI_EXTERNAL_XO2:
354*4882a593Smuzhiyun case DDB_CI_EXTERNAL_XO2_B:
355*4882a593Smuzhiyun ci_xo2_attach(port);
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun case DDB_CI_INTERNAL:
358*4882a593Smuzhiyun ci_attach(port);
359*4882a593Smuzhiyun break;
360*4882a593Smuzhiyun default:
361*4882a593Smuzhiyun return -ENODEV;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun if (!port->en)
365*4882a593Smuzhiyun return -ENODEV;
366*4882a593Smuzhiyun dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
ddb_ci_detach(struct ddb_port * port)370*4882a593Smuzhiyun void ddb_ci_detach(struct ddb_port *port)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun if (port->dvb[0].dev)
373*4882a593Smuzhiyun dvb_unregister_device(port->dvb[0].dev);
374*4882a593Smuzhiyun if (port->en) {
375*4882a593Smuzhiyun dvb_ca_en50221_release(port->en);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun dvb_module_release(port->dvb[0].i2c_client[0]);
378*4882a593Smuzhiyun port->dvb[0].i2c_client[0] = NULL;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* free alloc'ed memory if needed */
381*4882a593Smuzhiyun if (port->en_freedata)
382*4882a593Smuzhiyun kfree(port->en->data);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun port->en = NULL;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun }
387