Merge tag 'trace-seq-buf-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/roste...
[cascardo/linux.git] / drivers / media / dvb-frontends / sp2.c
1 /*
2  * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
3  *
4  * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
5  *
6  * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
7  * DVB-S2 CI card (cimax2) with following copyrights:
8  *
9  *  Copyright (C) 2009 NetUP Inc.
10  *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
11  *  Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
12  *
13  *    This program is free software; you can redistribute it and/or modify
14  *    it under the terms of the GNU General Public License as published by
15  *    the Free Software Foundation; either version 2 of the License, or
16  *    (at your option) any later version.
17  *
18  *    This program is distributed in the hope that it will be useful,
19  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *    GNU General Public License for more details.
22  */
23
24 #include "sp2_priv.h"
25
26 static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
27 {
28         int ret;
29         struct i2c_client *client = s->client;
30         struct i2c_adapter *adap = client->adapter;
31         struct i2c_msg msg[] = {
32                 {
33                         .addr = client->addr,
34                         .flags = 0,
35                         .buf = &reg,
36                         .len = 1
37                 }, {
38                         .addr = client->addr,
39                         .flags  = I2C_M_RD,
40                         .buf = buf,
41                         .len = len
42                 }
43         };
44
45         ret = i2c_transfer(adap, msg, 2);
46
47         if (ret != 2) {
48                 dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
49                                 reg, ret);
50                 if (ret < 0)
51                         return ret;
52                 else
53                         return -EIO;
54         }
55
56         dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
57                                 client->addr, reg, buf[0]);
58
59         return 0;
60 }
61
62 static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
63 {
64         int ret;
65         u8 buffer[35];
66         struct i2c_client *client = s->client;
67         struct i2c_adapter *adap = client->adapter;
68         struct i2c_msg msg = {
69                 .addr = client->addr,
70                 .flags = 0,
71                 .buf = &buffer[0],
72                 .len = len + 1
73         };
74
75         if ((len + 1) > sizeof(buffer)) {
76                 dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
77                                 reg, len);
78                 return -EINVAL;
79         }
80
81         buffer[0] = reg;
82         memcpy(&buffer[1], buf, len);
83
84         ret = i2c_transfer(adap, &msg, 1);
85
86         if (ret != 1) {
87                 dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
88                                 reg, ret);
89                 if (ret < 0)
90                         return ret;
91                 else
92                         return -EIO;
93         }
94
95         return 0;
96 }
97
98 static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
99                         u8 read, int addr, u8 data)
100 {
101         struct sp2 *s = en50221->data;
102         u8 store;
103         int mem, ret;
104         int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
105
106         dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x",
107                         slot, acs, addr, data);
108
109         if (slot != 0)
110                 return -EINVAL;
111
112         /*
113          * change module access type between IO space and attribute memory
114          * when needed
115          */
116         if (s->module_access_type != acs) {
117                 ret = sp2_read_i2c(s, 0x00, &store, 1);
118
119                 if (ret)
120                         return ret;
121
122                 store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
123                 store |= acs;
124
125                 ret = sp2_write_i2c(s, 0x00, &store, 1);
126                 if (ret)
127                         return ret;
128         }
129
130         s->module_access_type = acs;
131
132         /* implementation of ci_op_cam is device specific */
133         if (ci_op_cam) {
134                 ret = ci_op_cam(s->priv, read, addr, data, &mem);
135         } else {
136                 dev_err(&s->client->dev, "callback not defined");
137                 return -EINVAL;
138         }
139
140         if (ret)
141                 return ret;
142
143         if (read) {
144                 dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x",
145                                 addr, mem);
146                 return mem;
147         } else {
148                 return 0;
149         }
150 }
151
152 int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
153                                 int slot, int addr)
154 {
155         return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
156                         SP2_CI_RD, addr, 0);
157 }
158
159 int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
160                                 int slot, int addr, u8 data)
161 {
162         return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
163                         SP2_CI_WR, addr, data);
164 }
165
166 int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
167                                 int slot, u8 addr)
168 {
169         return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
170                         SP2_CI_RD, addr, 0);
171 }
172
173 int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
174                                 int slot, u8 addr, u8 data)
175 {
176         return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
177                         SP2_CI_WR, addr, data);
178 }
179
180 int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
181 {
182         struct sp2 *s = en50221->data;
183         u8 buf;
184         int ret;
185
186         dev_dbg(&s->client->dev, "slot: %d\n", slot);
187
188         if (slot != 0)
189                 return -EINVAL;
190
191         /* RST on */
192         buf = SP2_MOD_CTL_RST;
193         ret = sp2_write_i2c(s, 0x00, &buf, 1);
194
195         if (ret)
196                 return ret;
197
198         usleep_range(500, 600);
199
200         /* RST off */
201         buf = 0x00;
202         ret = sp2_write_i2c(s, 0x00, &buf, 1);
203
204         if (ret)
205                 return ret;
206
207         msleep(1000);
208
209         return 0;
210 }
211
212 int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
213 {
214         struct sp2 *s = en50221->data;
215
216         dev_dbg(&s->client->dev, "slot:%d\n", slot);
217
218         /* not implemented */
219         return 0;
220 }
221
222 int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
223 {
224         struct sp2 *s = en50221->data;
225         u8 buf;
226
227         dev_dbg(&s->client->dev, "slot:%d\n", slot);
228
229         if (slot != 0)
230                 return -EINVAL;
231
232         sp2_read_i2c(s, 0x00, &buf, 1);
233
234         /* disable bypass and enable TS */
235         buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
236         return sp2_write_i2c(s, 0, &buf, 1);
237 }
238
239 int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
240                                 int slot, int open)
241 {
242         struct sp2 *s = en50221->data;
243         u8 buf[2];
244         int ret;
245
246         dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
247
248         /*
249          * CAM module INSERT/REMOVE processing. Slow operation because of i2c
250          * transfers. Throttle read to one per sec.
251          */
252         if (time_after(jiffies, s->next_status_checked_time)) {
253                 ret = sp2_read_i2c(s, 0x00, buf, 1);
254                 s->next_status_checked_time = jiffies + msecs_to_jiffies(1000);
255
256                 if (ret)
257                         return 0;
258
259                 if (buf[0] & SP2_MOD_CTL_DET)
260                         s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
261                                         DVB_CA_EN50221_POLL_CAM_READY;
262                 else
263                         s->status = 0;
264         }
265
266         return s->status;
267 }
268
269 static int sp2_init(struct sp2 *s)
270 {
271         int ret = 0;
272         u8 buf;
273         u8 cimax_init[34] = {
274                 0x00, /* module A control*/
275                 0x00, /* auto select mask high A */
276                 0x00, /* auto select mask low A */
277                 0x00, /* auto select pattern high A */
278                 0x00, /* auto select pattern low A */
279                 0x44, /* memory access time A, 600 ns */
280                 0x00, /* invert input A */
281                 0x00, /* RFU */
282                 0x00, /* RFU */
283                 0x00, /* module B control*/
284                 0x00, /* auto select mask high B */
285                 0x00, /* auto select mask low B */
286                 0x00, /* auto select pattern high B */
287                 0x00, /* auto select pattern low B */
288                 0x44, /* memory access time B, 600 ns */
289                 0x00, /* invert input B */
290                 0x00, /* RFU */
291                 0x00, /* RFU */
292                 0x00, /* auto select mask high Ext */
293                 0x00, /* auto select mask low Ext */
294                 0x00, /* auto select pattern high Ext */
295                 0x00, /* auto select pattern low Ext */
296                 0x00, /* RFU */
297                 0x02, /* destination - module A */
298                 0x01, /* power control reg, VCC power on */
299                 0x00, /* RFU */
300                 0x00, /* int status read only */
301                 0x00, /* Interrupt Mask Register */
302                 0x05, /* EXTINT=active-high, INT=push-pull */
303                 0x00, /* USCG1 */
304                 0x04, /* ack active low */
305                 0x00, /* LOCK = 0 */
306                 0x22, /* unknown */
307                 0x00, /* synchronization? */
308         };
309
310         dev_dbg(&s->client->dev, "\n");
311
312         s->ca.owner = THIS_MODULE;
313         s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
314         s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
315         s->ca.read_cam_control = sp2_ci_read_cam_control;
316         s->ca.write_cam_control = sp2_ci_write_cam_control;
317         s->ca.slot_reset = sp2_ci_slot_reset;
318         s->ca.slot_shutdown = sp2_ci_slot_shutdown;
319         s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
320         s->ca.poll_slot_status = sp2_ci_poll_slot_status;
321         s->ca.data = s;
322         s->module_access_type = 0;
323
324         /* initialize all regs */
325         ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
326         if (ret)
327                 goto err;
328
329         /* lock registers */
330         buf = 1;
331         ret = sp2_write_i2c(s, 0x1f, &buf, 1);
332         if (ret)
333                 goto err;
334
335         /* power on slots */
336         ret = sp2_write_i2c(s, 0x18, &buf, 1);
337         if (ret)
338                 goto err;
339
340         ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
341         if (ret)
342                 goto err;
343
344         return 0;
345
346 err:
347         dev_dbg(&s->client->dev, "init failed=%d\n", ret);
348         return ret;
349 }
350
351 static int sp2_exit(struct i2c_client *client)
352 {
353         struct sp2 *s;
354
355         dev_dbg(&client->dev, "\n");
356
357         if (client == NULL)
358                 return 0;
359
360         s = i2c_get_clientdata(client);
361         if (s == NULL)
362                 return 0;
363
364         if (s->ca.data == NULL)
365                 return 0;
366
367         dvb_ca_en50221_release(&s->ca);
368
369         return 0;
370 }
371
372 static int sp2_probe(struct i2c_client *client,
373                 const struct i2c_device_id *id)
374 {
375         struct sp2_config *cfg = client->dev.platform_data;
376         struct sp2 *s;
377         int ret;
378
379         dev_dbg(&client->dev, "\n");
380
381         s = kzalloc(sizeof(struct sp2), GFP_KERNEL);
382         if (!s) {
383                 ret = -ENOMEM;
384                 dev_err(&client->dev, "kzalloc() failed\n");
385                 goto err;
386         }
387
388         s->client = client;
389         s->dvb_adap = cfg->dvb_adap;
390         s->priv = cfg->priv;
391         s->ci_control = cfg->ci_control;
392
393         i2c_set_clientdata(client, s);
394
395         ret = sp2_init(s);
396         if (ret)
397                 goto err;
398
399         dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
400         return 0;
401 err:
402         dev_dbg(&client->dev, "init failed=%d\n", ret);
403         kfree(s);
404
405         return ret;
406 }
407
408 static int sp2_remove(struct i2c_client *client)
409 {
410         struct si2157 *s = i2c_get_clientdata(client);
411
412         dev_dbg(&client->dev, "\n");
413
414         sp2_exit(client);
415         if (s != NULL)
416                 kfree(s);
417
418         return 0;
419 }
420
421 static const struct i2c_device_id sp2_id[] = {
422         {"sp2", 0},
423         {}
424 };
425 MODULE_DEVICE_TABLE(i2c, sp2_id);
426
427 static struct i2c_driver sp2_driver = {
428         .driver = {
429                 .owner  = THIS_MODULE,
430                 .name   = "sp2",
431         },
432         .probe          = sp2_probe,
433         .remove         = sp2_remove,
434         .id_table       = sp2_id,
435 };
436
437 module_i2c_driver(sp2_driver);
438
439 MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
440 MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
441 MODULE_LICENSE("GPL");