f946b1b65b1dbcb7143ce63072673bc1b283f8bc
[~shefty/rdma-dev.git] / drivers / media / dvb / dvb-usb / az6007.c
1 /*
2  * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
3  *
4  * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
5  *
6  * This driver was made publicly available by Terratec, at:
7  *      http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
8  * The original driver's license is GPL, as declared with MODULE_LICENSE()
9  *
10  *  Driver modifiyed by Mauro Carvalho Chehab <mchehab@redhat.com> in order
11  *      to work with upstream drxk driver, and to fix some bugs.
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 under version 2 of the License.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  */
22
23 #include "drxk.h"
24 #include "mt2063.h"
25 #include "dvb_ca_en50221.h"
26 #include "dvb-usb.h"
27
28 #define DVB_USB_LOG_PREFIX "az6007"
29
30 /* HACK: Should be moved to the right place */
31 #define USB_PID_AZUREWAVE_6007          0x0ccd
32 #define USB_PID_TERRATEC_H7             0x10b4
33
34 /* debug */
35 int dvb_usb_az6007_debug;
36 module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
37 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
38                  DVB_USB_DEBUG_STATUS);
39
40 #define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
41 #define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
42 #define deb_rc(args...)   dprintk(dvb_usb_az6007_debug, 0x04, args)
43 #define deb_fe(args...)   dprintk(dvb_usb_az6007_debug, 0x08, args)
44
45 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
46
47 struct az6007_device_state {
48         struct                  dvb_ca_en50221 ca;
49         struct                  mutex ca_mutex;
50         u8                      power_state;
51
52         /* Due to DRX-K - probably need changes */
53         int                     (*gate_ctrl) (struct dvb_frontend *, int);
54         struct                  semaphore pll_mutex;
55         bool                    dont_attach_fe1;
56 };
57
58 static struct drxk_config terratec_h7_drxk = {
59         .adr = 0x29,
60         .single_master = 1,
61         .no_i2c_bridge = 0,
62         .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
63 };
64
65 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
66 {
67         struct dvb_usb_adapter *adap = fe->sec_priv;
68         struct az6007_device_state *st;
69         int status;
70
71         info("%s: %s", __func__, enable ? "enable" : "disable");
72
73         if (!adap)
74                 return -EINVAL;
75
76         st = adap->priv;
77
78         if (!st)
79                 return -EINVAL;
80
81         if (enable) {
82 #if 0
83                 down(&st->pll_mutex);
84 #endif
85                 status = st->gate_ctrl(fe, 1);
86         } else {
87 #if 0
88                 status = st->gate_ctrl(fe, 0);
89 #endif
90                 up(&st->pll_mutex);
91         }
92         return status;
93 }
94
95 static struct mt2063_config az6007_mt2063_config = {
96         .tuner_address = 0x60,
97         .refclock = 36125000,
98 };
99
100 /* check for mutex FIXME */
101 static int az6007_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
102                             u16 index, u8 *b, int blen)
103 {
104         int ret = -1;
105
106         ret = usb_control_msg(d->udev,
107                               usb_rcvctrlpipe(d->udev, 0),
108                               req,
109                               USB_TYPE_VENDOR | USB_DIR_IN,
110                               value, index, b, blen, 5000);
111
112         if (ret < 0) {
113                 warn("usb in operation failed. (%d)", ret);
114                 return -EIO;
115         }
116
117         deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
118                  index);
119         debug_dump(b, blen, deb_xfer);
120
121         return ret;
122 }
123
124 static int az6007_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
125                              u16 index, u8 *b, int blen)
126 {
127         int ret;
128
129         deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
130                  index);
131         debug_dump(b, blen, deb_xfer);
132
133         if (blen > 64) {
134                 printk(KERN_ERR
135                        "az6007: doesn't suport I2C transactions longer than 64 bytes\n");
136                 return -EOPNOTSUPP;
137         }
138
139         ret = usb_control_msg(d->udev,
140                               usb_sndctrlpipe(d->udev, 0),
141                               req,
142                               USB_TYPE_VENDOR | USB_DIR_OUT,
143                               value, index, b, blen, 5000);
144         if (ret != blen) {
145                 warn("usb out operation failed. (%d)", ret);
146                 return -EIO;
147         }
148
149         return 0;
150 }
151
152 static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
153 {
154         return 0;
155 }
156
157 /* keys for the enclosed remote control */
158 static struct rc_map_table rc_map_az6007_table[] = {
159         {0x0001, KEY_1},
160         {0x0002, KEY_2},
161 };
162
163 /* remote control stuff (does not work with my box) */
164 static int az6007_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
165 {
166         return 0;
167 #if 0
168         u8 key[10];
169         int i;
170
171         /* remove the following return to enabled remote querying */
172
173         az6007_usb_in_op(d, READ_REMOTE_REQ, 0, 0, key, 10);
174
175         deb_rc("remote query key: %x %d\n", key[1], key[1]);
176
177         if (key[1] == 0x44) {
178                 *state = REMOTE_NO_KEY_PRESSED;
179                 return 0;
180         }
181
182         for (i = 0; i < ARRAY_SIZE(az6007_rc_keys); i++)
183                 if (az6007_rc_keys[i].custom == key[1]) {
184                         *state = REMOTE_KEY_PRESSED;
185                         *event = az6007_rc_keys[i].event;
186                         break;
187                 }
188         return 0;
189 #endif
190 }
191
192 /*
193 int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
194 {
195         u8 v = onoff;
196         return az6007_usb_out_op(d,0xBC,v,3,NULL,1);
197 }
198 */
199
200 static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
201 {
202         az6007_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
203         return 0;
204 }
205
206 static int az6007_frontend_poweron(struct dvb_usb_adapter *adap)
207 {
208         int ret;
209         u8 req;
210         u16 value;
211         u16 index;
212         int blen;
213
214         info("az6007_frontend_poweron adap=%p adap->dev=%p", adap, adap->dev);
215
216         req = 0xBC;
217         value = 1;              /* power on */
218         index = 3;
219         blen = 0;
220
221         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
222         if (ret != 0) {
223                 err("az6007_frontend_poweron failed!!!");
224                 return -EIO;
225         }
226
227         msleep_interruptible(200);
228
229         req = 0xBC;
230         value = 0;              /* power off */
231         index = 3;
232         blen = 0;
233
234         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
235         if (ret != 0) {
236                 err("az6007_frontend_poweron failed!!!");
237                 return -EIO;
238         }
239
240         msleep_interruptible(200);
241
242         req = 0xBC;
243         value = 1;              /* power on */
244         index = 3;
245         blen = 0;
246
247         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
248         if (ret != 0) {
249                 err("az6007_frontend_poweron failed!!!");
250                 return -EIO;
251         }
252         info("az6007_frontend_poweron: OK");
253
254         return 0;
255 }
256
257 static int az6007_frontend_reset(struct dvb_usb_adapter *adap)
258 {
259         int ret;
260         u8 req;
261         u16 value;
262         u16 index;
263         int blen;
264
265         info("az6007_frontend_reset adap=%p adap->dev=%p", adap, adap->dev);
266
267         /* reset demodulator */
268         req = 0xC0;
269         value = 1;              /* high */
270         index = 3;
271         blen = 0;
272         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
273         if (ret != 0) {
274                 err("az6007_frontend_reset failed 1 !!!");
275                 return -EIO;
276         }
277
278         req = 0xC0;
279         value = 0;              /* low */
280         index = 3;
281         blen = 0;
282         msleep_interruptible(200);
283         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
284         if (ret != 0) {
285                 err("az6007_frontend_reset failed 2 !!!");
286                 return -EIO;
287         }
288         msleep_interruptible(200);
289         req = 0xC0;
290         value = 1;              /* high */
291         index = 3;
292         blen = 0;
293
294         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
295         if (ret != 0) {
296                 err("az6007_frontend_reset failed 3 !!!");
297                 return -EIO;
298         }
299
300         msleep_interruptible(200);
301
302         info("reset az6007 frontend");
303
304         return 0;
305 }
306
307 static int az6007_led_on_off(struct usb_interface *intf, int onoff)
308 {
309         int ret = -1;
310         u8 req;
311         u16 value;
312         u16 index;
313         int blen;
314         /* TS through */
315         req = 0xBC;
316         value = onoff;
317         index = 0;
318         blen = 0;
319
320         ret = usb_control_msg(interface_to_usbdev(intf),
321                               usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
322                               req,
323                               USB_TYPE_VENDOR | USB_DIR_OUT,
324                               value, index, NULL, blen, 2000);
325
326         if (ret < 0) {
327                 warn("usb in operation failed. (%d)", ret);
328                 ret = -EIO;
329         } else
330                 ret = 0;
331
332         deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
333                  index);
334
335         return ret;
336 }
337
338 static int az6007_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)
339 {
340         int ret;
341         u8 req;
342         u16 value;
343         u16 index;
344         int blen;
345         /* TS through */
346         req = 0xC7;
347         value = onoff;
348         index = 0;
349         blen = 0;
350
351         ret = az6007_usb_out_op(adap->dev, req, value, index, NULL, blen);
352         if (ret != 0)
353                 return -EIO;
354         return 0;
355 }
356
357 static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
358 {
359         struct az6007_device_state *st = adap->priv;
360
361         int result;
362
363         BUG_ON(!st);
364
365         az6007_frontend_poweron(adap);
366         az6007_frontend_reset(adap);
367
368         info("az6007_frontend_attach: drxk");
369
370         adap->fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
371                               &adap->dev->i2c_adap, &adap->fe2);
372         if (!adap->fe) {
373                 result = -EINVAL;
374                 goto out_free;
375         }
376
377         info("Setting hacks");
378
379         /* FIXME: do we need a pll semaphore? */
380         adap->fe->sec_priv = adap;
381         sema_init(&st->pll_mutex, 1);
382         st->gate_ctrl = adap->fe->ops.i2c_gate_ctrl;
383         adap->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
384         adap->fe2->id = 1;
385
386         info("az6007_frontend_attach: mt2063");
387         /* Attach mt2063 to DVB-C frontend */
388         if (adap->fe->ops.i2c_gate_ctrl)
389                 adap->fe->ops.i2c_gate_ctrl(adap->fe, 1);
390         if (!dvb_attach(mt2063_attach, adap->fe, &az6007_mt2063_config,
391                         &adap->dev->i2c_adap)) {
392                 result = -EINVAL;
393
394                 goto out_free;
395         }
396         if (adap->fe->ops.i2c_gate_ctrl)
397                 adap->fe->ops.i2c_gate_ctrl(adap->fe, 0);
398
399         /* Hack - needed due to drxk */
400         adap->fe2->tuner_priv = adap->fe->tuner_priv;
401         memcpy(&adap->fe2->ops.tuner_ops,
402                &adap->fe->ops.tuner_ops, sizeof(adap->fe->ops.tuner_ops));
403         return 0;
404
405 out_free:
406         if (adap->fe)
407                 dvb_frontend_detach(adap->fe);
408         adap->fe = NULL;
409         adap->fe2 = NULL;
410
411         return result;
412 }
413
414 static struct dvb_usb_device_properties az6007_properties;
415
416 static void az6007_usb_disconnect(struct usb_interface *intf)
417 {
418         dvb_usb_device_exit(intf);
419 }
420
421 /* I2C */
422 static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
423                            int num)
424 {
425         struct dvb_usb_device *d = i2c_get_adapdata(adap);
426         int i, j, len;
427         int ret = 0;
428         u16 index;
429         u16 value;
430         int length;
431         u8 req, addr;
432         u8 data[512];
433
434         if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
435                 return -EAGAIN;
436
437         for (i = 0; i < num; i++) {
438                 addr = msgs[i].addr << 1;
439                 if (((i + 1) < num)
440                     && (msgs[i].len == 1)
441                     && (!msgs[i].flags & I2C_M_RD)
442                     && (msgs[i + 1].flags & I2C_M_RD)
443                     && (msgs[i].addr == msgs[i + 1].addr)) {
444                         /*
445                          * A write + read xfer for the same address, where
446                          * the first xfer has just 1 byte length.
447                          * Need to join both into one operation
448                          */
449                         if (dvb_usb_az6007_debug & 2)
450                                 printk(KERN_DEBUG
451                                        "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
452                                        addr, msgs[i].len, msgs[i + 1].len);
453                         req = 0xb9;
454                         index = msgs[i].buf[0];
455                         value = addr | (1 << 8);
456                         length = 6 + msgs[i + 1].len;
457                         len = msgs[i + 1].len;
458                         ret = az6007_usb_in_op(d, req, value, index, data,
459                                                length);
460                         if (ret >= len) {
461                                 for (j = 0; j < len; j++) {
462                                         msgs[i + 1].buf[j] = data[j + 5];
463                                         if (dvb_usb_az6007_debug & 2)
464                                                 printk(KERN_CONT
465                                                        "0x%02x ",
466                                                        msgs[i + 1].buf[j]);
467                                 }
468                         } else
469                                 ret = -EIO;
470                         i++;
471                 } else if (!(msgs[i].flags & I2C_M_RD)) {
472                         /* write bytes */
473                         if (dvb_usb_az6007_debug & 2)
474                                 printk(KERN_DEBUG
475                                        "az6007 I2C xfer write addr=0x%x len=%d: ",
476                                        addr, msgs[i].len);
477                         req = 0xbd;
478                         index = msgs[i].buf[0];
479                         value = addr | (1 << 8);
480                         length = msgs[i].len - 1;
481                         len = msgs[i].len - 1;
482                         if (dvb_usb_az6007_debug & 2)
483                                 printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
484                         for (j = 0; j < len; j++) {
485                                 data[j] = msgs[i].buf[j + 1];
486                                 if (dvb_usb_az6007_debug & 2)
487                                         printk(KERN_CONT "0x%02x ", data[j]);
488                         }
489                         ret =  az6007_usb_out_op(d, req, value, index, data,
490                                                  length);
491                 } else {
492                         /* read bytes */
493                         if (dvb_usb_az6007_debug & 2)
494                                 printk(KERN_DEBUG
495                                        "az6007 I2C xfer read addr=0x%x len=%d: ",
496                                        addr, msgs[i].len);
497                         req = 0xb9;
498                         index = msgs[i].buf[0];
499                         value = addr;
500                         length = msgs[i].len + 6;
501                         len = msgs[i].len;
502                         ret = az6007_usb_in_op(d, req, value, index, data,
503                                                length);
504                         for (j = 0; j < len; j++) {
505                                 msgs[i].buf[j] = data[j + 5];
506                                 if (dvb_usb_az6007_debug & 2)
507                                         printk(KERN_CONT
508                                                "0x%02x ", data[j + 5]);
509                         }
510                 }
511                 if (dvb_usb_az6007_debug & 2)
512                         printk(KERN_CONT "\n");
513                 if (ret < 0)
514                         goto err;
515         }
516 err:
517         mutex_unlock(&d->i2c_mutex);
518
519         if (ret < 0) {
520                 info("%s ERROR: %i\n", __func__, ret);
521                 return ret;
522         }
523         return num;
524 }
525
526 static u32 az6007_i2c_func(struct i2c_adapter *adapter)
527 {
528         return I2C_FUNC_I2C;
529 }
530
531 static struct i2c_algorithm az6007_i2c_algo = {
532         .master_xfer = az6007_i2c_xfer,
533         .functionality = az6007_i2c_func,
534 };
535
536 int az6007_identify_state(struct usb_device *udev,
537                           struct dvb_usb_device_properties *props,
538                           struct dvb_usb_device_description **desc, int *cold)
539 {
540         u8 b[16];
541         s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
542                                   0xb7, USB_TYPE_VENDOR | USB_DIR_IN, 6, 0, b,
543                                   6, USB_CTRL_GET_TIMEOUT);
544
545         info("FW GET_VERSION length: %d", ret);
546
547         *cold = ret <= 0;
548
549         info("cold: %d", *cold);
550         return 0;
551 }
552
553 static int az6007_usb_probe(struct usb_interface *intf,
554                             const struct usb_device_id *id)
555 {
556         az6007_led_on_off(intf, 0);
557
558         return dvb_usb_device_init(intf, &az6007_properties,
559                                    THIS_MODULE, NULL, adapter_nr);
560 }
561
562 static struct usb_device_id az6007_usb_table[] = {
563         {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
564         {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
565         {0},
566 };
567
568 MODULE_DEVICE_TABLE(usb, az6007_usb_table);
569
570 static struct dvb_usb_device_properties az6007_properties = {
571         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
572         .usb_ctrl = CYPRESS_FX2,
573         .firmware            = "dvb-usb-az6007-03.fw",
574         .no_reconnect        = 1,
575
576         .identify_state         = az6007_identify_state,
577         .num_adapters = 1,
578         .adapter = {
579                 {
580                         /* .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, */
581                         .streaming_ctrl   = az6007_streaming_ctrl,
582                         .frontend_attach  = az6007_frontend_attach,
583
584                         /* parameter for the MPEG2-data transfer */
585                         .stream = {
586                                 .type = USB_BULK,
587                                 .count = 10,
588                                 .endpoint = 0x02,
589                                 .u = {
590                                         .bulk = {
591                                                 .buffersize = 4096,
592                                         }
593                                 }
594                         },
595                         .size_of_priv     = sizeof(struct az6007_device_state),
596                 }
597         },
598         /* .power_ctrl       = az6007_power_ctrl, */
599         .read_mac_address = az6007_read_mac_addr,
600
601         .rc.legacy = {
602                 .rc_map_table  = rc_map_az6007_table,
603                 .rc_map_size  = ARRAY_SIZE(rc_map_az6007_table),
604                 .rc_interval      = 400,
605                 .rc_query         = az6007_rc_query,
606         },
607         .i2c_algo         = &az6007_i2c_algo,
608
609         .num_device_descs = 2,
610         .devices = {
611                 { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
612                   .cold_ids = { &az6007_usb_table[0], NULL },
613                   .warm_ids = { NULL },
614                 },
615                 { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
616                   .cold_ids = { &az6007_usb_table[1], NULL },
617                   .warm_ids = { NULL },
618                 },
619                 { NULL },
620         }
621 };
622
623 /* usb specific object needed to register this driver with the usb subsystem */
624 static struct usb_driver az6007_usb_driver = {
625         .name           = "dvb_usb_az6007",
626         .probe          = az6007_usb_probe,
627         .disconnect = dvb_usb_device_exit,
628         /* .disconnect  = az6007_usb_disconnect, */
629         .id_table       = az6007_usb_table,
630 };
631
632 /* module stuff */
633 static int __init az6007_usb_module_init(void)
634 {
635         int result;
636         info("az6007 usb module init");
637
638         result = usb_register(&az6007_usb_driver);
639         if (result) {
640                 err("usb_register failed. (%d)", result);
641                 return result;
642         }
643
644         return 0;
645 }
646
647 static void __exit az6007_usb_module_exit(void)
648 {
649         /* deregister this driver from the USB subsystem */
650         info("az6007 usb module exit");
651         usb_deregister(&az6007_usb_driver);
652 }
653
654 module_init(az6007_usb_module_init);
655 module_exit(az6007_usb_module_exit);
656
657 MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
658 MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
659 MODULE_VERSION("1.1");
660 MODULE_LICENSE("GPL");