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