blob: 1c0160dfc2af2d8a4c8caec2f5ad0aa6746cca95 [file] [log] [blame]
Antti Palosaari5decdd22006-11-05 16:05:38 -03001/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
2 *
Antti Palosaari4c7e3ea2007-01-21 15:56:10 -03003 * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
Antti Palosaari5decdd22006-11-05 16:05:38 -03004 *
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 */
18static int dvb_usb_au6610_debug;
19module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
20MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
21
Antti Palosaari5decdd22006-11-05 16:05:38 -030022static 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, read returns 5 and write 6 bytes */
28
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
59static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
60{
61 u8 request;
62 u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
63
64 if (wo) {
65 request = AU6610_REQ_I2C_WRITE;
66 } else { /* rw */
67 request = AU6610_REQ_I2C_READ;
68 }
69
70 return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
71}
72
73
74/* I2C */
75static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
76{
77 struct dvb_usb_device *d = i2c_get_adapdata(adap);
78 int i;
79
80 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
81 return -EAGAIN;
82
83 if (num > 2)
84 return -EINVAL;
85
86 for (i = 0; i < num; i++) {
87 /* write/read request */
88 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
89 if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
90 msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
91 break;
92 i++;
93 } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
94 msg[i].len, NULL, 0) < 0)
95 break;
96 }
97
98 mutex_unlock(&d->i2c_mutex);
99 return i;
100}
101
102
103static u32 au6610_i2c_func(struct i2c_adapter *adapter)
104{
105 return I2C_FUNC_I2C;
106}
107
108static struct i2c_algorithm au6610_i2c_algo = {
109 .master_xfer = au6610_i2c_xfer,
110 .functionality = au6610_i2c_func,
111};
112
113/* Callbacks for DVB USB */
114static int au6610_identify_state(struct usb_device *udev,
115 struct dvb_usb_device_properties *props,
116 struct dvb_usb_device_description **desc,
117 int *cold)
118{
119 *cold = 0;
120 return 0;
121}
122
123static struct zl10353_config au6610_zl10353_config = {
124 .demod_address = 0x1e,
125 .no_tuner = 1,
126 .parallel_ts = 1,
127};
128
Antti Palosaari5decdd22006-11-05 16:05:38 -0300129static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
130{
131 if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
132 &adap->dev->i2c_adap)) != NULL) {
133 return 0;
134 }
135
136 return -EIO;
137}
138
Antti Palosaari4c7e3ea2007-01-21 15:56:10 -0300139static struct qt1010_config au6610_qt1010_config = {
140 .i2c_address = 0xc4
141};
142
143static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
144{
145 /* TODO FIXME; probably I2C gate.
146 QT1010 tuner does not respond before we write 0x1a to ZL10353 demodulator
147 register 0x62. This ought to be done somewhere in demodulator initialization.
148 This solution is temporary hack. */
149 u8 buf[2] = { 0x62, 0x1a };
150 struct i2c_msg msg = {
151 .addr = au6610_zl10353_config.demod_address, .flags = 0, .buf = buf, .len = 2
152 };
153 if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
154 printk(KERN_WARNING "au6610 tuner attach failed\n");
155 return -EREMOTEIO;
156 }
157 return dvb_attach(qt1010_attach,
158 adap->fe, &adap->dev->i2c_adap,
159 &au6610_qt1010_config) == NULL ? -ENODEV : 0;
160}
161
Antti Palosaari5decdd22006-11-05 16:05:38 -0300162/* DVB USB Driver stuff */
163static struct dvb_usb_device_properties au6610_properties;
164
165static int au6610_probe(struct usb_interface *intf, const struct usb_device_id *id)
166{
167 struct dvb_usb_device *d;
168 struct usb_host_interface *alt;
169 int ret;
170
171 if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
172 return -ENODEV;
173
174 if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
175 alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
176
177 if (alt == NULL) {
178 deb_rc("no alt found!\n");
179 return -ENODEV;
180 }
181 ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
182 alt->desc.bAlternateSetting);
183 }
184
185 return ret;
186}
187
188
189static struct usb_device_id au6610_table [] = {
190 { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
191 { } /* Terminating entry */
192};
193MODULE_DEVICE_TABLE (usb, au6610_table);
194
195static struct dvb_usb_device_properties au6610_properties = {
196 .caps = DVB_USB_IS_AN_I2C_ADAPTER,
197 .usb_ctrl = DEVICE_SPECIFIC,
198 .size_of_priv = 0,
199 .identify_state = au6610_identify_state,
200 .num_adapters = 1,
201 .adapter = {
202 {
203 .frontend_attach = au6610_zl10353_frontend_attach,
Antti Palosaari4c7e3ea2007-01-21 15:56:10 -0300204 .tuner_attach = au6610_qt1010_tuner_attach,
Antti Palosaari5decdd22006-11-05 16:05:38 -0300205
206 .stream = {
207 .type = USB_ISOC,
208 .count = 5,
209 .endpoint = 0x82,
210 .u = {
211 .isoc = {
212 .framesperurb = 40,
213 .framesize = 942, /* maximum packet size */
214 .interval = 1.25, /* 125 us */
215 }
216 }
217 },
218 }
219 },
220 .i2c_algo = &au6610_i2c_algo,
221 .num_device_descs = 1,
222 .devices = {
223 {
224 "Sigmatek DVB-110 DVB-T USB2.0",
225 { &au6610_table[0], NULL },
226 { NULL },
227 },
228 }
229};
230
231static struct usb_driver au6610_driver = {
232 .name = "dvb_usb_au6610",
233 .probe = au6610_probe,
234 .disconnect = dvb_usb_device_exit,
235 .id_table = au6610_table,
236};
237
238/* module stuff */
239static int __init au6610_module_init(void)
240{
241 int ret;
242
243 if ((ret = usb_register(&au6610_driver))) {
244 err("usb_register failed. Error number %d", ret);
245 return ret;
246 }
247
248 return 0;
249}
250
251static void __exit au6610_module_exit(void)
252{
253 /* deregister this driver from the USB subsystem */
254 usb_deregister(&au6610_driver);
255}
256
257module_init (au6610_module_init);
258module_exit (au6610_module_exit);
259
260MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
261MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
262MODULE_VERSION("0.1");
263MODULE_LICENSE("GPL");