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