Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / dvb-frontends / sp2.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
4  *
5  * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
6  *
7  * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
8  * DVB-S2 CI card (cimax2) with following copyrights:
9  *
10  *  Copyright (C) 2009 NetUP Inc.
11  *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
12  *  Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
13  */
14
15 #include "sp2_priv.h"
16
17 static 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 = &reg,
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
53 static 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
92 static 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          * change module access type between IO space and attribute memory
105          * when needed
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         /* implementation of ci_op_cam is device specific */
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
146 int 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
153 int 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
160 int 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
167 int 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
174 int 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         /* RST on */
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         /* RST off */
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
206 int 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         /* not implemented */
213         return 0;
214 }
215
216 int 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         /* disable bypass and enable TS */
229         buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
230         return sp2_write_i2c(s, 0, &buf, 1);
231 }
232
233 int 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          * CAM module INSERT/REMOVE processing. Slow operation because of i2c
244          * transfers. Throttle read to one per sec.
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
263 static int sp2_init(struct sp2 *s)
264 {
265         int ret = 0;
266         u8 buf;
267         u8 cimax_init[34] = {
268                 0x00, /* module A control*/
269                 0x00, /* auto select mask high A */
270                 0x00, /* auto select mask low A */
271                 0x00, /* auto select pattern high A */
272                 0x00, /* auto select pattern low A */
273                 0x44, /* memory access time A, 600 ns */
274                 0x00, /* invert input A */
275                 0x00, /* RFU */
276                 0x00, /* RFU */
277                 0x00, /* module B control*/
278                 0x00, /* auto select mask high B */
279                 0x00, /* auto select mask low B */
280                 0x00, /* auto select pattern high B */
281                 0x00, /* auto select pattern low B */
282                 0x44, /* memory access time B, 600 ns */
283                 0x00, /* invert input B */
284                 0x00, /* RFU */
285                 0x00, /* RFU */
286                 0x00, /* auto select mask high Ext */
287                 0x00, /* auto select mask low Ext */
288                 0x00, /* auto select pattern high Ext */
289                 0x00, /* auto select pattern low Ext */
290                 0x00, /* RFU */
291                 0x02, /* destination - module A */
292                 0x01, /* power control reg, VCC power on */
293                 0x00, /* RFU */
294                 0x00, /* int status read only */
295                 0x00, /* Interrupt Mask Register */
296                 0x05, /* EXTINT=active-high, INT=push-pull */
297                 0x00, /* USCG1 */
298                 0x04, /* ack active low */
299                 0x00, /* LOCK = 0 */
300                 0x22, /* unknown */
301                 0x00, /* synchronization? */
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         /* initialize all regs */
319         ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
320         if (ret)
321                 goto err;
322
323         /* lock registers */
324         buf = 1;
325         ret = sp2_write_i2c(s, 0x1f, &buf, 1);
326         if (ret)
327                 goto err;
328
329         /* power on slots */
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
340 err:
341         dev_dbg(&s->client->dev, "init failed=%d\n", ret);
342         return ret;
343 }
344
345 static 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
366 static 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;
394 err:
395         dev_dbg(&client->dev, "init failed=%d\n", ret);
396         kfree(s);
397
398         return ret;
399 }
400
401 static 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
411 static const struct i2c_device_id sp2_id[] = {
412         {"sp2", 0},
413         {}
414 };
415 MODULE_DEVICE_TABLE(i2c, sp2_id);
416
417 static 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
426 module_i2c_driver(sp2_driver);
427
428 MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
429 MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
430 MODULE_LICENSE("GPL");