Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[pandora-kernel.git] / drivers / media / dvb / dvb-usb / ce6230.c
1 /*
2  * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
3  *
4  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
5  *
6  *    This program is free software; you can redistribute it and/or modify
7  *    it under the terms of the GNU General Public License as published by
8  *    the Free Software Foundation; either version 2 of the License, or
9  *    (at your option) any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License
17  *    along with this program; if not, write to the Free Software
18  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include "ce6230.h"
23 #include "zl10353.h"
24 #include "mxl5005s.h"
25
26 /* debug */
27 static int dvb_usb_ce6230_debug;
28 module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
29 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
30 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
31
32 static struct zl10353_config ce6230_zl10353_config;
33
34 static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
35 {
36         int ret;
37         unsigned int pipe;
38         u8 request;
39         u8 requesttype;
40         u16 value;
41         u16 index;
42         u8 *buf;
43
44         request = req->cmd;
45         value = req->value;
46         index = req->index;
47
48         switch (req->cmd) {
49         case I2C_READ:
50         case DEMOD_READ:
51         case REG_READ:
52                 requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
53                 break;
54         case I2C_WRITE:
55         case DEMOD_WRITE:
56         case REG_WRITE:
57                 requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
58                 break;
59         default:
60                 err("unknown command:%02x", req->cmd);
61                 ret = -EPERM;
62                 goto error;
63         }
64
65         buf = kmalloc(req->data_len, GFP_KERNEL);
66         if (!buf) {
67                 ret = -ENOMEM;
68                 goto error;
69         }
70
71         if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
72                 /* write */
73                 memcpy(buf, req->data, req->data_len);
74                 pipe = usb_sndctrlpipe(udev, 0);
75         } else {
76                 /* read */
77                 pipe = usb_rcvctrlpipe(udev, 0);
78         }
79
80         msleep(1); /* avoid I2C errors */
81
82         ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
83                                 buf, req->data_len, CE6230_USB_TIMEOUT);
84
85         ce6230_debug_dump(request, requesttype, value, index, buf,
86                 req->data_len, deb_xfer);
87
88         if (ret < 0)
89                 deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
90         else
91                 ret = 0;
92
93         /* read request, copy returned data to return buf */
94         if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
95                 memcpy(req->data, buf, req->data_len);
96
97         kfree(buf);
98 error:
99         return ret;
100 }
101
102 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
103 {
104         return ce6230_rw_udev(d->udev, req);
105 }
106
107 /* I2C */
108 static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
109                            int num)
110 {
111         struct dvb_usb_device *d = i2c_get_adapdata(adap);
112         int i = 0;
113         struct req_t req;
114         int ret = 0;
115         memset(&req, 0, sizeof(req));
116
117         if (num > 2)
118                 return -EINVAL;
119
120         if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
121                 return -EAGAIN;
122
123         while (i < num) {
124                 if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
125                         if (msg[i].addr ==
126                                 ce6230_zl10353_config.demod_address) {
127                                 req.cmd = DEMOD_READ;
128                                 req.value = msg[i].addr >> 1;
129                                 req.index = msg[i].buf[0];
130                                 req.data_len = msg[i+1].len;
131                                 req.data = &msg[i+1].buf[0];
132                                 ret = ce6230_ctrl_msg(d, &req);
133                         } else {
134                                 err("i2c read not implemented");
135                                 ret = -EPERM;
136                         }
137                         i += 2;
138                 } else {
139                         if (msg[i].addr ==
140                                 ce6230_zl10353_config.demod_address) {
141                                 req.cmd = DEMOD_WRITE;
142                                 req.value = msg[i].addr >> 1;
143                                 req.index = msg[i].buf[0];
144                                 req.data_len = msg[i].len-1;
145                                 req.data = &msg[i].buf[1];
146                                 ret = ce6230_ctrl_msg(d, &req);
147                         } else {
148                                 req.cmd = I2C_WRITE;
149                                 req.value = 0x2000 + (msg[i].addr >> 1);
150                                 req.index = 0x0000;
151                                 req.data_len = msg[i].len;
152                                 req.data = &msg[i].buf[0];
153                                 ret = ce6230_ctrl_msg(d, &req);
154                         }
155                         i += 1;
156                 }
157                 if (ret)
158                         break;
159         }
160
161         mutex_unlock(&d->i2c_mutex);
162         return ret ? ret : i;
163 }
164
165 static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
166 {
167         return I2C_FUNC_I2C;
168 }
169
170 static struct i2c_algorithm ce6230_i2c_algo = {
171         .master_xfer   = ce6230_i2c_xfer,
172         .functionality = ce6230_i2c_func,
173 };
174
175 /* Callbacks for DVB USB */
176 static struct zl10353_config ce6230_zl10353_config = {
177         .demod_address = 0x1e,
178         .adc_clock = 450000,
179         .if2 = 45700,
180         .no_tuner = 1,
181         .parallel_ts = 1,
182         .clock_ctl_1 = 0x34,
183         .pll_0 = 0x0e,
184 };
185
186 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
187 {
188         deb_info("%s:\n", __func__);
189         adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
190                 &adap->dev->i2c_adap);
191         if (adap->fe == NULL)
192                 return -ENODEV;
193         return 0;
194 }
195
196 static struct mxl5005s_config ce6230_mxl5003s_config = {
197         .i2c_address     = 0xc6,
198         .if_freq         = IF_FREQ_4570000HZ,
199         .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
200         .agc_mode        = MXL_SINGLE_AGC,
201         .tracking_filter = MXL_TF_DEFAULT,
202         .rssi_enable     = MXL_RSSI_ENABLE,
203         .cap_select      = MXL_CAP_SEL_ENABLE,
204         .div_out         = MXL_DIV_OUT_4,
205         .clock_out       = MXL_CLOCK_OUT_DISABLE,
206         .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
207         .top             = MXL5005S_TOP_25P2,
208         .mod_mode        = MXL_DIGITAL_MODE,
209         .if_mode         = MXL_ZERO_IF,
210         .AgcMasterByte   = 0x00,
211 };
212
213 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
214 {
215         int ret;
216         deb_info("%s:\n", __func__);
217         ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
218                         &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
219         return ret;
220 }
221
222 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
223 {
224         int ret;
225         deb_info("%s: onoff:%d\n", __func__, onoff);
226
227         /* InterfaceNumber 1 / AlternateSetting 0     idle
228            InterfaceNumber 1 / AlternateSetting 1     streaming */
229         ret = usb_set_interface(d->udev, 1, onoff);
230         if (ret)
231                 err("usb_set_interface failed with error:%d", ret);
232
233         return ret;
234 }
235
236 /* DVB USB Driver stuff */
237 static struct dvb_usb_device_properties ce6230_properties;
238
239 static int ce6230_probe(struct usb_interface *intf,
240                         const struct usb_device_id *id)
241 {
242         int ret = 0;
243         struct dvb_usb_device *d = NULL;
244
245         deb_info("%s: interface:%d\n", __func__,
246                 intf->cur_altsetting->desc.bInterfaceNumber);
247
248         if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
249                 ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
250                         &d, adapter_nr);
251                 if (ret)
252                         err("init failed with error:%d\n", ret);
253         }
254
255         return ret;
256 }
257
258 static struct usb_device_id ce6230_table[] = {
259         { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
260         { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
261         { } /* Terminating entry */
262 };
263 MODULE_DEVICE_TABLE(usb, ce6230_table);
264
265 static struct dvb_usb_device_properties ce6230_properties = {
266         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
267
268         .usb_ctrl = DEVICE_SPECIFIC,
269         .no_reconnect = 1,
270
271         .size_of_priv = 0,
272
273         .num_adapters = 1,
274         .adapter = {
275                 {
276                         .frontend_attach  = ce6230_zl10353_frontend_attach,
277                         .tuner_attach     = ce6230_mxl5003s_tuner_attach,
278                         .stream = {
279                                 .type = USB_BULK,
280                                 .count = 6,
281                                 .endpoint = 0x82,
282                                 .u = {
283                                         .bulk = {
284                                                 .buffersize = (16*512),
285                                         }
286                                 }
287                         },
288                 }
289         },
290
291         .power_ctrl = ce6230_power_ctrl,
292
293         .i2c_algo = &ce6230_i2c_algo,
294
295         .num_device_descs = 2,
296         .devices = {
297                 {
298                         .name = "Intel CE9500 reference design",
299                         .cold_ids = {NULL},
300                         .warm_ids = {&ce6230_table[0], NULL},
301                 },
302                 {
303                         .name = "AVerMedia A310 USB 2.0 DVB-T tuner",
304                         .cold_ids = {NULL},
305                         .warm_ids = {&ce6230_table[1], NULL},
306                 },
307         }
308 };
309
310 static struct usb_driver ce6230_driver = {
311         .name       = "dvb_usb_ce6230",
312         .probe      = ce6230_probe,
313         .disconnect = dvb_usb_device_exit,
314         .id_table   = ce6230_table,
315 };
316
317 /* module stuff */
318 static int __init ce6230_module_init(void)
319 {
320         int ret;
321         deb_info("%s:\n", __func__);
322         ret = usb_register(&ce6230_driver);
323         if (ret)
324                 err("usb_register failed with error:%d", ret);
325
326         return ret;
327 }
328
329 static void __exit ce6230_module_exit(void)
330 {
331         deb_info("%s:\n", __func__);
332         /* deregister this driver from the USB subsystem */
333         usb_deregister(&ce6230_driver);
334 }
335
336 module_init(ce6230_module_init);
337 module_exit(ce6230_module_exit);
338
339 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
340 MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
341 MODULE_LICENSE("GPL");