Merge branch 'slub/earlyboot' into for-linus
[linux-2.6] / drivers / media / dvb / siano / sms-cards.c
1 /*
2  *  Card-specific functions for the Siano SMS1xxx USB dongle
3  *
4  *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
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 version 2 as
8  *  published by the Free Software Foundation;
9  *
10  *  Software distributed under the License is distributed on an "AS IS"
11  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
12  *
13  *  See the GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "sms-cards.h"
21 #include "smsir.h"
22
23 static int sms_dbg;
24 module_param_named(cards_dbg, sms_dbg, int, 0644);
25 MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
26
27 static struct sms_board sms_boards[] = {
28         [SMS_BOARD_UNKNOWN] = {
29                 .name   = "Unknown board",
30         },
31         [SMS1XXX_BOARD_SIANO_STELLAR] = {
32                 .name   = "Siano Stellar Digital Receiver",
33                 .type   = SMS_STELLAR,
34         },
35         [SMS1XXX_BOARD_SIANO_NOVA_A] = {
36                 .name   = "Siano Nova A Digital Receiver",
37                 .type   = SMS_NOVA_A0,
38         },
39         [SMS1XXX_BOARD_SIANO_NOVA_B] = {
40                 .name   = "Siano Nova B Digital Receiver",
41                 .type   = SMS_NOVA_B0,
42         },
43         [SMS1XXX_BOARD_SIANO_VEGA] = {
44                 .name   = "Siano Vega Digital Receiver",
45                 .type   = SMS_VEGA,
46         },
47         [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
48                 .name   = "Hauppauge Catamount",
49                 .type   = SMS_STELLAR,
50                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
51         },
52         [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
53                 .name   = "Hauppauge Okemo-A",
54                 .type   = SMS_NOVA_A0,
55                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
56         },
57         [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
58                 .name   = "Hauppauge Okemo-B",
59                 .type   = SMS_NOVA_B0,
60                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
61         },
62         [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
63                 .name   = "Hauppauge WinTV MiniStick",
64                 .type   = SMS_NOVA_B0,
65                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
66                 .board_cfg.leds_power = 26,
67                 .board_cfg.led0 = 27,
68                 .board_cfg.led1 = 28,
69                 .led_power = 26,
70                 .led_lo    = 27,
71                 .led_hi    = 28,
72         },
73         [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
74                 .name   = "Hauppauge WinTV MiniCard",
75                 .type   = SMS_NOVA_B0,
76                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
77                 .lna_ctrl  = 29,
78                 .board_cfg.foreign_lna0_ctrl = 29,
79                 .rf_switch = 17,
80                 .board_cfg.rf_switch_uhf = 17,
81         },
82         [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
83                 .name   = "Hauppauge WinTV MiniCard",
84                 .type   = SMS_NOVA_B0,
85                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
86                 .lna_ctrl  = -1,
87         },
88         [SMS1XXX_BOARD_SIANO_NICE] = {
89         /* 11 */
90                 .name = "Siano Nice Digital Receiver",
91                 .type = SMS_NOVA_B0,
92         },
93         [SMS1XXX_BOARD_SIANO_VENICE] = {
94         /* 12 */
95                 .name = "Siano Venice Digital Receiver",
96                 .type = SMS_VEGA,
97         },
98 };
99
100 struct sms_board *sms_get_board(int id)
101 {
102         BUG_ON(id >= ARRAY_SIZE(sms_boards));
103
104         return &sms_boards[id];
105 }
106 EXPORT_SYMBOL_GPL(sms_get_board);
107 static inline void sms_gpio_assign_11xx_default_led_config(
108                 struct smscore_gpio_config *pGpioConfig) {
109         pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
110         pGpioConfig->InputCharacteristics =
111                 SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
112         pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
113         pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
114         pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
115 }
116
117 int sms_board_event(struct smscore_device_t *coredev,
118                 enum SMS_BOARD_EVENTS gevent) {
119         int board_id = smscore_get_board_id(coredev);
120         struct sms_board *board = sms_get_board(board_id);
121         struct smscore_gpio_config MyGpioConfig;
122
123         sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
124
125         switch (gevent) {
126         case BOARD_EVENT_POWER_INIT: /* including hotplug */
127                 switch (board_id) {
128                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
129                         /* set I/O and turn off all LEDs */
130                         smscore_gpio_configure(coredev,
131                                         board->board_cfg.leds_power,
132                                         &MyGpioConfig);
133                         smscore_gpio_set_level(coredev,
134                                         board->board_cfg.leds_power, 0);
135                         smscore_gpio_configure(coredev, board->board_cfg.led0,
136                                         &MyGpioConfig);
137                         smscore_gpio_set_level(coredev,
138                                         board->board_cfg.led0, 0);
139                         smscore_gpio_configure(coredev, board->board_cfg.led1,
140                                         &MyGpioConfig);
141                         smscore_gpio_set_level(coredev,
142                                         board->board_cfg.led1, 0);
143                         break;
144                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
145                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
146                         /* set I/O and turn off LNA */
147                         smscore_gpio_configure(coredev,
148                                         board->board_cfg.foreign_lna0_ctrl,
149                                         &MyGpioConfig);
150                         smscore_gpio_set_level(coredev,
151                                         board->board_cfg.foreign_lna0_ctrl,
152                                         0);
153                         break;
154                 }
155                 break; /* BOARD_EVENT_BIND */
156
157         case BOARD_EVENT_POWER_SUSPEND:
158                 switch (board_id) {
159                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
160                         smscore_gpio_set_level(coredev,
161                                                 board->board_cfg.leds_power, 0);
162                         smscore_gpio_set_level(coredev,
163                                                 board->board_cfg.led0, 0);
164                         smscore_gpio_set_level(coredev,
165                                                 board->board_cfg.led1, 0);
166                         break;
167                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
168                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
169                         smscore_gpio_set_level(coredev,
170                                         board->board_cfg.foreign_lna0_ctrl,
171                                         0);
172                         break;
173                 }
174                 break; /* BOARD_EVENT_POWER_SUSPEND */
175
176         case BOARD_EVENT_POWER_RESUME:
177                 switch (board_id) {
178                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
179                         smscore_gpio_set_level(coredev,
180                                                 board->board_cfg.leds_power, 1);
181                         smscore_gpio_set_level(coredev,
182                                                 board->board_cfg.led0, 1);
183                         smscore_gpio_set_level(coredev,
184                                                 board->board_cfg.led1, 0);
185                         break;
186                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
187                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
188                         smscore_gpio_set_level(coredev,
189                                         board->board_cfg.foreign_lna0_ctrl,
190                                         1);
191                         break;
192                 }
193                 break; /* BOARD_EVENT_POWER_RESUME */
194
195         case BOARD_EVENT_BIND:
196                 switch (board_id) {
197                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
198                         smscore_gpio_set_level(coredev,
199                                 board->board_cfg.leds_power, 1);
200                         smscore_gpio_set_level(coredev,
201                                 board->board_cfg.led0, 1);
202                         smscore_gpio_set_level(coredev,
203                                 board->board_cfg.led1, 0);
204                         break;
205                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
206                 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
207                         smscore_gpio_set_level(coredev,
208                                         board->board_cfg.foreign_lna0_ctrl,
209                                         1);
210                         break;
211                 }
212                 break; /* BOARD_EVENT_BIND */
213
214         case BOARD_EVENT_SCAN_PROG:
215                 break; /* BOARD_EVENT_SCAN_PROG */
216         case BOARD_EVENT_SCAN_COMP:
217                 break; /* BOARD_EVENT_SCAN_COMP */
218         case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
219                 break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
220         case BOARD_EVENT_FE_LOCK:
221                 switch (board_id) {
222                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
223                         smscore_gpio_set_level(coredev,
224                         board->board_cfg.led1, 1);
225                         break;
226                 }
227                 break; /* BOARD_EVENT_FE_LOCK */
228         case BOARD_EVENT_FE_UNLOCK:
229                 switch (board_id) {
230                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
231                         smscore_gpio_set_level(coredev,
232                                                 board->board_cfg.led1, 0);
233                         break;
234                 }
235                 break; /* BOARD_EVENT_FE_UNLOCK */
236         case BOARD_EVENT_DEMOD_LOCK:
237                 break; /* BOARD_EVENT_DEMOD_LOCK */
238         case BOARD_EVENT_DEMOD_UNLOCK:
239                 break; /* BOARD_EVENT_DEMOD_UNLOCK */
240         case BOARD_EVENT_RECEPTION_MAX_4:
241                 break; /* BOARD_EVENT_RECEPTION_MAX_4 */
242         case BOARD_EVENT_RECEPTION_3:
243                 break; /* BOARD_EVENT_RECEPTION_3 */
244         case BOARD_EVENT_RECEPTION_2:
245                 break; /* BOARD_EVENT_RECEPTION_2 */
246         case BOARD_EVENT_RECEPTION_1:
247                 break; /* BOARD_EVENT_RECEPTION_1 */
248         case BOARD_EVENT_RECEPTION_LOST_0:
249                 break; /* BOARD_EVENT_RECEPTION_LOST_0 */
250         case BOARD_EVENT_MULTIPLEX_OK:
251                 switch (board_id) {
252                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
253                         smscore_gpio_set_level(coredev,
254                                                 board->board_cfg.led1, 1);
255                         break;
256                 }
257                 break; /* BOARD_EVENT_MULTIPLEX_OK */
258         case BOARD_EVENT_MULTIPLEX_ERRORS:
259                 switch (board_id) {
260                 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
261                         smscore_gpio_set_level(coredev,
262                                                 board->board_cfg.led1, 0);
263                         break;
264                 }
265                 break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
266
267         default:
268                 sms_err("Unknown SMS board event");
269                 break;
270         }
271         return 0;
272 }
273 EXPORT_SYMBOL_GPL(sms_board_event);
274
275 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
276 {
277         int lvl, ret;
278         u32 gpio;
279         struct smscore_config_gpio gpioconfig = {
280                 .direction            = SMS_GPIO_DIRECTION_OUTPUT,
281                 .pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
282                 .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
283                 .outputslewrate       = SMS_GPIO_OUTPUTSLEWRATE_FAST,
284                 .outputdriving        = SMS_GPIO_OUTPUTDRIVING_4mA,
285         };
286
287         if (pin == 0)
288                 return -EINVAL;
289
290         if (pin < 0) {
291                 /* inverted gpio */
292                 gpio = pin * -1;
293                 lvl = enable ? 0 : 1;
294         } else {
295                 gpio = pin;
296                 lvl = enable ? 1 : 0;
297         }
298
299         ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
300         if (ret < 0)
301                 return ret;
302
303         return smscore_set_gpio(coredev, gpio, lvl);
304 }
305
306 int sms_board_setup(struct smscore_device_t *coredev)
307 {
308         int board_id = smscore_get_board_id(coredev);
309         struct sms_board *board = sms_get_board(board_id);
310
311         switch (board_id) {
312         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
313                 /* turn off all LEDs */
314                 sms_set_gpio(coredev, board->led_power, 0);
315                 sms_set_gpio(coredev, board->led_hi, 0);
316                 sms_set_gpio(coredev, board->led_lo, 0);
317                 break;
318         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
319         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
320                 /* turn off LNA */
321                 sms_set_gpio(coredev, board->lna_ctrl, 0);
322                 break;
323         }
324         return 0;
325 }
326 EXPORT_SYMBOL_GPL(sms_board_setup);
327
328 int sms_board_power(struct smscore_device_t *coredev, int onoff)
329 {
330         int board_id = smscore_get_board_id(coredev);
331         struct sms_board *board = sms_get_board(board_id);
332
333         switch (board_id) {
334         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
335                 /* power LED */
336                 sms_set_gpio(coredev,
337                              board->led_power, onoff ? 1 : 0);
338                 break;
339         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
340         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
341                 /* LNA */
342                 if (!onoff)
343                         sms_set_gpio(coredev, board->lna_ctrl, 0);
344                 break;
345         }
346         return 0;
347 }
348 EXPORT_SYMBOL_GPL(sms_board_power);
349
350 int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
351 {
352         int board_id = smscore_get_board_id(coredev);
353         struct sms_board *board = sms_get_board(board_id);
354
355         /* dont touch GPIO if LEDs are already set */
356         if (smscore_led_state(coredev, -1) == led)
357                 return 0;
358
359         switch (board_id) {
360         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
361                 sms_set_gpio(coredev,
362                              board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
363                 sms_set_gpio(coredev,
364                              board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
365
366                 smscore_led_state(coredev, led);
367                 break;
368         }
369         return 0;
370 }
371 EXPORT_SYMBOL_GPL(sms_board_led_feedback);
372
373 int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
374 {
375         int board_id = smscore_get_board_id(coredev);
376         struct sms_board *board = sms_get_board(board_id);
377
378         sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
379
380         switch (board_id) {
381         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
382         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
383                 sms_set_gpio(coredev,
384                              board->rf_switch, onoff ? 1 : 0);
385                 return sms_set_gpio(coredev,
386                                     board->lna_ctrl, onoff ? 1 : 0);
387         }
388         return -EINVAL;
389 }
390 EXPORT_SYMBOL_GPL(sms_board_lna_control);
391
392 int sms_board_load_modules(int id)
393 {
394         switch (id) {
395         case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
396         case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
397         case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
398         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
399                 request_module("smsdvb");
400                 break;
401         default:
402                 /* do nothing */
403                 break;
404         }
405         return 0;
406 }
407 EXPORT_SYMBOL_GPL(sms_board_load_modules);