Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / media / dvb / dvb-usb / dw2102.c
1 /* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card
2 *
3 * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
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
7 *       Free Software Foundation, version 2.
8 *
9 * see Documentation/dvb/README.dvb-usb for more information
10 */
11 #include <linux/version.h>
12 #include "dw2102.h"
13 #include "stv0299.h"
14 #include "z0194a.h"
15
16 #ifndef USB_PID_DW2102
17 #define USB_PID_DW2102 0x2102
18 #endif
19
20 #define DW2102_READ_MSG 0
21 #define DW2102_WRITE_MSG 1
22
23 #define REG_1F_SYMBOLRATE_BYTE0 0x1f
24 #define REG_20_SYMBOLRATE_BYTE1 0x20
25 #define REG_21_SYMBOLRATE_BYTE2 0x21
26
27 #define DW2102_VOLTAGE_CTRL (0x1800)
28 #define DW2102_RC_QUERY (0x1a00)
29
30 struct dw2102_state {
31         u32 last_key_pressed;
32 };
33 struct dw2102_rc_keys {
34         u32 keycode;
35         u32 event;
36 };
37
38 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
39
40 static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
41                 u8 *data, u16 len, int flags)
42 {
43         int ret;
44         u8 u8buf[len];
45
46         unsigned int pipe = (flags == DW2102_READ_MSG) ?
47                 usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
48         u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
49
50         if (flags == DW2102_WRITE_MSG)
51                 memcpy(u8buf, data, len);
52         ret = usb_control_msg(dev, pipe, request,
53                 request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000);
54
55         if (flags == DW2102_READ_MSG)
56                 memcpy(data, u8buf, len);
57         return ret;
58 }
59
60 /* I2C */
61
62 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
63                 int num)
64 {
65 struct dvb_usb_device *d = i2c_get_adapdata(adap);
66         int i = 0, ret = 0;
67         u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
68         u8 request;
69         u16 value;
70
71         if (!d)
72                 return -ENODEV;
73         if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
74                 return -EAGAIN;
75
76         switch (num) {
77         case 2:
78                 /* read stv0299 register */
79                 request = 0xb5;
80                 value = msg[0].buf[0];/* register */
81                 for (i = 0; i < msg[1].len; i++) {
82                         value = value + i;
83                         ret = dw2102_op_rw(d->udev, 0xb5,
84                                 value, buf6, 2, DW2102_READ_MSG);
85                         msg[1].buf[i] = buf6[0];
86
87                 }
88                 break;
89         case 1:
90                 switch (msg[0].addr) {
91                 case 0x68:
92                         /* write to stv0299 register */
93                         buf6[0] = 0x2a;
94                         buf6[1] = msg[0].buf[0];
95                         buf6[2] = msg[0].buf[1];
96                         ret = dw2102_op_rw(d->udev, 0xb2,
97                                 0, buf6, 3, DW2102_WRITE_MSG);
98                         break;
99                 case 0x60:
100                         if (msg[0].flags == 0) {
101                         /* write to tuner pll */
102                                 buf6[0] = 0x2c;
103                                 buf6[1] = 5;
104                                 buf6[2] = 0xc0;
105                                 buf6[3] = msg[0].buf[0];
106                                 buf6[4] = msg[0].buf[1];
107                                 buf6[5] = msg[0].buf[2];
108                                 buf6[6] = msg[0].buf[3];
109                                 ret = dw2102_op_rw(d->udev, 0xb2,
110                                 0, buf6, 7, DW2102_WRITE_MSG);
111                         } else {
112                         /* write to tuner pll */
113                                 ret = dw2102_op_rw(d->udev, 0xb5,
114                                 0, buf6, 1, DW2102_READ_MSG);
115                                 msg[0].buf[0] = buf6[0];
116                         }
117                         break;
118                 case (DW2102_RC_QUERY):
119                         ret  = dw2102_op_rw(d->udev, 0xb8,
120                                 0, buf6, 2, DW2102_READ_MSG);
121                         msg[0].buf[0] = buf6[0];
122                         msg[0].buf[1] = buf6[1];
123                         break;
124                 case (DW2102_VOLTAGE_CTRL):
125                         buf6[0] = 0x30;
126                         buf6[1] = msg[0].buf[0];
127                         ret = dw2102_op_rw(d->udev, 0xb2,
128                                 0, buf6, 2, DW2102_WRITE_MSG);
129                         break;
130                 }
131
132                 break;
133         }
134
135         mutex_unlock(&d->i2c_mutex);
136         return num;
137 }
138
139 static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
140 {
141         return I2C_FUNC_I2C;
142 }
143
144 static struct i2c_algorithm dw2102_i2c_algo = {
145         .master_xfer = dw2102_i2c_transfer,
146         .functionality = dw2102_i2c_func,
147 };
148
149 static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
150 {
151         static u8 command_13v[1] = {0x00};
152         static u8 command_18v[1] = {0x01};
153         struct i2c_msg msg[] = {
154                 {.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
155                         .buf = command_13v, .len = 1},
156         };
157
158         struct dvb_usb_adapter *udev_adap =
159                 (struct dvb_usb_adapter *)(fe->dvb->priv);
160         if (voltage == SEC_VOLTAGE_18)
161                 msg[0].buf = command_18v;
162         i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
163         return 0;
164 }
165
166 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
167 {
168         d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
169                 &d->dev->i2c_adap);
170         if (d->fe != NULL) {
171                 d->fe->ops.set_voltage = dw2102_set_voltage;
172                 info("Attached stv0299!\n");
173                 return 0;
174         }
175         return -EIO;
176 }
177
178 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
179 {
180         dvb_attach(dvb_pll_attach, adap->fe, 0x60,
181                 &adap->dev->i2c_adap, DVB_PLL_OPERA1);
182         return 0;
183 }
184
185 static struct dvb_usb_rc_key dw2102_rc_keys[] = {
186         { 0xf8, 0x0a, KEY_Q },          /*power*/
187         { 0xf8, 0x0c, KEY_M },          /*mute*/
188         { 0xf8, 0x11, KEY_1 },
189         { 0xf8, 0x12, KEY_2 },
190         { 0xf8, 0x13, KEY_3 },
191         { 0xf8, 0x14, KEY_4 },
192         { 0xf8, 0x15, KEY_5 },
193         { 0xf8, 0x16, KEY_6 },
194         { 0xf8, 0x17, KEY_7 },
195         { 0xf8, 0x18, KEY_8 },
196         { 0xf8, 0x19, KEY_9 },
197         { 0xf8, 0x10, KEY_0 },
198         { 0xf8, 0x1c, KEY_PAGEUP },     /*ch+*/
199         { 0xf8, 0x0f, KEY_PAGEDOWN },   /*ch-*/
200         { 0xf8, 0x1a, KEY_O },          /*vol+*/
201         { 0xf8, 0x0e, KEY_Z },          /*vol-*/
202         { 0xf8, 0x04, KEY_R },          /*rec*/
203         { 0xf8, 0x09, KEY_D },          /*fav*/
204         { 0xf8, 0x08, KEY_BACKSPACE },  /*rewind*/
205         { 0xf8, 0x07, KEY_A },          /*fast*/
206         { 0xf8, 0x0b, KEY_P },          /*pause*/
207         { 0xf8, 0x02, KEY_ESC },        /*cancel*/
208         { 0xf8, 0x03, KEY_G },          /*tab*/
209         { 0xf8, 0x00, KEY_UP },         /*up*/
210         { 0xf8, 0x1f, KEY_ENTER },      /*ok*/
211         { 0xf8, 0x01, KEY_DOWN },       /*down*/
212         { 0xf8, 0x05, KEY_C },          /*cap*/
213         { 0xf8, 0x06, KEY_S },          /*stop*/
214         { 0xf8, 0x40, KEY_F },          /*full*/
215         { 0xf8, 0x1e, KEY_W },          /*tvmode*/
216         { 0xf8, 0x1b, KEY_B },          /*recall*/
217
218 };
219
220
221
222 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
223 {
224         struct dw2102_state *st = d->priv;
225         u8 key[2];
226         struct i2c_msg msg[] = {
227                 {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
228                 .len = 2},
229         };
230         int i;
231
232         *state = REMOTE_NO_KEY_PRESSED;
233         if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
234                 for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) {
235                         if (dw2102_rc_keys[i].data == msg[0].buf[0]) {
236                                 *state = REMOTE_KEY_PRESSED;
237                                 *event = dw2102_rc_keys[i].event;
238                                 st->last_key_pressed =
239                                         dw2102_rc_keys[i].event;
240                                 break;
241                         }
242                 st->last_key_pressed = 0;
243                 }
244         }
245         /* info("key: %x %x\n",key[0],key[1]); */
246         return 0;
247 }
248
249 static struct usb_device_id dw2102_table[] = {
250         {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
251         {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
252         { }
253 };
254
255 MODULE_DEVICE_TABLE(usb, dw2102_table);
256
257 static int dw2102_load_firmware(struct usb_device *dev,
258                         const struct firmware *frmwr)
259 {
260         u8 *b, *p;
261         int ret = 0, i;
262         u8 reset;
263         u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0};
264         const struct firmware *fw;
265         const char *filename = "dvb-usb-dw2101.fw";
266         switch (dev->descriptor.idProduct) {
267         case 0x2101:
268                 ret = request_firmware(&fw, filename, &dev->dev);
269                 if (ret != 0) {
270                         err("did not find the firmware file. (%s) "
271                         "Please see linux/Documentation/dvb/ for more details "
272                         "on firmware-problems.", filename);
273                         return ret;
274                 }
275                 break;
276         case USB_PID_DW2102:
277                 fw = frmwr;
278                 break;
279         }
280         info("start downloading DW2102 firmware");
281         p = kmalloc(fw->size, GFP_KERNEL);
282         reset = 1;
283         /*stop the CPU*/
284         dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
285         dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
286
287         if (p != NULL) {
288                 memcpy(p, fw->data, fw->size);
289                 for (i = 0; i < fw->size; i += 0x40) {
290                         b = (u8 *) p + i;
291                         if (dw2102_op_rw
292                                 (dev, 0xa0, i, b , 0x40,
293                                         DW2102_WRITE_MSG) != 0x40
294                                 ) {
295                                 err("error while transferring firmware");
296                                 ret = -EINVAL;
297                                 break;
298                         }
299                 }
300                 /* restart the CPU */
301                 reset = 0;
302                 if (ret || dw2102_op_rw
303                         (dev, 0xa0, 0x7f92, &reset, 1,
304                         DW2102_WRITE_MSG) != 1) {
305                         err("could not restart the USB controller CPU.");
306                         ret = -EINVAL;
307                 }
308                 if (ret || dw2102_op_rw
309                         (dev, 0xa0, 0xe600, &reset, 1,
310                         DW2102_WRITE_MSG) != 1) {
311                         err("could not restart the USB controller CPU.");
312                         ret = -EINVAL;
313                 }
314                 /* init registers */
315                 switch (dev->descriptor.idProduct) {
316                 case USB_PID_DW2102:
317                         dw2102_op_rw
318                                 (dev, 0xbf, 0x0040, &reset, 0,
319                                 DW2102_WRITE_MSG);
320                         dw2102_op_rw
321                                 (dev, 0xb9, 0x0000, &reset16[0], 2,
322                                 DW2102_READ_MSG);
323                         break;
324                 case 0x2101:
325                         dw2102_op_rw
326                                 (dev, 0xbc, 0x0030, &reset16[0], 2,
327                                 DW2102_READ_MSG);
328                         dw2102_op_rw
329                                 (dev, 0xba, 0x0000, &reset16[0], 7,
330                                 DW2102_READ_MSG);
331                         dw2102_op_rw
332                                 (dev, 0xba, 0x0000, &reset16[0], 7,
333                                 DW2102_READ_MSG);
334                         dw2102_op_rw
335                                 (dev, 0xb9, 0x0000, &reset16[0], 2,
336                                 DW2102_READ_MSG);
337                         break;
338                 }
339                 kfree(p);
340         }
341         return ret;
342 }
343
344 static struct dvb_usb_device_properties dw2102_properties = {
345         .caps = DVB_USB_IS_AN_I2C_ADAPTER,
346         .usb_ctrl = DEVICE_SPECIFIC,
347         .firmware = "dvb-usb-dw2102.fw",
348         .size_of_priv = sizeof(struct dw2102_state),
349         .no_reconnect = 1,
350
351         .i2c_algo = &dw2102_i2c_algo,
352         .rc_key_map = dw2102_rc_keys,
353         .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys),
354         .rc_interval = 150,
355         .rc_query = dw2102_rc_query,
356
357         .generic_bulk_ctrl_endpoint = 0x81,
358         /* parameter for the MPEG2-data transfer */
359         .num_adapters = 1,
360         .download_firmware = dw2102_load_firmware,
361         .adapter = {
362                 {
363                         .frontend_attach = dw2102_frontend_attach,
364                         .streaming_ctrl = NULL,
365                         .tuner_attach = dw2102_tuner_attach,
366                         .stream = {
367                                 .type = USB_BULK,
368                                 .count = 8,
369                                 .endpoint = 0x82,
370                                 .u = {
371                                         .bulk = {
372                                                 .buffersize = 4096,
373                                         }
374                                 }
375                         },
376                 }
377         },
378         .num_device_descs = 2,
379         .devices = {
380                 {"DVBWorld DVB-S 2102 USB2.0",
381                         {&dw2102_table[0], NULL},
382                         {NULL},
383                 },
384                 {"DVBWorld DVB-S 2101 USB2.0",
385                         {&dw2102_table[1], NULL},
386                         {NULL},
387                 },
388         }
389 };
390
391 static int dw2102_probe(struct usb_interface *intf,
392                 const struct usb_device_id *id)
393 {
394         return dvb_usb_device_init(intf, &dw2102_properties,
395                 THIS_MODULE, NULL, adapter_nr);
396 }
397
398 static struct usb_driver dw2102_driver = {
399         .name = "dw2102",
400         .probe = dw2102_probe,
401         .disconnect = dvb_usb_device_exit,
402         .id_table = dw2102_table,
403 };
404
405 static int __init dw2102_module_init(void)
406 {
407         int ret =  usb_register(&dw2102_driver);
408         if (ret)
409                 err("usb_register failed. Error number %d", ret);
410
411         return ret;
412 }
413
414 static void __exit dw2102_module_exit(void)
415 {
416         usb_deregister(&dw2102_driver);
417 }
418
419 module_init(dw2102_module_init);
420 module_exit(dw2102_module_exit);
421
422 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
423 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device");
424 MODULE_VERSION("0.1");
425 MODULE_LICENSE("GPL");