]> err.no Git - linux-2.6/blob - drivers/media/dvb/dvb-usb/au6610.c
456b89f4f761573c2d2e33a7c1787b875a1739f2
[linux-2.6] / drivers / media / dvb / dvb-usb / au6610.c
1 /* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
2  *
3  * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
4  *
5  *      This program is free software; you can redistribute it and/or modify it
6  *      under the terms of the GNU General Public License as published by the Free
7  *      Software Foundation, version 2.
8  *
9  * see Documentation/dvb/README.dvb-usb for more information
10  */
11
12 #include "au6610.h"
13
14 #include "zl10353.h"
15 #include "qt1010.h"
16
17 /* debug */
18 static int dvb_usb_au6610_debug;
19 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
20 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
21
22 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
23                           u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
24 {
25         int ret;
26         u16 index;
27         u8 usb_buf[6]; /* enough for all known requests,
28                           read returns 5 and write 6 bytes */
29         switch (wlen) {
30         case 1:
31                 index = wbuf[0] << 8;
32                 break;
33         case 2:
34                 index = wbuf[0] << 8;
35                 index += wbuf[1];
36                 break;
37         default:
38                 warn("wlen = %x, aborting.", wlen);
39                 return -EINVAL;
40         }
41
42         ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
43                               USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
44                               sizeof(usb_buf), AU6610_USB_TIMEOUT);
45
46         if (ret < 0)
47                 return ret;
48
49         switch (operation) {
50         case AU6610_REQ_I2C_READ:
51         case AU6610_REQ_USB_READ:
52                 /* requested value is always 5th byte in buffer */
53                 rbuf[0] = usb_buf[4];
54         }
55
56         return ret;
57 }
58
59 static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
60                           u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
61 {
62         u8 request;
63         u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
64
65         if (wo) {
66                 request = AU6610_REQ_I2C_WRITE;
67         } else { /* rw */
68                 request = AU6610_REQ_I2C_READ;
69         }
70
71         return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
72 }
73
74
75 /* I2C */
76 static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
77                            int num)
78 {
79         struct dvb_usb_device *d = i2c_get_adapdata(adap);
80         int i;
81
82         if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
83                 return -EAGAIN;
84
85         if (num > 2)
86                 return -EINVAL;
87
88         for (i = 0; i < num; i++) {
89                 /* write/read request */
90                 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
91                         if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
92                                            msg[i].len, msg[i+1].buf,
93                                            msg[i+1].len) < 0)
94                                 break;
95                         i++;
96                 } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
97                                                msg[i].len, NULL, 0) < 0)
98                                 break;
99         }
100
101         mutex_unlock(&d->i2c_mutex);
102         return i;
103 }
104
105
106 static u32 au6610_i2c_func(struct i2c_adapter *adapter)
107 {
108         return I2C_FUNC_I2C;
109 }
110
111 static struct i2c_algorithm au6610_i2c_algo = {
112         .master_xfer   = au6610_i2c_xfer,
113         .functionality = au6610_i2c_func,
114 };
115
116 /* Callbacks for DVB USB */
117 static int au6610_identify_state(struct usb_device *udev,
118                                  struct dvb_usb_device_properties *props,
119                                  struct dvb_usb_device_description **desc,
120                                  int *cold)
121 {
122         *cold = 0;
123         return 0;
124 }
125
126 static struct zl10353_config au6610_zl10353_config = {
127         .demod_address = 0x1e,
128         .no_tuner = 1,
129         .parallel_ts = 1,
130 };
131
132 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
133 {
134         if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
135                                    &adap->dev->i2c_adap)) != NULL) {
136                 return 0;
137         }
138
139         return -EIO;
140 }
141
142 static struct qt1010_config au6610_qt1010_config = {
143         .i2c_address = 0xc4
144 };
145
146 static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
147 {
148         /* TODO FIXME; probably I2C gate.
149         QT1010 tuner does not respond before we write 0x1a to ZL10353 demod
150         register 0x62. This ought to be done somewhere in demod initialization.
151         This solution is temporary hack. */
152
153         u8 buf[2] = { 0x62, 0x1a };
154         struct i2c_msg msg = { .addr = au6610_zl10353_config.demod_address,
155                                .flags = 0, .buf = buf, .len = 2 };
156
157         if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
158                 printk(KERN_WARNING "au6610 tuner attach failed\n");
159                 return -EREMOTEIO;
160         }
161         return dvb_attach(qt1010_attach,
162                           adap->fe, &adap->dev->i2c_adap,
163                           &au6610_qt1010_config) == NULL ? -ENODEV : 0;
164 }
165
166 /* DVB USB Driver stuff */
167 static struct dvb_usb_device_properties au6610_properties;
168
169 static int au6610_probe(struct usb_interface *intf,
170                         const struct usb_device_id *id)
171 {
172         struct dvb_usb_device *d;
173         struct usb_host_interface *alt;
174         int ret;
175
176         if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
177                 return -ENODEV;
178
179         if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
180                 alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
181
182                 if (alt == NULL) {
183                         deb_rc("no alt found!\n");
184                         return -ENODEV;
185                 }
186                 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
187                                         alt->desc.bAlternateSetting);
188         }
189
190         return ret;
191 }
192
193
194 static struct usb_device_id au6610_table [] = {
195         { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
196         { }             /* Terminating entry */
197 };
198 MODULE_DEVICE_TABLE (usb, au6610_table);
199
200 static struct dvb_usb_device_properties au6610_properties = {
201         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
202         .usb_ctrl = DEVICE_SPECIFIC,
203         .size_of_priv     = 0,
204         .identify_state   = au6610_identify_state,
205         .num_adapters = 1,
206         .adapter = {
207                 {
208                         .frontend_attach  = au6610_zl10353_frontend_attach,
209                         .tuner_attach     = au6610_qt1010_tuner_attach,
210
211                         .stream = {
212                                 .type = USB_ISOC,
213                                 .count = 5,
214                                 .endpoint = 0x82,
215                                 .u = {
216                                         .isoc = {
217                                                 .framesperurb = 40,
218                                                 .framesize = 942,   /* maximum packet size */
219                                                 .interval = 1.25,   /* 125 us */
220                                         }
221                                 }
222                         },
223                 }
224         },
225         .i2c_algo = &au6610_i2c_algo,
226         .num_device_descs = 1,
227         .devices = {
228                 {
229                         "Sigmatek DVB-110 DVB-T USB2.0",
230                         { &au6610_table[0], NULL },
231                         { NULL },
232                 },
233         }
234 };
235
236 static struct usb_driver au6610_driver = {
237         .name       = "dvb_usb_au6610",
238         .probe      = au6610_probe,
239         .disconnect = dvb_usb_device_exit,
240         .id_table   = au6610_table,
241 };
242
243 /* module stuff */
244 static int __init au6610_module_init(void)
245 {
246         int ret;
247
248         if ((ret = usb_register(&au6610_driver))) {
249                 err("usb_register failed. Error number %d", ret);
250                 return ret;
251         }
252
253         return 0;
254 }
255
256 static void __exit au6610_module_exit(void)
257 {
258         /* deregister this driver from the USB subsystem */
259         usb_deregister(&au6610_driver);
260 }
261
262 module_init (au6610_module_init);
263 module_exit (au6610_module_exit);
264
265 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
266 MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
267 MODULE_VERSION("0.1");
268 MODULE_LICENSE("GPL");