1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "sp2_priv.h"
16
17static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
18{
19 int ret;
20 struct i2c_client *client = s->client;
21 struct i2c_adapter *adap = client->adapter;
22 struct i2c_msg msg[] = {
23 {
24 .addr = client->addr,
25 .flags = 0,
26 .buf = ®,
27 .len = 1
28 }, {
29 .addr = client->addr,
30 .flags = I2C_M_RD,
31 .buf = buf,
32 .len = len
33 }
34 };
35
36 ret = i2c_transfer(adap, msg, 2);
37
38 if (ret != 2) {
39 dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
40 reg, ret);
41 if (ret < 0)
42 return ret;
43 else
44 return -EIO;
45 }
46
47 dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
48 client->addr, reg, buf[0]);
49
50 return 0;
51}
52
53static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
54{
55 int ret;
56 u8 buffer[35];
57 struct i2c_client *client = s->client;
58 struct i2c_adapter *adap = client->adapter;
59 struct i2c_msg msg = {
60 .addr = client->addr,
61 .flags = 0,
62 .buf = &buffer[0],
63 .len = len + 1
64 };
65
66 if ((len + 1) > sizeof(buffer)) {
67 dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
68 reg, len);
69 return -EINVAL;
70 }
71
72 buffer[0] = reg;
73 memcpy(&buffer[1], buf, len);
74
75 ret = i2c_transfer(adap, &msg, 1);
76
77 if (ret != 1) {
78 dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
79 reg, ret);
80 if (ret < 0)
81 return ret;
82 else
83 return -EIO;
84 }
85
86 dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %*ph\n",
87 client->addr, reg, len, buf);
88
89 return 0;
90}
91
92static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
93 u8 read, int addr, u8 data)
94{
95 struct sp2 *s = en50221->data;
96 u8 store;
97 int mem, ret;
98 int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
99
100 if (slot != 0)
101 return -EINVAL;
102
103
104
105
106
107 if (s->module_access_type != acs) {
108 ret = sp2_read_i2c(s, 0x00, &store, 1);
109
110 if (ret)
111 return ret;
112
113 store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
114 store |= acs;
115
116 ret = sp2_write_i2c(s, 0x00, &store, 1);
117 if (ret)
118 return ret;
119 }
120
121 s->module_access_type = acs;
122
123
124 if (ci_op_cam) {
125 ret = ci_op_cam(s->priv, read, addr, data, &mem);
126 } else {
127 dev_err(&s->client->dev, "callback not defined");
128 return -EINVAL;
129 }
130
131 if (ret)
132 return ret;
133
134 dev_dbg(&s->client->dev, "%s: slot=%d, addr=0x%04x, %s, data=%x",
135 (read) ? "read" : "write", slot, addr,
136 (acs == SP2_CI_ATTR_ACS) ? "attr" : "io",
137 (read) ? mem : data);
138
139 if (read)
140 return mem;
141 else
142 return 0;
143
144}
145
146int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
147 int slot, int addr)
148{
149 return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
150 SP2_CI_RD, addr, 0);
151}
152
153int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
154 int slot, int addr, u8 data)
155{
156 return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
157 SP2_CI_WR, addr, data);
158}
159
160int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
161 int slot, u8 addr)
162{
163 return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
164 SP2_CI_RD, addr, 0);
165}
166
167int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
168 int slot, u8 addr, u8 data)
169{
170 return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
171 SP2_CI_WR, addr, data);
172}
173
174int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
175{
176 struct sp2 *s = en50221->data;
177 u8 buf;
178 int ret;
179
180 dev_dbg(&s->client->dev, "slot: %d\n", slot);
181
182 if (slot != 0)
183 return -EINVAL;
184
185
186 buf = SP2_MOD_CTL_RST;
187 ret = sp2_write_i2c(s, 0x00, &buf, 1);
188
189 if (ret)
190 return ret;
191
192 usleep_range(500, 600);
193
194
195 buf = 0x00;
196 ret = sp2_write_i2c(s, 0x00, &buf, 1);
197
198 if (ret)
199 return ret;
200
201 msleep(1000);
202
203 return 0;
204}
205
206int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
207{
208 struct sp2 *s = en50221->data;
209
210 dev_dbg(&s->client->dev, "slot:%d\n", slot);
211
212
213 return 0;
214}
215
216int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
217{
218 struct sp2 *s = en50221->data;
219 u8 buf;
220
221 dev_dbg(&s->client->dev, "slot:%d\n", slot);
222
223 if (slot != 0)
224 return -EINVAL;
225
226 sp2_read_i2c(s, 0x00, &buf, 1);
227
228
229 buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
230 return sp2_write_i2c(s, 0, &buf, 1);
231}
232
233int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
234 int slot, int open)
235{
236 struct sp2 *s = en50221->data;
237 u8 buf[2];
238 int ret;
239
240 dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
241
242
243
244
245
246 if (time_after(jiffies, s->next_status_checked_time)) {
247 ret = sp2_read_i2c(s, 0x00, buf, 1);
248 s->next_status_checked_time = jiffies + msecs_to_jiffies(1000);
249
250 if (ret)
251 return 0;
252
253 if (buf[0] & SP2_MOD_CTL_DET)
254 s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
255 DVB_CA_EN50221_POLL_CAM_READY;
256 else
257 s->status = 0;
258 }
259
260 return s->status;
261}
262
263static int sp2_init(struct sp2 *s)
264{
265 int ret = 0;
266 u8 buf;
267 u8 cimax_init[34] = {
268 0x00,
269 0x00,
270 0x00,
271 0x00,
272 0x00,
273 0x44,
274 0x00,
275 0x00,
276 0x00,
277 0x00,
278 0x00,
279 0x00,
280 0x00,
281 0x00,
282 0x44,
283 0x00,
284 0x00,
285 0x00,
286 0x00,
287 0x00,
288 0x00,
289 0x00,
290 0x00,
291 0x02,
292 0x01,
293 0x00,
294 0x00,
295 0x00,
296 0x05,
297 0x00,
298 0x04,
299 0x00,
300 0x22,
301 0x00,
302 };
303
304 dev_dbg(&s->client->dev, "\n");
305
306 s->ca.owner = THIS_MODULE;
307 s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
308 s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
309 s->ca.read_cam_control = sp2_ci_read_cam_control;
310 s->ca.write_cam_control = sp2_ci_write_cam_control;
311 s->ca.slot_reset = sp2_ci_slot_reset;
312 s->ca.slot_shutdown = sp2_ci_slot_shutdown;
313 s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
314 s->ca.poll_slot_status = sp2_ci_poll_slot_status;
315 s->ca.data = s;
316 s->module_access_type = 0;
317
318
319 ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
320 if (ret)
321 goto err;
322
323
324 buf = 1;
325 ret = sp2_write_i2c(s, 0x1f, &buf, 1);
326 if (ret)
327 goto err;
328
329
330 ret = sp2_write_i2c(s, 0x18, &buf, 1);
331 if (ret)
332 goto err;
333
334 ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
335 if (ret)
336 goto err;
337
338 return 0;
339
340err:
341 dev_dbg(&s->client->dev, "init failed=%d\n", ret);
342 return ret;
343}
344
345static int sp2_exit(struct i2c_client *client)
346{
347 struct sp2 *s;
348
349 dev_dbg(&client->dev, "\n");
350
351 if (!client)
352 return 0;
353
354 s = i2c_get_clientdata(client);
355 if (!s)
356 return 0;
357
358 if (!s->ca.data)
359 return 0;
360
361 dvb_ca_en50221_release(&s->ca);
362
363 return 0;
364}
365
366static int sp2_probe(struct i2c_client *client,
367 const struct i2c_device_id *id)
368{
369 struct sp2_config *cfg = client->dev.platform_data;
370 struct sp2 *s;
371 int ret;
372
373 dev_dbg(&client->dev, "\n");
374
375 s = kzalloc(sizeof(*s), GFP_KERNEL);
376 if (!s) {
377 ret = -ENOMEM;
378 goto err;
379 }
380
381 s->client = client;
382 s->dvb_adap = cfg->dvb_adap;
383 s->priv = cfg->priv;
384 s->ci_control = cfg->ci_control;
385
386 i2c_set_clientdata(client, s);
387
388 ret = sp2_init(s);
389 if (ret)
390 goto err;
391
392 dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
393 return 0;
394err:
395 dev_dbg(&client->dev, "init failed=%d\n", ret);
396 kfree(s);
397
398 return ret;
399}
400
401static int sp2_remove(struct i2c_client *client)
402{
403 struct sp2 *s = i2c_get_clientdata(client);
404
405 dev_dbg(&client->dev, "\n");
406 sp2_exit(client);
407 kfree(s);
408 return 0;
409}
410
411static const struct i2c_device_id sp2_id[] = {
412 {"sp2", 0},
413 {}
414};
415MODULE_DEVICE_TABLE(i2c, sp2_id);
416
417static struct i2c_driver sp2_driver = {
418 .driver = {
419 .name = "sp2",
420 },
421 .probe = sp2_probe,
422 .remove = sp2_remove,
423 .id_table = sp2_id,
424};
425
426module_i2c_driver(sp2_driver);
427
428MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
429MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
430MODULE_LICENSE("GPL");
431