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
16 #include "sms-cards.h"
17 #include "smsir.h"
18 #include <linux/module.h>
19
20 static struct sms_board sms_boards[] = {
21 [SMS_BOARD_UNKNOWN] = {
22 .name = "Unknown board",
23 .type = SMS_UNKNOWN_TYPE,
24 .default_mode = DEVICE_MODE_NONE,
25 },
26 [SMS1XXX_BOARD_SIANO_STELLAR] = {
27 .name = "Siano Stellar Digital Receiver",
28 .type = SMS_STELLAR,
29 .default_mode = DEVICE_MODE_DVBT_BDA,
30 },
31 [SMS1XXX_BOARD_SIANO_NOVA_A] = {
32 .name = "Siano Nova A Digital Receiver",
33 .type = SMS_NOVA_A0,
34 .default_mode = DEVICE_MODE_DVBT_BDA,
35 },
36 [SMS1XXX_BOARD_SIANO_NOVA_B] = {
37 .name = "Siano Nova B Digital Receiver",
38 .type = SMS_NOVA_B0,
39 .default_mode = DEVICE_MODE_DVBT_BDA,
40 },
41 [SMS1XXX_BOARD_SIANO_VEGA] = {
42 .name = "Siano Vega Digital Receiver",
43 .type = SMS_VEGA,
44 .default_mode = DEVICE_MODE_CMMB,
45 },
46 [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
47 .name = "Hauppauge Catamount",
48 .type = SMS_STELLAR,
49 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_STELLAR,
50 .default_mode = DEVICE_MODE_DVBT_BDA,
51 },
52 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
53 .name = "Hauppauge Okemo-A",
54 .type = SMS_NOVA_A0,
55 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_A,
56 .default_mode = DEVICE_MODE_DVBT_BDA,
57 },
58 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
59 .name = "Hauppauge Okemo-B",
60 .type = SMS_NOVA_B0,
61 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_B,
62 .default_mode = DEVICE_MODE_DVBT_BDA,
63 },
64 [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
65 .name = "Hauppauge WinTV MiniStick",
66 .type = SMS_NOVA_B0,
67 .fw[DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_HCW_55XXX,
68 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
69 .default_mode = DEVICE_MODE_DVBT_BDA,
70 .rc_codes = RC_MAP_HAUPPAUGE,
71 .board_cfg.leds_power = 26,
72 .board_cfg.led0 = 27,
73 .board_cfg.led1 = 28,
74 .board_cfg.ir = 9,
75 .led_power = 26,
76 .led_lo = 27,
77 .led_hi = 28,
78 },
79 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
80 .name = "Hauppauge WinTV MiniCard",
81 .type = SMS_NOVA_B0,
82 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
83 .default_mode = DEVICE_MODE_DVBT_BDA,
84 .lna_ctrl = 29,
85 .board_cfg.foreign_lna0_ctrl = 29,
86 .rf_switch = 17,
87 .board_cfg.rf_switch_uhf = 17,
88 },
89 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
90 .name = "Hauppauge WinTV MiniCard",
91 .type = SMS_NOVA_B0,
92 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
93 .default_mode = DEVICE_MODE_DVBT_BDA,
94 .lna_ctrl = -1,
95 },
96 [SMS1XXX_BOARD_SIANO_NICE] = {
97 .name = "Siano Nice Digital Receiver",
98 .type = SMS_NOVA_B0,
99 .default_mode = DEVICE_MODE_DVBT_BDA,
100 },
101 [SMS1XXX_BOARD_SIANO_VENICE] = {
102 .name = "Siano Venice Digital Receiver",
103 .type = SMS_VEGA,
104 .default_mode = DEVICE_MODE_CMMB,
105 },
106 [SMS1XXX_BOARD_SIANO_STELLAR_ROM] = {
107 .name = "Siano Stellar Digital Receiver ROM",
108 .type = SMS_STELLAR,
109 .default_mode = DEVICE_MODE_DVBT_BDA,
110 .intf_num = 1,
111 },
112 [SMS1XXX_BOARD_ZTE_DVB_DATA_CARD] = {
113 .name = "ZTE Data Card Digital Receiver",
114 .type = SMS_NOVA_B0,
115 .default_mode = DEVICE_MODE_DVBT_BDA,
116 .intf_num = 5,
117 .mtu = 15792,
118 },
119 [SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD] = {
120 .name = "ONDA Data Card Digital Receiver",
121 .type = SMS_NOVA_B0,
122 .default_mode = DEVICE_MODE_DVBT_BDA,
123 .intf_num = 6,
124 .mtu = 15792,
125 },
126 [SMS1XXX_BOARD_SIANO_MING] = {
127 .name = "Siano Ming Digital Receiver",
128 .type = SMS_MING,
129 .default_mode = DEVICE_MODE_CMMB,
130 },
131 [SMS1XXX_BOARD_SIANO_PELE] = {
132 .name = "Siano Pele Digital Receiver",
133 .type = SMS_PELE,
134 .default_mode = DEVICE_MODE_ISDBT_BDA,
135 },
136 [SMS1XXX_BOARD_SIANO_RIO] = {
137 .name = "Siano Rio Digital Receiver",
138 .type = SMS_RIO,
139 .default_mode = DEVICE_MODE_ISDBT_BDA,
140 },
141 [SMS1XXX_BOARD_SIANO_DENVER_1530] = {
142 .name = "Siano Denver (ATSC-M/H) Digital Receiver",
143 .type = SMS_DENVER_1530,
144 .default_mode = DEVICE_MODE_ATSC,
145 .crystal = 2400,
146 },
147 [SMS1XXX_BOARD_SIANO_DENVER_2160] = {
148 .name = "Siano Denver (TDMB) Digital Receiver",
149 .type = SMS_DENVER_2160,
150 .default_mode = DEVICE_MODE_DAB_TDMB,
151 },
152 [SMS1XXX_BOARD_PCTV_77E] = {
153 .name = "Hauppauge microStick 77e",
154 .type = SMS_NOVA_B0,
155 .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
156 .default_mode = DEVICE_MODE_DVBT_BDA,
157 },
158 };
159
sms_get_board(unsigned id)160 struct sms_board *sms_get_board(unsigned id)
161 {
162 BUG_ON(id >= ARRAY_SIZE(sms_boards));
163
164 return &sms_boards[id];
165 }
166 EXPORT_SYMBOL_GPL(sms_get_board);
sms_gpio_assign_11xx_default_led_config(struct smscore_config_gpio * p_gpio_config)167 static inline void sms_gpio_assign_11xx_default_led_config(
168 struct smscore_config_gpio *p_gpio_config) {
169 p_gpio_config->direction = SMS_GPIO_DIRECTION_OUTPUT;
170 p_gpio_config->inputcharacteristics =
171 SMS_GPIO_INPUTCHARACTERISTICS_NORMAL;
172 p_gpio_config->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA;
173 p_gpio_config->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
174 p_gpio_config->pullupdown = SMS_GPIO_PULLUPDOWN_NONE;
175 }
176
sms_board_event(struct smscore_device_t * coredev,enum SMS_BOARD_EVENTS gevent)177 int sms_board_event(struct smscore_device_t *coredev,
178 enum SMS_BOARD_EVENTS gevent)
179 {
180 struct smscore_config_gpio my_gpio_config;
181
182 sms_gpio_assign_11xx_default_led_config(&my_gpio_config);
183
184 switch (gevent) {
185 case BOARD_EVENT_POWER_INIT: /* including hotplug */
186 break; /* BOARD_EVENT_BIND */
187
188 case BOARD_EVENT_POWER_SUSPEND:
189 break; /* BOARD_EVENT_POWER_SUSPEND */
190
191 case BOARD_EVENT_POWER_RESUME:
192 break; /* BOARD_EVENT_POWER_RESUME */
193
194 case BOARD_EVENT_BIND:
195 break; /* BOARD_EVENT_BIND */
196
197 case BOARD_EVENT_SCAN_PROG:
198 break; /* BOARD_EVENT_SCAN_PROG */
199 case BOARD_EVENT_SCAN_COMP:
200 break; /* BOARD_EVENT_SCAN_COMP */
201 case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
202 break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
203 case BOARD_EVENT_FE_LOCK:
204 break; /* BOARD_EVENT_FE_LOCK */
205 case BOARD_EVENT_FE_UNLOCK:
206 break; /* BOARD_EVENT_FE_UNLOCK */
207 case BOARD_EVENT_DEMOD_LOCK:
208 break; /* BOARD_EVENT_DEMOD_LOCK */
209 case BOARD_EVENT_DEMOD_UNLOCK:
210 break; /* BOARD_EVENT_DEMOD_UNLOCK */
211 case BOARD_EVENT_RECEPTION_MAX_4:
212 break; /* BOARD_EVENT_RECEPTION_MAX_4 */
213 case BOARD_EVENT_RECEPTION_3:
214 break; /* BOARD_EVENT_RECEPTION_3 */
215 case BOARD_EVENT_RECEPTION_2:
216 break; /* BOARD_EVENT_RECEPTION_2 */
217 case BOARD_EVENT_RECEPTION_1:
218 break; /* BOARD_EVENT_RECEPTION_1 */
219 case BOARD_EVENT_RECEPTION_LOST_0:
220 break; /* BOARD_EVENT_RECEPTION_LOST_0 */
221 case BOARD_EVENT_MULTIPLEX_OK:
222 break; /* BOARD_EVENT_MULTIPLEX_OK */
223 case BOARD_EVENT_MULTIPLEX_ERRORS:
224 break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
225
226 default:
227 pr_err("Unknown SMS board event\n");
228 break;
229 }
230 return 0;
231 }
232 EXPORT_SYMBOL_GPL(sms_board_event);
233
sms_set_gpio(struct smscore_device_t * coredev,int pin,int enable)234 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
235 {
236 int lvl, ret;
237 u32 gpio;
238 struct smscore_config_gpio gpioconfig = {
239 .direction = SMS_GPIO_DIRECTION_OUTPUT,
240 .pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
241 .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
242 .outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_FAST,
243 .outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA,
244 };
245
246 if (pin == 0)
247 return -EINVAL;
248
249 if (pin < 0) {
250 /* inverted gpio */
251 gpio = pin * -1;
252 lvl = enable ? 0 : 1;
253 } else {
254 gpio = pin;
255 lvl = enable ? 1 : 0;
256 }
257
258 ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
259 if (ret < 0)
260 return ret;
261
262 return smscore_set_gpio(coredev, gpio, lvl);
263 }
264
sms_board_setup(struct smscore_device_t * coredev)265 int sms_board_setup(struct smscore_device_t *coredev)
266 {
267 int board_id = smscore_get_board_id(coredev);
268 struct sms_board *board = sms_get_board(board_id);
269
270 switch (board_id) {
271 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
272 /* turn off all LEDs */
273 sms_set_gpio(coredev, board->led_power, 0);
274 sms_set_gpio(coredev, board->led_hi, 0);
275 sms_set_gpio(coredev, board->led_lo, 0);
276 break;
277 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
278 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
279 /* turn off LNA */
280 sms_set_gpio(coredev, board->lna_ctrl, 0);
281 break;
282 }
283 return 0;
284 }
285 EXPORT_SYMBOL_GPL(sms_board_setup);
286
sms_board_power(struct smscore_device_t * coredev,int onoff)287 int sms_board_power(struct smscore_device_t *coredev, int onoff)
288 {
289 int board_id = smscore_get_board_id(coredev);
290 struct sms_board *board = sms_get_board(board_id);
291
292 switch (board_id) {
293 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
294 /* power LED */
295 sms_set_gpio(coredev,
296 board->led_power, onoff ? 1 : 0);
297 break;
298 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
299 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
300 /* LNA */
301 if (!onoff)
302 sms_set_gpio(coredev, board->lna_ctrl, 0);
303 break;
304 }
305 return 0;
306 }
307 EXPORT_SYMBOL_GPL(sms_board_power);
308
sms_board_led_feedback(struct smscore_device_t * coredev,int led)309 int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
310 {
311 int board_id = smscore_get_board_id(coredev);
312 struct sms_board *board = sms_get_board(board_id);
313
314 /* dont touch GPIO if LEDs are already set */
315 if (smscore_led_state(coredev, -1) == led)
316 return 0;
317
318 switch (board_id) {
319 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
320 sms_set_gpio(coredev,
321 board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
322 sms_set_gpio(coredev,
323 board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
324
325 smscore_led_state(coredev, led);
326 break;
327 }
328 return 0;
329 }
330 EXPORT_SYMBOL_GPL(sms_board_led_feedback);
331
sms_board_lna_control(struct smscore_device_t * coredev,int onoff)332 int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
333 {
334 int board_id = smscore_get_board_id(coredev);
335 struct sms_board *board = sms_get_board(board_id);
336
337 pr_debug("%s: LNA %s\n", __func__, onoff ? "enabled" : "disabled");
338
339 switch (board_id) {
340 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
341 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
342 sms_set_gpio(coredev,
343 board->rf_switch, onoff ? 1 : 0);
344 return sms_set_gpio(coredev,
345 board->lna_ctrl, onoff ? 1 : 0);
346 }
347 return -EINVAL;
348 }
349 EXPORT_SYMBOL_GPL(sms_board_lna_control);
350
sms_board_load_modules(int id)351 int sms_board_load_modules(int id)
352 {
353 request_module("smsdvb");
354 return 0;
355 }
356 EXPORT_SYMBOL_GPL(sms_board_load_modules);
357