V4L/DVB (10700): saa7115: don't access reg 0x87 if it is not present.
[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
22 struct usb_device_id smsusb_id_table[] = {
23 #ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
24         { USB_DEVICE(0x187f, 0x0010),
25                 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
26         { USB_DEVICE(0x187f, 0x0100),
27                 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
28         { USB_DEVICE(0x187f, 0x0200),
29                 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
30         { USB_DEVICE(0x187f, 0x0201),
31                 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
32         { USB_DEVICE(0x187f, 0x0300),
33                 .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
34 #endif
35         { USB_DEVICE(0x2040, 0x1700),
36                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
37         { USB_DEVICE(0x2040, 0x1800),
38                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
39         { USB_DEVICE(0x2040, 0x1801),
40                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
41         { USB_DEVICE(0x2040, 0x2000),
42                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
43         { USB_DEVICE(0x2040, 0x2009),
44                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
45         { USB_DEVICE(0x2040, 0x200a),
46                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
47         { USB_DEVICE(0x2040, 0x2010),
48                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
49         { USB_DEVICE(0x2040, 0x2011),
50                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
51         { USB_DEVICE(0x2040, 0x2019),
52                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
53         { USB_DEVICE(0x2040, 0x5500),
54                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
55         { USB_DEVICE(0x2040, 0x5510),
56                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
57         { USB_DEVICE(0x2040, 0x5520),
58                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
59         { USB_DEVICE(0x2040, 0x5530),
60                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
61         { USB_DEVICE(0x2040, 0x5580),
62                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
63         { USB_DEVICE(0x2040, 0x5590),
64                 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
65         { }             /* Terminating entry */
66 };
67 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
68
69 static struct sms_board sms_boards[] = {
70         [SMS_BOARD_UNKNOWN] = {
71                 .name   = "Unknown board",
72         },
73         [SMS1XXX_BOARD_SIANO_STELLAR] = {
74                 .name   = "Siano Stellar Digital Receiver",
75                 .type   = SMS_STELLAR,
76                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
77         },
78         [SMS1XXX_BOARD_SIANO_NOVA_A] = {
79                 .name   = "Siano Nova A Digital Receiver",
80                 .type   = SMS_NOVA_A0,
81                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
82         },
83         [SMS1XXX_BOARD_SIANO_NOVA_B] = {
84                 .name   = "Siano Nova B Digital Receiver",
85                 .type   = SMS_NOVA_B0,
86                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
87         },
88         [SMS1XXX_BOARD_SIANO_VEGA] = {
89                 .name   = "Siano Vega Digital Receiver",
90                 .type   = SMS_VEGA,
91         },
92         [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
93                 .name   = "Hauppauge Catamount",
94                 .type   = SMS_STELLAR,
95                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
96         },
97         [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
98                 .name   = "Hauppauge Okemo-A",
99                 .type   = SMS_NOVA_A0,
100                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
101         },
102         [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
103                 .name   = "Hauppauge Okemo-B",
104                 .type   = SMS_NOVA_B0,
105                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
106         },
107         [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
108                 .name   = "Hauppauge WinTV MiniStick",
109                 .type   = SMS_NOVA_B0,
110                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
111                 .led_power = 26,
112                 .led_lo    = 27,
113                 .led_hi    = 28,
114         },
115         [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
116                 .name   = "Hauppauge WinTV MiniCard",
117                 .type   = SMS_NOVA_B0,
118                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
119                 .lna_ctrl  = 29,
120         },
121         [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
122                 .name   = "Hauppauge WinTV MiniCard",
123                 .type   = SMS_NOVA_B0,
124                 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
125                 .lna_ctrl  = -1,
126         },
127 };
128
129 struct sms_board *sms_get_board(int id)
130 {
131         BUG_ON(id >= ARRAY_SIZE(sms_boards));
132
133         return &sms_boards[id];
134 }
135
136 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
137 {
138         int lvl, ret;
139         u32 gpio;
140         struct smscore_gpio_config gpioconfig = {
141                 .direction            = SMS_GPIO_DIRECTION_OUTPUT,
142                 .pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
143                 .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
144                 .outputslewrate       = SMS_GPIO_OUTPUTSLEWRATE_FAST,
145                 .outputdriving        = SMS_GPIO_OUTPUTDRIVING_4mA,
146         };
147
148         if (pin == 0)
149                 return -EINVAL;
150
151         if (pin < 0) {
152                 /* inverted gpio */
153                 gpio = pin * -1;
154                 lvl = enable ? 0 : 1;
155         } else {
156                 gpio = pin;
157                 lvl = enable ? 1 : 0;
158         }
159
160         ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
161         if (ret < 0)
162                 return ret;
163
164         return smscore_set_gpio(coredev, gpio, lvl);
165 }
166
167 int sms_board_setup(struct smscore_device_t *coredev)
168 {
169         int board_id = smscore_get_board_id(coredev);
170         struct sms_board *board = sms_get_board(board_id);
171
172         switch (board_id) {
173         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
174                 /* turn off all LEDs */
175                 sms_set_gpio(coredev, board->led_power, 0);
176                 sms_set_gpio(coredev, board->led_hi, 0);
177                 sms_set_gpio(coredev, board->led_lo, 0);
178                 break;
179         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
180         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
181                 /* turn off LNA */
182                 sms_set_gpio(coredev, board->lna_ctrl, 0);
183                 break;
184         }
185         return 0;
186 }
187
188 int sms_board_power(struct smscore_device_t *coredev, int onoff)
189 {
190         int board_id = smscore_get_board_id(coredev);
191         struct sms_board *board = sms_get_board(board_id);
192
193         switch (board_id) {
194         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
195                 /* power LED */
196                 sms_set_gpio(coredev,
197                              board->led_power, onoff ? 1 : 0);
198                 break;
199         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
200         case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
201                 /* LNA */
202                 sms_set_gpio(coredev,
203                              board->lna_ctrl, onoff ? 1 : 0);
204                 break;
205         }
206         return 0;
207 }
208
209 int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
210 {
211         int board_id = smscore_get_board_id(coredev);
212         struct sms_board *board = sms_get_board(board_id);
213
214         /* dont touch GPIO if LEDs are already set */
215         if (smscore_led_state(coredev, -1) == led)
216                 return 0;
217
218         switch (board_id) {
219         case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
220                 sms_set_gpio(coredev,
221                              board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
222                 sms_set_gpio(coredev,
223                              board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
224
225                 smscore_led_state(coredev, led);
226                 break;
227         }
228         return 0;
229 }