diff options
Diffstat (limited to 'drivers/media/dvb/frontends')
34 files changed, 7291 insertions, 178 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 7dbb4a223c99..96b93e21a84b 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -43,6 +43,20 @@ config DVB_S5H1420 | |||
43 | help | 43 | help |
44 | A DVB-S tuner module. Say Y when you want to support this frontend. | 44 | A DVB-S tuner module. Say Y when you want to support this frontend. |
45 | 45 | ||
46 | config DVB_STV0288 | ||
47 | tristate "ST STV0288 based" | ||
48 | depends on DVB_CORE && I2C | ||
49 | default m if DVB_FE_CUSTOMISE | ||
50 | help | ||
51 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
52 | |||
53 | config DVB_STB6000 | ||
54 | tristate "ST STB6000 silicon tuner" | ||
55 | depends on DVB_CORE && I2C | ||
56 | default m if DVB_FE_CUSTOMISE | ||
57 | help | ||
58 | A DVB-S silicon tuner module. Say Y when you want to support this tuner. | ||
59 | |||
46 | config DVB_STV0299 | 60 | config DVB_STV0299 |
47 | tristate "ST STV0299 based" | 61 | tristate "ST STV0299 based" |
48 | depends on DVB_CORE && I2C | 62 | depends on DVB_CORE && I2C |
@@ -92,6 +106,20 @@ config DVB_TUA6100 | |||
92 | help | 106 | help |
93 | A DVB-S PLL chip. | 107 | A DVB-S PLL chip. |
94 | 108 | ||
109 | config DVB_CX24116 | ||
110 | tristate "Conexant CX24116 based" | ||
111 | depends on DVB_CORE && I2C | ||
112 | default m if DVB_FE_CUSTOMISE | ||
113 | help | ||
114 | A DVB-S/S2 tuner module. Say Y when you want to support this frontend. | ||
115 | |||
116 | config DVB_SI21XX | ||
117 | tristate "Silicon Labs SI21XX based" | ||
118 | depends on DVB_CORE && I2C | ||
119 | default m if DVB_FE_CUSTOMISE | ||
120 | help | ||
121 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
122 | |||
95 | comment "DVB-T (terrestrial) frontends" | 123 | comment "DVB-T (terrestrial) frontends" |
96 | depends on DVB_CORE | 124 | depends on DVB_CORE |
97 | 125 | ||
@@ -385,4 +413,23 @@ config DVB_ISL6421 | |||
385 | help | 413 | help |
386 | An SEC control chip. | 414 | An SEC control chip. |
387 | 415 | ||
416 | config DVB_LGS8GL5 | ||
417 | tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" | ||
418 | depends on DVB_CORE && I2C | ||
419 | default m if DVB_FE_CUSTOMISE | ||
420 | help | ||
421 | A DMB-TH tuner module. Say Y when you want to support this frontend. | ||
422 | |||
423 | comment "Tools to develop new frontends" | ||
424 | |||
425 | config DVB_DUMMY_FE | ||
426 | tristate "Dummy frontend driver" | ||
427 | default n | ||
428 | |||
429 | config DVB_AF9013 | ||
430 | tristate "Afatech AF9013 demodulator" | ||
431 | depends on DVB_CORE && I2C | ||
432 | default m if DVB_FE_CUSTOMISE | ||
433 | help | ||
434 | Say Y when you want to support this frontend. | ||
388 | endmenu | 435 | endmenu |
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 028da55611c0..aba79f4a63a7 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -48,3 +48,10 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o | |||
48 | obj-$(CONFIG_DVB_AU8522) += au8522.o | 48 | obj-$(CONFIG_DVB_AU8522) += au8522.o |
49 | obj-$(CONFIG_DVB_TDA10048) += tda10048.o | 49 | obj-$(CONFIG_DVB_TDA10048) += tda10048.o |
50 | obj-$(CONFIG_DVB_S5H1411) += s5h1411.o | 50 | obj-$(CONFIG_DVB_S5H1411) += s5h1411.o |
51 | obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o | ||
52 | obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o | ||
53 | obj-$(CONFIG_DVB_AF9013) += af9013.o | ||
54 | obj-$(CONFIG_DVB_CX24116) += cx24116.o | ||
55 | obj-$(CONFIG_DVB_SI21XX) += si21xx.o | ||
56 | obj-$(CONFIG_DVB_STV0288) += stv0288.o | ||
57 | obj-$(CONFIG_DVB_STB6000) += stb6000.o | ||
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c new file mode 100644 index 000000000000..21c1060cf10e --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.c | |||
@@ -0,0 +1,1685 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/firmware.h> | ||
32 | |||
33 | #include "dvb_frontend.h" | ||
34 | #include "af9013_priv.h" | ||
35 | #include "af9013.h" | ||
36 | |||
37 | int af9013_debug; | ||
38 | |||
39 | struct af9013_state { | ||
40 | struct i2c_adapter *i2c; | ||
41 | struct dvb_frontend frontend; | ||
42 | |||
43 | struct af9013_config config; | ||
44 | |||
45 | u16 signal_strength; | ||
46 | u32 ber; | ||
47 | u32 ucblocks; | ||
48 | u16 snr; | ||
49 | u32 frequency; | ||
50 | unsigned long next_statistics_check; | ||
51 | }; | ||
52 | |||
53 | static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; | ||
54 | |||
55 | static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, | ||
56 | u8 *val, u8 len) | ||
57 | { | ||
58 | u8 buf[3+len]; | ||
59 | struct i2c_msg msg = { | ||
60 | .addr = state->config.demod_address, | ||
61 | .flags = 0, | ||
62 | .len = sizeof(buf), | ||
63 | .buf = buf }; | ||
64 | |||
65 | buf[0] = reg >> 8; | ||
66 | buf[1] = reg & 0xff; | ||
67 | buf[2] = mbox; | ||
68 | memcpy(&buf[3], val, len); | ||
69 | |||
70 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
71 | warn("I2C write failed reg:%04x len:%d", reg, len); | ||
72 | return -EREMOTEIO; | ||
73 | } | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, | ||
78 | u8 len) | ||
79 | { | ||
80 | u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); | ||
81 | return af9013_write_regs(state, mbox, reg, val, len); | ||
82 | } | ||
83 | |||
84 | static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, | ||
85 | u8 len) | ||
86 | { | ||
87 | u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); | ||
88 | return af9013_write_regs(state, mbox, reg, val, len); | ||
89 | } | ||
90 | |||
91 | /* write single register */ | ||
92 | static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) | ||
93 | { | ||
94 | return af9013_write_ofdm_regs(state, reg, &val, 1); | ||
95 | } | ||
96 | |||
97 | /* read single register */ | ||
98 | static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) | ||
99 | { | ||
100 | u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; | ||
101 | u8 ibuf[1]; | ||
102 | struct i2c_msg msg[2] = { | ||
103 | { | ||
104 | .addr = state->config.demod_address, | ||
105 | .flags = 0, | ||
106 | .len = sizeof(obuf), | ||
107 | .buf = obuf | ||
108 | }, { | ||
109 | .addr = state->config.demod_address, | ||
110 | .flags = I2C_M_RD, | ||
111 | .len = sizeof(ibuf), | ||
112 | .buf = ibuf | ||
113 | } | ||
114 | }; | ||
115 | |||
116 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
117 | warn("I2C read failed reg:%04x", reg); | ||
118 | return -EREMOTEIO; | ||
119 | } | ||
120 | *val = ibuf[0]; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, | ||
125 | u8 len, u8 val) | ||
126 | { | ||
127 | int ret; | ||
128 | u8 tmp, mask; | ||
129 | |||
130 | ret = af9013_read_reg(state, reg, &tmp); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | mask = regmask[len - 1] << pos; | ||
135 | tmp = (tmp & ~mask) | ((val << pos) & mask); | ||
136 | |||
137 | return af9013_write_reg(state, reg, tmp); | ||
138 | } | ||
139 | |||
140 | static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, | ||
141 | u8 len, u8 *val) | ||
142 | { | ||
143 | int ret; | ||
144 | u8 tmp; | ||
145 | |||
146 | ret = af9013_read_reg(state, reg, &tmp); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | *val = (tmp >> pos) & regmask[len - 1]; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) | ||
154 | { | ||
155 | int ret; | ||
156 | u8 pos; | ||
157 | u16 addr; | ||
158 | deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); | ||
159 | |||
160 | /* GPIO0 & GPIO1 0xd735 | ||
161 | GPIO2 & GPIO3 0xd736 */ | ||
162 | |||
163 | switch (gpio) { | ||
164 | case 0: | ||
165 | case 1: | ||
166 | addr = 0xd735; | ||
167 | break; | ||
168 | case 2: | ||
169 | case 3: | ||
170 | addr = 0xd736; | ||
171 | break; | ||
172 | |||
173 | default: | ||
174 | err("invalid gpio:%d\n", gpio); | ||
175 | ret = -EINVAL; | ||
176 | goto error; | ||
177 | }; | ||
178 | |||
179 | switch (gpio) { | ||
180 | case 0: | ||
181 | case 2: | ||
182 | pos = 0; | ||
183 | break; | ||
184 | case 1: | ||
185 | case 3: | ||
186 | default: | ||
187 | pos = 4; | ||
188 | break; | ||
189 | }; | ||
190 | |||
191 | ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); | ||
192 | |||
193 | error: | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static u32 af913_div(u32 a, u32 b, u32 x) | ||
198 | { | ||
199 | u32 r = 0, c = 0, i; | ||
200 | deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); | ||
201 | |||
202 | if (a > b) { | ||
203 | c = a / b; | ||
204 | a = a - c * b; | ||
205 | } | ||
206 | |||
207 | for (i = 0; i < x; i++) { | ||
208 | if (a >= b) { | ||
209 | r += 1; | ||
210 | a -= b; | ||
211 | } | ||
212 | a <<= 1; | ||
213 | r <<= 1; | ||
214 | } | ||
215 | r = (c << (u32)x) + r; | ||
216 | |||
217 | deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); | ||
218 | return r; | ||
219 | } | ||
220 | |||
221 | static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) | ||
222 | { | ||
223 | int ret = 0; | ||
224 | u8 i = 0; | ||
225 | u8 buf[24]; | ||
226 | u32 ns_coeff1_2048nu; | ||
227 | u32 ns_coeff1_8191nu; | ||
228 | u32 ns_coeff1_8192nu; | ||
229 | u32 ns_coeff1_8193nu; | ||
230 | u32 ns_coeff2_2k; | ||
231 | u32 ns_coeff2_8k; | ||
232 | |||
233 | deb_info("%s: adc_clock:%d bw:%d\n", __func__, | ||
234 | state->config.adc_clock, bw); | ||
235 | |||
236 | switch (state->config.adc_clock) { | ||
237 | case 28800: /* 28.800 MHz */ | ||
238 | switch (bw) { | ||
239 | case BANDWIDTH_6_MHZ: | ||
240 | ns_coeff1_2048nu = 0x01e79e7a; | ||
241 | ns_coeff1_8191nu = 0x0079eb6e; | ||
242 | ns_coeff1_8192nu = 0x0079e79e; | ||
243 | ns_coeff1_8193nu = 0x0079e3cf; | ||
244 | ns_coeff2_2k = 0x00f3cf3d; | ||
245 | ns_coeff2_8k = 0x003cf3cf; | ||
246 | break; | ||
247 | case BANDWIDTH_7_MHZ: | ||
248 | ns_coeff1_2048nu = 0x0238e38e; | ||
249 | ns_coeff1_8191nu = 0x008e3d55; | ||
250 | ns_coeff1_8192nu = 0x008e38e4; | ||
251 | ns_coeff1_8193nu = 0x008e3472; | ||
252 | ns_coeff2_2k = 0x011c71c7; | ||
253 | ns_coeff2_8k = 0x00471c72; | ||
254 | break; | ||
255 | case BANDWIDTH_8_MHZ: | ||
256 | ns_coeff1_2048nu = 0x028a28a3; | ||
257 | ns_coeff1_8191nu = 0x00a28f3d; | ||
258 | ns_coeff1_8192nu = 0x00a28a29; | ||
259 | ns_coeff1_8193nu = 0x00a28514; | ||
260 | ns_coeff2_2k = 0x01451451; | ||
261 | ns_coeff2_8k = 0x00514514; | ||
262 | break; | ||
263 | default: | ||
264 | ret = -EINVAL; | ||
265 | } | ||
266 | break; | ||
267 | case 20480: /* 20.480 MHz */ | ||
268 | switch (bw) { | ||
269 | case BANDWIDTH_6_MHZ: | ||
270 | ns_coeff1_2048nu = 0x02adb6dc; | ||
271 | ns_coeff1_8191nu = 0x00ab7313; | ||
272 | ns_coeff1_8192nu = 0x00ab6db7; | ||
273 | ns_coeff1_8193nu = 0x00ab685c; | ||
274 | ns_coeff2_2k = 0x0156db6e; | ||
275 | ns_coeff2_8k = 0x0055b6dc; | ||
276 | break; | ||
277 | case BANDWIDTH_7_MHZ: | ||
278 | ns_coeff1_2048nu = 0x03200001; | ||
279 | ns_coeff1_8191nu = 0x00c80640; | ||
280 | ns_coeff1_8192nu = 0x00c80000; | ||
281 | ns_coeff1_8193nu = 0x00c7f9c0; | ||
282 | ns_coeff2_2k = 0x01900000; | ||
283 | ns_coeff2_8k = 0x00640000; | ||
284 | break; | ||
285 | case BANDWIDTH_8_MHZ: | ||
286 | ns_coeff1_2048nu = 0x03924926; | ||
287 | ns_coeff1_8191nu = 0x00e4996e; | ||
288 | ns_coeff1_8192nu = 0x00e49249; | ||
289 | ns_coeff1_8193nu = 0x00e48b25; | ||
290 | ns_coeff2_2k = 0x01c92493; | ||
291 | ns_coeff2_8k = 0x00724925; | ||
292 | break; | ||
293 | default: | ||
294 | ret = -EINVAL; | ||
295 | } | ||
296 | break; | ||
297 | case 28000: /* 28.000 MHz */ | ||
298 | switch (bw) { | ||
299 | case BANDWIDTH_6_MHZ: | ||
300 | ns_coeff1_2048nu = 0x01f58d10; | ||
301 | ns_coeff1_8191nu = 0x007d672f; | ||
302 | ns_coeff1_8192nu = 0x007d6344; | ||
303 | ns_coeff1_8193nu = 0x007d5f59; | ||
304 | ns_coeff2_2k = 0x00fac688; | ||
305 | ns_coeff2_8k = 0x003eb1a2; | ||
306 | break; | ||
307 | case BANDWIDTH_7_MHZ: | ||
308 | ns_coeff1_2048nu = 0x02492492; | ||
309 | ns_coeff1_8191nu = 0x00924db7; | ||
310 | ns_coeff1_8192nu = 0x00924925; | ||
311 | ns_coeff1_8193nu = 0x00924492; | ||
312 | ns_coeff2_2k = 0x01249249; | ||
313 | ns_coeff2_8k = 0x00492492; | ||
314 | break; | ||
315 | case BANDWIDTH_8_MHZ: | ||
316 | ns_coeff1_2048nu = 0x029cbc15; | ||
317 | ns_coeff1_8191nu = 0x00a7343f; | ||
318 | ns_coeff1_8192nu = 0x00a72f05; | ||
319 | ns_coeff1_8193nu = 0x00a729cc; | ||
320 | ns_coeff2_2k = 0x014e5e0a; | ||
321 | ns_coeff2_8k = 0x00539783; | ||
322 | break; | ||
323 | default: | ||
324 | ret = -EINVAL; | ||
325 | } | ||
326 | break; | ||
327 | case 25000: /* 25.000 MHz */ | ||
328 | switch (bw) { | ||
329 | case BANDWIDTH_6_MHZ: | ||
330 | ns_coeff1_2048nu = 0x0231bcb5; | ||
331 | ns_coeff1_8191nu = 0x008c7391; | ||
332 | ns_coeff1_8192nu = 0x008c6f2d; | ||
333 | ns_coeff1_8193nu = 0x008c6aca; | ||
334 | ns_coeff2_2k = 0x0118de5b; | ||
335 | ns_coeff2_8k = 0x00463797; | ||
336 | break; | ||
337 | case BANDWIDTH_7_MHZ: | ||
338 | ns_coeff1_2048nu = 0x028f5c29; | ||
339 | ns_coeff1_8191nu = 0x00a3dc29; | ||
340 | ns_coeff1_8192nu = 0x00a3d70a; | ||
341 | ns_coeff1_8193nu = 0x00a3d1ec; | ||
342 | ns_coeff2_2k = 0x0147ae14; | ||
343 | ns_coeff2_8k = 0x0051eb85; | ||
344 | break; | ||
345 | case BANDWIDTH_8_MHZ: | ||
346 | ns_coeff1_2048nu = 0x02ecfb9d; | ||
347 | ns_coeff1_8191nu = 0x00bb44c1; | ||
348 | ns_coeff1_8192nu = 0x00bb3ee7; | ||
349 | ns_coeff1_8193nu = 0x00bb390d; | ||
350 | ns_coeff2_2k = 0x01767dce; | ||
351 | ns_coeff2_8k = 0x005d9f74; | ||
352 | break; | ||
353 | default: | ||
354 | ret = -EINVAL; | ||
355 | } | ||
356 | break; | ||
357 | default: | ||
358 | err("invalid xtal"); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | if (ret) { | ||
362 | err("invalid bandwidth"); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24); | ||
367 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16); | ||
368 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8); | ||
369 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff)); | ||
370 | buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22); | ||
371 | buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14); | ||
372 | buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6); | ||
373 | buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f)); | ||
374 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24); | ||
375 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16); | ||
376 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8); | ||
377 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff)); | ||
378 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24); | ||
379 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16); | ||
380 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8); | ||
381 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff)); | ||
382 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24); | ||
383 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16); | ||
384 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8); | ||
385 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff)); | ||
386 | buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22); | ||
387 | buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14); | ||
388 | buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6); | ||
389 | buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f)); | ||
390 | |||
391 | deb_info("%s: coeff:", __func__); | ||
392 | debug_dump(buf, sizeof(buf), deb_info); | ||
393 | |||
394 | /* program */ | ||
395 | for (i = 0; i < sizeof(buf); i++) { | ||
396 | ret = af9013_write_reg(state, 0xae00 + i, buf[i]); | ||
397 | if (ret) | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int af9013_set_adc_ctrl(struct af9013_state *state) | ||
405 | { | ||
406 | int ret; | ||
407 | u8 buf[3], tmp, i; | ||
408 | u32 adc_cw; | ||
409 | |||
410 | deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); | ||
411 | |||
412 | /* adc frequency type */ | ||
413 | switch (state->config.adc_clock) { | ||
414 | case 28800: /* 28.800 MHz */ | ||
415 | tmp = 0; | ||
416 | break; | ||
417 | case 20480: /* 20.480 MHz */ | ||
418 | tmp = 1; | ||
419 | break; | ||
420 | case 28000: /* 28.000 MHz */ | ||
421 | tmp = 2; | ||
422 | break; | ||
423 | case 25000: /* 25.000 MHz */ | ||
424 | tmp = 3; | ||
425 | break; | ||
426 | default: | ||
427 | err("invalid xtal"); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); | ||
432 | |||
433 | buf[0] = (u8) ((adc_cw & 0x000000ff)); | ||
434 | buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); | ||
435 | buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); | ||
436 | |||
437 | deb_info("%s: adc_cw:", __func__); | ||
438 | debug_dump(buf, sizeof(buf), deb_info); | ||
439 | |||
440 | /* program */ | ||
441 | for (i = 0; i < sizeof(buf); i++) { | ||
442 | ret = af9013_write_reg(state, 0xd180 + i, buf[i]); | ||
443 | if (ret) | ||
444 | goto error; | ||
445 | } | ||
446 | ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); | ||
447 | error: | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) | ||
452 | { | ||
453 | int ret; | ||
454 | u16 addr; | ||
455 | u8 buf[3], i, j; | ||
456 | u32 adc_freq, freq_cw; | ||
457 | s8 bfs_spec_inv; | ||
458 | int if_sample_freq; | ||
459 | |||
460 | for (j = 0; j < 3; j++) { | ||
461 | if (j == 0) { | ||
462 | addr = 0xd140; /* fcw normal */ | ||
463 | bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; | ||
464 | } else if (j == 1) { | ||
465 | addr = 0x9be7; /* fcw dummy ram */ | ||
466 | bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; | ||
467 | } else { | ||
468 | addr = 0x9bea; /* fcw inverted */ | ||
469 | bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; | ||
470 | } | ||
471 | |||
472 | adc_freq = state->config.adc_clock * 1000; | ||
473 | if_sample_freq = state->config.tuner_if * 1000; | ||
474 | |||
475 | /* TDA18271 uses different sampling freq for every bw */ | ||
476 | if (state->config.tuner == AF9013_TUNER_TDA18271) { | ||
477 | switch (bw) { | ||
478 | case BANDWIDTH_6_MHZ: | ||
479 | if_sample_freq = 3300000; /* 3.3 MHz */ | ||
480 | break; | ||
481 | case BANDWIDTH_7_MHZ: | ||
482 | if_sample_freq = 3800000; /* 3.8 MHz */ | ||
483 | break; | ||
484 | case BANDWIDTH_8_MHZ: | ||
485 | default: | ||
486 | if_sample_freq = 4300000; /* 4.3 MHz */ | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | while (if_sample_freq > (adc_freq / 2)) | ||
492 | if_sample_freq = if_sample_freq - adc_freq; | ||
493 | |||
494 | if (if_sample_freq >= 0) | ||
495 | bfs_spec_inv = bfs_spec_inv * (-1); | ||
496 | else | ||
497 | if_sample_freq = if_sample_freq * (-1); | ||
498 | |||
499 | freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); | ||
500 | |||
501 | if (bfs_spec_inv == -1) | ||
502 | freq_cw = 0x00800000 - freq_cw; | ||
503 | |||
504 | buf[0] = (u8) ((freq_cw & 0x000000ff)); | ||
505 | buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); | ||
506 | buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); | ||
507 | |||
508 | |||
509 | deb_info("%s: freq_cw:", __func__); | ||
510 | debug_dump(buf, sizeof(buf), deb_info); | ||
511 | |||
512 | /* program */ | ||
513 | for (i = 0; i < sizeof(buf); i++) { | ||
514 | ret = af9013_write_reg(state, addr++, buf[i]); | ||
515 | if (ret) | ||
516 | goto error; | ||
517 | } | ||
518 | } | ||
519 | error: | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static int af9013_set_ofdm_params(struct af9013_state *state, | ||
524 | struct dvb_ofdm_parameters *params, u8 *auto_mode) | ||
525 | { | ||
526 | int ret; | ||
527 | u8 i, buf[3] = {0, 0, 0}; | ||
528 | *auto_mode = 0; /* set if parameters are requested to auto set */ | ||
529 | |||
530 | switch (params->transmission_mode) { | ||
531 | case TRANSMISSION_MODE_AUTO: | ||
532 | *auto_mode = 1; | ||
533 | case TRANSMISSION_MODE_2K: | ||
534 | break; | ||
535 | case TRANSMISSION_MODE_8K: | ||
536 | buf[0] |= (1 << 0); | ||
537 | break; | ||
538 | default: | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | switch (params->guard_interval) { | ||
543 | case GUARD_INTERVAL_AUTO: | ||
544 | *auto_mode = 1; | ||
545 | case GUARD_INTERVAL_1_32: | ||
546 | break; | ||
547 | case GUARD_INTERVAL_1_16: | ||
548 | buf[0] |= (1 << 2); | ||
549 | break; | ||
550 | case GUARD_INTERVAL_1_8: | ||
551 | buf[0] |= (2 << 2); | ||
552 | break; | ||
553 | case GUARD_INTERVAL_1_4: | ||
554 | buf[0] |= (3 << 2); | ||
555 | break; | ||
556 | default: | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | switch (params->hierarchy_information) { | ||
561 | case HIERARCHY_AUTO: | ||
562 | *auto_mode = 1; | ||
563 | case HIERARCHY_NONE: | ||
564 | break; | ||
565 | case HIERARCHY_1: | ||
566 | buf[0] |= (1 << 4); | ||
567 | break; | ||
568 | case HIERARCHY_2: | ||
569 | buf[0] |= (2 << 4); | ||
570 | break; | ||
571 | case HIERARCHY_4: | ||
572 | buf[0] |= (3 << 4); | ||
573 | break; | ||
574 | default: | ||
575 | return -EINVAL; | ||
576 | }; | ||
577 | |||
578 | switch (params->constellation) { | ||
579 | case QAM_AUTO: | ||
580 | *auto_mode = 1; | ||
581 | case QPSK: | ||
582 | break; | ||
583 | case QAM_16: | ||
584 | buf[1] |= (1 << 6); | ||
585 | break; | ||
586 | case QAM_64: | ||
587 | buf[1] |= (2 << 6); | ||
588 | break; | ||
589 | default: | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | |||
593 | /* Use HP. How and which case we can switch to LP? */ | ||
594 | buf[1] |= (1 << 4); | ||
595 | |||
596 | switch (params->code_rate_HP) { | ||
597 | case FEC_AUTO: | ||
598 | *auto_mode = 1; | ||
599 | case FEC_1_2: | ||
600 | break; | ||
601 | case FEC_2_3: | ||
602 | buf[2] |= (1 << 0); | ||
603 | break; | ||
604 | case FEC_3_4: | ||
605 | buf[2] |= (2 << 0); | ||
606 | break; | ||
607 | case FEC_5_6: | ||
608 | buf[2] |= (3 << 0); | ||
609 | break; | ||
610 | case FEC_7_8: | ||
611 | buf[2] |= (4 << 0); | ||
612 | break; | ||
613 | default: | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | |||
617 | switch (params->code_rate_LP) { | ||
618 | case FEC_AUTO: | ||
619 | /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO | ||
620 | by dvb_frontend.c for compatibility */ | ||
621 | if (params->hierarchy_information != HIERARCHY_NONE) | ||
622 | *auto_mode = 1; | ||
623 | case FEC_1_2: | ||
624 | break; | ||
625 | case FEC_2_3: | ||
626 | buf[2] |= (1 << 3); | ||
627 | break; | ||
628 | case FEC_3_4: | ||
629 | buf[2] |= (2 << 3); | ||
630 | break; | ||
631 | case FEC_5_6: | ||
632 | buf[2] |= (3 << 3); | ||
633 | break; | ||
634 | case FEC_7_8: | ||
635 | buf[2] |= (4 << 3); | ||
636 | break; | ||
637 | case FEC_NONE: | ||
638 | if (params->hierarchy_information == HIERARCHY_AUTO) | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | switch (params->bandwidth) { | ||
645 | case BANDWIDTH_6_MHZ: | ||
646 | break; | ||
647 | case BANDWIDTH_7_MHZ: | ||
648 | buf[1] |= (1 << 2); | ||
649 | break; | ||
650 | case BANDWIDTH_8_MHZ: | ||
651 | buf[1] |= (2 << 2); | ||
652 | break; | ||
653 | default: | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | |||
657 | /* program */ | ||
658 | for (i = 0; i < sizeof(buf); i++) { | ||
659 | ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); | ||
660 | if (ret) | ||
661 | break; | ||
662 | } | ||
663 | |||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | static int af9013_reset(struct af9013_state *state, u8 sleep) | ||
668 | { | ||
669 | int ret; | ||
670 | u8 tmp, i; | ||
671 | deb_info("%s\n", __func__); | ||
672 | |||
673 | /* enable OFDM reset */ | ||
674 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); | ||
675 | if (ret) | ||
676 | goto error; | ||
677 | |||
678 | /* start reset mechanism */ | ||
679 | ret = af9013_write_reg(state, 0xaeff, 1); | ||
680 | if (ret) | ||
681 | goto error; | ||
682 | |||
683 | /* reset is done when bit 1 is set */ | ||
684 | for (i = 0; i < 150; i++) { | ||
685 | ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); | ||
686 | if (ret) | ||
687 | goto error; | ||
688 | if (tmp) | ||
689 | break; /* reset done */ | ||
690 | msleep(10); | ||
691 | } | ||
692 | if (!tmp) | ||
693 | return -ETIMEDOUT; | ||
694 | |||
695 | /* don't clear reset when going to sleep */ | ||
696 | if (!sleep) { | ||
697 | /* clear OFDM reset */ | ||
698 | ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); | ||
699 | if (ret) | ||
700 | goto error; | ||
701 | |||
702 | /* disable OFDM reset */ | ||
703 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); | ||
704 | } | ||
705 | error: | ||
706 | return ret; | ||
707 | } | ||
708 | |||
709 | static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) | ||
710 | { | ||
711 | int ret; | ||
712 | deb_info("%s: onoff:%d\n", __func__, onoff); | ||
713 | |||
714 | if (onoff) { | ||
715 | /* power on */ | ||
716 | ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); | ||
717 | if (ret) | ||
718 | goto error; | ||
719 | ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); | ||
720 | if (ret) | ||
721 | goto error; | ||
722 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); | ||
723 | } else { | ||
724 | /* power off */ | ||
725 | ret = af9013_reset(state, 1); | ||
726 | if (ret) | ||
727 | goto error; | ||
728 | ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); | ||
729 | } | ||
730 | error: | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | static int af9013_lock_led(struct af9013_state *state, u8 onoff) | ||
735 | { | ||
736 | deb_info("%s: onoff:%d\n", __func__, onoff); | ||
737 | |||
738 | return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); | ||
739 | } | ||
740 | |||
741 | static int af9013_set_frontend(struct dvb_frontend *fe, | ||
742 | struct dvb_frontend_parameters *params) | ||
743 | { | ||
744 | struct af9013_state *state = fe->demodulator_priv; | ||
745 | int ret; | ||
746 | u8 auto_mode; /* auto set TPS */ | ||
747 | |||
748 | deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, | ||
749 | params->u.ofdm.bandwidth); | ||
750 | |||
751 | state->frequency = params->frequency; | ||
752 | |||
753 | /* program CFOE coefficients */ | ||
754 | ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); | ||
755 | if (ret) | ||
756 | goto error; | ||
757 | |||
758 | /* program frequency control */ | ||
759 | ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); | ||
760 | if (ret) | ||
761 | goto error; | ||
762 | |||
763 | /* clear TPS lock flag (inverted flag) */ | ||
764 | ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); | ||
765 | if (ret) | ||
766 | goto error; | ||
767 | |||
768 | /* clear MPEG2 lock flag */ | ||
769 | ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); | ||
770 | if (ret) | ||
771 | goto error; | ||
772 | |||
773 | /* empty channel function */ | ||
774 | ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); | ||
775 | if (ret) | ||
776 | goto error; | ||
777 | |||
778 | /* empty DVB-T channel function */ | ||
779 | ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); | ||
780 | if (ret) | ||
781 | goto error; | ||
782 | |||
783 | /* program tuner */ | ||
784 | if (fe->ops.tuner_ops.set_params) | ||
785 | fe->ops.tuner_ops.set_params(fe, params); | ||
786 | |||
787 | /* program TPS and bandwidth, check if auto mode needed */ | ||
788 | ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); | ||
789 | if (ret) | ||
790 | goto error; | ||
791 | |||
792 | if (auto_mode) { | ||
793 | /* clear easy mode flag */ | ||
794 | ret = af9013_write_reg(state, 0xaefd, 0); | ||
795 | deb_info("%s: auto TPS\n", __func__); | ||
796 | } else { | ||
797 | /* set easy mode flag */ | ||
798 | ret = af9013_write_reg(state, 0xaefd, 1); | ||
799 | if (ret) | ||
800 | goto error; | ||
801 | ret = af9013_write_reg(state, 0xaefe, 0); | ||
802 | deb_info("%s: manual TPS\n", __func__); | ||
803 | } | ||
804 | if (ret) | ||
805 | goto error; | ||
806 | |||
807 | /* everything is set, lets try to receive channel - OFSM GO! */ | ||
808 | ret = af9013_write_reg(state, 0xffff, 0); | ||
809 | if (ret) | ||
810 | goto error; | ||
811 | |||
812 | error: | ||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | static int af9013_get_frontend(struct dvb_frontend *fe, | ||
817 | struct dvb_frontend_parameters *p) | ||
818 | { | ||
819 | struct af9013_state *state = fe->demodulator_priv; | ||
820 | int ret; | ||
821 | u8 i, buf[3]; | ||
822 | deb_info("%s\n", __func__); | ||
823 | |||
824 | /* read TPS registers */ | ||
825 | for (i = 0; i < 3; i++) { | ||
826 | ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); | ||
827 | if (ret) | ||
828 | goto error; | ||
829 | } | ||
830 | |||
831 | switch ((buf[1] >> 6) & 3) { | ||
832 | case 0: | ||
833 | p->u.ofdm.constellation = QPSK; | ||
834 | break; | ||
835 | case 1: | ||
836 | p->u.ofdm.constellation = QAM_16; | ||
837 | break; | ||
838 | case 2: | ||
839 | p->u.ofdm.constellation = QAM_64; | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | switch ((buf[0] >> 0) & 3) { | ||
844 | case 0: | ||
845 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||
846 | break; | ||
847 | case 1: | ||
848 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; | ||
849 | } | ||
850 | |||
851 | switch ((buf[0] >> 2) & 3) { | ||
852 | case 0: | ||
853 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||
854 | break; | ||
855 | case 1: | ||
856 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; | ||
857 | break; | ||
858 | case 2: | ||
859 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; | ||
860 | break; | ||
861 | case 3: | ||
862 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; | ||
863 | break; | ||
864 | } | ||
865 | |||
866 | switch ((buf[0] >> 4) & 7) { | ||
867 | case 0: | ||
868 | p->u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||
869 | break; | ||
870 | case 1: | ||
871 | p->u.ofdm.hierarchy_information = HIERARCHY_1; | ||
872 | break; | ||
873 | case 2: | ||
874 | p->u.ofdm.hierarchy_information = HIERARCHY_2; | ||
875 | break; | ||
876 | case 3: | ||
877 | p->u.ofdm.hierarchy_information = HIERARCHY_4; | ||
878 | break; | ||
879 | } | ||
880 | |||
881 | switch ((buf[2] >> 0) & 7) { | ||
882 | case 0: | ||
883 | p->u.ofdm.code_rate_HP = FEC_1_2; | ||
884 | break; | ||
885 | case 1: | ||
886 | p->u.ofdm.code_rate_HP = FEC_2_3; | ||
887 | break; | ||
888 | case 2: | ||
889 | p->u.ofdm.code_rate_HP = FEC_3_4; | ||
890 | break; | ||
891 | case 3: | ||
892 | p->u.ofdm.code_rate_HP = FEC_5_6; | ||
893 | break; | ||
894 | case 4: | ||
895 | p->u.ofdm.code_rate_HP = FEC_7_8; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | switch ((buf[2] >> 3) & 7) { | ||
900 | case 0: | ||
901 | p->u.ofdm.code_rate_LP = FEC_1_2; | ||
902 | break; | ||
903 | case 1: | ||
904 | p->u.ofdm.code_rate_LP = FEC_2_3; | ||
905 | break; | ||
906 | case 2: | ||
907 | p->u.ofdm.code_rate_LP = FEC_3_4; | ||
908 | break; | ||
909 | case 3: | ||
910 | p->u.ofdm.code_rate_LP = FEC_5_6; | ||
911 | break; | ||
912 | case 4: | ||
913 | p->u.ofdm.code_rate_LP = FEC_7_8; | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | switch ((buf[1] >> 2) & 3) { | ||
918 | case 0: | ||
919 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
920 | break; | ||
921 | case 1: | ||
922 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
923 | break; | ||
924 | case 2: | ||
925 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
926 | break; | ||
927 | } | ||
928 | |||
929 | p->inversion = INVERSION_AUTO; | ||
930 | p->frequency = state->frequency; | ||
931 | |||
932 | error: | ||
933 | return ret; | ||
934 | } | ||
935 | |||
936 | static int af9013_update_ber_unc(struct dvb_frontend *fe) | ||
937 | { | ||
938 | struct af9013_state *state = fe->demodulator_priv; | ||
939 | int ret; | ||
940 | u8 buf[3], i; | ||
941 | u32 error_bit_count = 0; | ||
942 | u32 total_bit_count = 0; | ||
943 | u32 abort_packet_count = 0; | ||
944 | |||
945 | state->ber = 0; | ||
946 | |||
947 | /* check if error bit count is ready */ | ||
948 | ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); | ||
949 | if (ret) | ||
950 | goto error; | ||
951 | if (!buf[0]) | ||
952 | goto exit; | ||
953 | |||
954 | /* get RSD packet abort count */ | ||
955 | for (i = 0; i < 2; i++) { | ||
956 | ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); | ||
957 | if (ret) | ||
958 | goto error; | ||
959 | } | ||
960 | abort_packet_count = (buf[1] << 8) + buf[0]; | ||
961 | |||
962 | /* get error bit count */ | ||
963 | for (i = 0; i < 3; i++) { | ||
964 | ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); | ||
965 | if (ret) | ||
966 | goto error; | ||
967 | } | ||
968 | error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
969 | error_bit_count = error_bit_count - abort_packet_count * 8 * 8; | ||
970 | |||
971 | /* get used RSD counting period (10000 RSD packets used) */ | ||
972 | for (i = 0; i < 2; i++) { | ||
973 | ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); | ||
974 | if (ret) | ||
975 | goto error; | ||
976 | } | ||
977 | total_bit_count = (buf[1] << 8) + buf[0]; | ||
978 | total_bit_count = total_bit_count - abort_packet_count; | ||
979 | total_bit_count = total_bit_count * 204 * 8; | ||
980 | |||
981 | if (total_bit_count) | ||
982 | state->ber = error_bit_count * 1000000000 / total_bit_count; | ||
983 | |||
984 | state->ucblocks += abort_packet_count; | ||
985 | |||
986 | deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, | ||
987 | error_bit_count, total_bit_count, abort_packet_count); | ||
988 | |||
989 | /* set BER counting range */ | ||
990 | ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); | ||
991 | if (ret) | ||
992 | goto error; | ||
993 | ret = af9013_write_reg(state, 0xd386, 10000 >> 8); | ||
994 | if (ret) | ||
995 | goto error; | ||
996 | /* reset and start BER counter */ | ||
997 | ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); | ||
998 | if (ret) | ||
999 | goto error; | ||
1000 | |||
1001 | exit: | ||
1002 | error: | ||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | static int af9013_update_snr(struct dvb_frontend *fe) | ||
1007 | { | ||
1008 | struct af9013_state *state = fe->demodulator_priv; | ||
1009 | int ret; | ||
1010 | u8 buf[3], i, len; | ||
1011 | u32 quant = 0; | ||
1012 | struct snr_table *snr_table; | ||
1013 | |||
1014 | /* check if quantizer ready (for snr) */ | ||
1015 | ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); | ||
1016 | if (ret) | ||
1017 | goto error; | ||
1018 | if (buf[0]) { | ||
1019 | /* quantizer ready - read it */ | ||
1020 | for (i = 0; i < 3; i++) { | ||
1021 | ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); | ||
1022 | if (ret) | ||
1023 | goto error; | ||
1024 | } | ||
1025 | quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
1026 | |||
1027 | /* read current constellation */ | ||
1028 | ret = af9013_read_reg(state, 0xd3c1, &buf[0]); | ||
1029 | if (ret) | ||
1030 | goto error; | ||
1031 | |||
1032 | switch ((buf[0] >> 6) & 3) { | ||
1033 | case 0: | ||
1034 | len = ARRAY_SIZE(qpsk_snr_table); | ||
1035 | snr_table = qpsk_snr_table; | ||
1036 | break; | ||
1037 | case 1: | ||
1038 | len = ARRAY_SIZE(qam16_snr_table); | ||
1039 | snr_table = qam16_snr_table; | ||
1040 | break; | ||
1041 | case 2: | ||
1042 | len = ARRAY_SIZE(qam64_snr_table); | ||
1043 | snr_table = qam64_snr_table; | ||
1044 | break; | ||
1045 | default: | ||
1046 | len = 0; | ||
1047 | break; | ||
1048 | } | ||
1049 | |||
1050 | if (len) { | ||
1051 | for (i = 0; i < len; i++) { | ||
1052 | if (quant < snr_table[i].val) { | ||
1053 | state->snr = snr_table[i].snr * 10; | ||
1054 | break; | ||
1055 | } | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1059 | /* set quantizer super frame count */ | ||
1060 | ret = af9013_write_reg(state, 0xd2e2, 1); | ||
1061 | if (ret) | ||
1062 | goto error; | ||
1063 | |||
1064 | /* check quantizer availability */ | ||
1065 | for (i = 0; i < 10; i++) { | ||
1066 | msleep(10); | ||
1067 | ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, | ||
1068 | &buf[0]); | ||
1069 | if (ret) | ||
1070 | goto error; | ||
1071 | if (!buf[0]) | ||
1072 | break; | ||
1073 | } | ||
1074 | |||
1075 | /* reset quantizer */ | ||
1076 | ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); | ||
1077 | if (ret) | ||
1078 | goto error; | ||
1079 | } | ||
1080 | |||
1081 | error: | ||
1082 | return ret; | ||
1083 | } | ||
1084 | |||
1085 | static int af9013_update_signal_strength(struct dvb_frontend *fe) | ||
1086 | { | ||
1087 | struct af9013_state *state = fe->demodulator_priv; | ||
1088 | int ret; | ||
1089 | u8 tmp0; | ||
1090 | u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80; | ||
1091 | int signal_strength; | ||
1092 | |||
1093 | deb_info("%s\n", __func__); | ||
1094 | |||
1095 | state->signal_strength = 0; | ||
1096 | |||
1097 | ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0); | ||
1098 | if (ret) | ||
1099 | goto error; | ||
1100 | if (tmp0) { | ||
1101 | ret = af9013_read_reg(state, 0x9bbd, &rf_50); | ||
1102 | if (ret) | ||
1103 | goto error; | ||
1104 | ret = af9013_read_reg(state, 0x9bd0, &rf_80); | ||
1105 | if (ret) | ||
1106 | goto error; | ||
1107 | ret = af9013_read_reg(state, 0x9be2, &if_50); | ||
1108 | if (ret) | ||
1109 | goto error; | ||
1110 | ret = af9013_read_reg(state, 0x9be4, &if_80); | ||
1111 | if (ret) | ||
1112 | goto error; | ||
1113 | ret = af9013_read_reg(state, 0xd07c, &rf_gain); | ||
1114 | if (ret) | ||
1115 | goto error; | ||
1116 | ret = af9013_read_reg(state, 0xd07d, &if_gain); | ||
1117 | if (ret) | ||
1118 | goto error; | ||
1119 | signal_strength = (0xffff / (9 * (rf_50 + if_50) - \ | ||
1120 | 11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \ | ||
1121 | 11 * (rf_80 + if_80)); | ||
1122 | if (signal_strength < 0) | ||
1123 | signal_strength = 0; | ||
1124 | else if (signal_strength > 0xffff) | ||
1125 | signal_strength = 0xffff; | ||
1126 | |||
1127 | state->signal_strength = signal_strength; | ||
1128 | } | ||
1129 | |||
1130 | error: | ||
1131 | return ret; | ||
1132 | } | ||
1133 | |||
1134 | static int af9013_update_statistics(struct dvb_frontend *fe) | ||
1135 | { | ||
1136 | struct af9013_state *state = fe->demodulator_priv; | ||
1137 | int ret; | ||
1138 | |||
1139 | if (time_before(jiffies, state->next_statistics_check)) | ||
1140 | return 0; | ||
1141 | |||
1142 | /* set minimum statistic update interval */ | ||
1143 | state->next_statistics_check = jiffies + msecs_to_jiffies(1200); | ||
1144 | |||
1145 | ret = af9013_update_signal_strength(fe); | ||
1146 | if (ret) | ||
1147 | goto error; | ||
1148 | ret = af9013_update_snr(fe); | ||
1149 | if (ret) | ||
1150 | goto error; | ||
1151 | ret = af9013_update_ber_unc(fe); | ||
1152 | if (ret) | ||
1153 | goto error; | ||
1154 | |||
1155 | error: | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | static int af9013_get_tune_settings(struct dvb_frontend *fe, | ||
1160 | struct dvb_frontend_tune_settings *fesettings) | ||
1161 | { | ||
1162 | fesettings->min_delay_ms = 800; | ||
1163 | fesettings->step_size = 0; | ||
1164 | fesettings->max_drift = 0; | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
1170 | { | ||
1171 | struct af9013_state *state = fe->demodulator_priv; | ||
1172 | int ret = 0; | ||
1173 | u8 tmp; | ||
1174 | *status = 0; | ||
1175 | |||
1176 | /* TPS lock */ | ||
1177 | ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); | ||
1178 | if (ret) | ||
1179 | goto error; | ||
1180 | if (tmp) | ||
1181 | *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; | ||
1182 | |||
1183 | /* MPEG2 lock */ | ||
1184 | ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); | ||
1185 | if (ret) | ||
1186 | goto error; | ||
1187 | if (tmp) | ||
1188 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
1189 | |||
1190 | if (!*status & FE_HAS_SIGNAL) { | ||
1191 | /* AGC lock */ | ||
1192 | ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); | ||
1193 | if (ret) | ||
1194 | goto error; | ||
1195 | if (tmp) | ||
1196 | *status |= FE_HAS_SIGNAL; | ||
1197 | } | ||
1198 | |||
1199 | if (!*status & FE_HAS_CARRIER) { | ||
1200 | /* CFO lock */ | ||
1201 | ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); | ||
1202 | if (ret) | ||
1203 | goto error; | ||
1204 | if (tmp) | ||
1205 | *status |= FE_HAS_CARRIER; | ||
1206 | } | ||
1207 | |||
1208 | if (!*status & FE_HAS_CARRIER) { | ||
1209 | /* SFOE lock */ | ||
1210 | ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); | ||
1211 | if (ret) | ||
1212 | goto error; | ||
1213 | if (tmp) | ||
1214 | *status |= FE_HAS_CARRIER; | ||
1215 | } | ||
1216 | |||
1217 | ret = af9013_update_statistics(fe); | ||
1218 | |||
1219 | error: | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
1225 | { | ||
1226 | struct af9013_state *state = fe->demodulator_priv; | ||
1227 | int ret; | ||
1228 | ret = af9013_update_statistics(fe); | ||
1229 | *ber = state->ber; | ||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
1234 | { | ||
1235 | struct af9013_state *state = fe->demodulator_priv; | ||
1236 | int ret; | ||
1237 | ret = af9013_update_statistics(fe); | ||
1238 | *strength = state->signal_strength; | ||
1239 | return ret; | ||
1240 | } | ||
1241 | |||
1242 | static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
1243 | { | ||
1244 | struct af9013_state *state = fe->demodulator_priv; | ||
1245 | int ret; | ||
1246 | ret = af9013_update_statistics(fe); | ||
1247 | *snr = state->snr; | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
1252 | { | ||
1253 | struct af9013_state *state = fe->demodulator_priv; | ||
1254 | int ret; | ||
1255 | ret = af9013_update_statistics(fe); | ||
1256 | *ucblocks = state->ucblocks; | ||
1257 | return ret; | ||
1258 | } | ||
1259 | |||
1260 | static int af9013_sleep(struct dvb_frontend *fe) | ||
1261 | { | ||
1262 | struct af9013_state *state = fe->demodulator_priv; | ||
1263 | int ret; | ||
1264 | deb_info("%s\n", __func__); | ||
1265 | |||
1266 | ret = af9013_lock_led(state, 0); | ||
1267 | if (ret) | ||
1268 | goto error; | ||
1269 | |||
1270 | ret = af9013_power_ctrl(state, 0); | ||
1271 | error: | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | static int af9013_init(struct dvb_frontend *fe) | ||
1276 | { | ||
1277 | struct af9013_state *state = fe->demodulator_priv; | ||
1278 | int ret, i, len; | ||
1279 | u8 tmp0, tmp1; | ||
1280 | struct regdesc *init; | ||
1281 | deb_info("%s\n", __func__); | ||
1282 | |||
1283 | /* reset OFDM */ | ||
1284 | ret = af9013_reset(state, 0); | ||
1285 | if (ret) | ||
1286 | goto error; | ||
1287 | |||
1288 | /* power on */ | ||
1289 | ret = af9013_power_ctrl(state, 1); | ||
1290 | if (ret) | ||
1291 | goto error; | ||
1292 | |||
1293 | /* enable ADC */ | ||
1294 | ret = af9013_write_reg(state, 0xd73a, 0xa4); | ||
1295 | if (ret) | ||
1296 | goto error; | ||
1297 | |||
1298 | /* write API version to firmware */ | ||
1299 | for (i = 0; i < sizeof(state->config.api_version); i++) { | ||
1300 | ret = af9013_write_reg(state, 0x9bf2 + i, | ||
1301 | state->config.api_version[i]); | ||
1302 | if (ret) | ||
1303 | goto error; | ||
1304 | } | ||
1305 | |||
1306 | /* program ADC control */ | ||
1307 | ret = af9013_set_adc_ctrl(state); | ||
1308 | if (ret) | ||
1309 | goto error; | ||
1310 | |||
1311 | /* set I2C master clock */ | ||
1312 | ret = af9013_write_reg(state, 0xd416, 0x14); | ||
1313 | if (ret) | ||
1314 | goto error; | ||
1315 | |||
1316 | /* set 16 embx */ | ||
1317 | ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); | ||
1318 | if (ret) | ||
1319 | goto error; | ||
1320 | |||
1321 | /* set no trigger */ | ||
1322 | ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); | ||
1323 | if (ret) | ||
1324 | goto error; | ||
1325 | |||
1326 | /* set read-update bit for constellation */ | ||
1327 | ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); | ||
1328 | if (ret) | ||
1329 | goto error; | ||
1330 | |||
1331 | /* enable FEC monitor */ | ||
1332 | ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); | ||
1333 | if (ret) | ||
1334 | goto error; | ||
1335 | |||
1336 | /* load OFSM settings */ | ||
1337 | deb_info("%s: load ofsm settings\n", __func__); | ||
1338 | len = ARRAY_SIZE(ofsm_init); | ||
1339 | init = ofsm_init; | ||
1340 | for (i = 0; i < len; i++) { | ||
1341 | ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, | ||
1342 | init[i].len, init[i].val); | ||
1343 | if (ret) | ||
1344 | goto error; | ||
1345 | } | ||
1346 | |||
1347 | /* load tuner specific settings */ | ||
1348 | deb_info("%s: load tuner specific settings\n", __func__); | ||
1349 | switch (state->config.tuner) { | ||
1350 | case AF9013_TUNER_MXL5003D: | ||
1351 | len = ARRAY_SIZE(tuner_init_mxl5003d); | ||
1352 | init = tuner_init_mxl5003d; | ||
1353 | break; | ||
1354 | case AF9013_TUNER_MXL5005D: | ||
1355 | case AF9013_TUNER_MXL5005R: | ||
1356 | len = ARRAY_SIZE(tuner_init_mxl5005); | ||
1357 | init = tuner_init_mxl5005; | ||
1358 | break; | ||
1359 | case AF9013_TUNER_ENV77H11D5: | ||
1360 | len = ARRAY_SIZE(tuner_init_env77h11d5); | ||
1361 | init = tuner_init_env77h11d5; | ||
1362 | break; | ||
1363 | case AF9013_TUNER_MT2060: | ||
1364 | len = ARRAY_SIZE(tuner_init_mt2060); | ||
1365 | init = tuner_init_mt2060; | ||
1366 | break; | ||
1367 | case AF9013_TUNER_MC44S803: | ||
1368 | len = ARRAY_SIZE(tuner_init_mc44s803); | ||
1369 | init = tuner_init_mc44s803; | ||
1370 | break; | ||
1371 | case AF9013_TUNER_QT1010: | ||
1372 | case AF9013_TUNER_QT1010A: | ||
1373 | len = ARRAY_SIZE(tuner_init_qt1010); | ||
1374 | init = tuner_init_qt1010; | ||
1375 | break; | ||
1376 | case AF9013_TUNER_MT2060_2: | ||
1377 | len = ARRAY_SIZE(tuner_init_mt2060_2); | ||
1378 | init = tuner_init_mt2060_2; | ||
1379 | break; | ||
1380 | case AF9013_TUNER_TDA18271: | ||
1381 | len = ARRAY_SIZE(tuner_init_tda18271); | ||
1382 | init = tuner_init_tda18271; | ||
1383 | break; | ||
1384 | case AF9013_TUNER_UNKNOWN: | ||
1385 | default: | ||
1386 | len = ARRAY_SIZE(tuner_init_unknown); | ||
1387 | init = tuner_init_unknown; | ||
1388 | break; | ||
1389 | } | ||
1390 | |||
1391 | for (i = 0; i < len; i++) { | ||
1392 | ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, | ||
1393 | init[i].len, init[i].val); | ||
1394 | if (ret) | ||
1395 | goto error; | ||
1396 | } | ||
1397 | |||
1398 | /* set TS mode */ | ||
1399 | deb_info("%s: setting ts mode\n", __func__); | ||
1400 | tmp0 = 0; /* parallel mode */ | ||
1401 | tmp1 = 0; /* serial mode */ | ||
1402 | switch (state->config.output_mode) { | ||
1403 | case AF9013_OUTPUT_MODE_PARALLEL: | ||
1404 | tmp0 = 1; | ||
1405 | break; | ||
1406 | case AF9013_OUTPUT_MODE_SERIAL: | ||
1407 | tmp1 = 1; | ||
1408 | break; | ||
1409 | case AF9013_OUTPUT_MODE_USB: | ||
1410 | /* usb mode for AF9015 */ | ||
1411 | default: | ||
1412 | break; | ||
1413 | } | ||
1414 | ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ | ||
1415 | if (ret) | ||
1416 | goto error; | ||
1417 | ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ | ||
1418 | if (ret) | ||
1419 | goto error; | ||
1420 | |||
1421 | /* enable lock led */ | ||
1422 | ret = af9013_lock_led(state, 1); | ||
1423 | if (ret) | ||
1424 | goto error; | ||
1425 | |||
1426 | error: | ||
1427 | return ret; | ||
1428 | } | ||
1429 | |||
1430 | static struct dvb_frontend_ops af9013_ops; | ||
1431 | |||
1432 | static int af9013_download_firmware(struct af9013_state *state) | ||
1433 | { | ||
1434 | int i, len, packets, remainder, ret; | ||
1435 | const struct firmware *fw; | ||
1436 | u16 addr = 0x5100; /* firmware start address */ | ||
1437 | u16 checksum = 0; | ||
1438 | u8 val; | ||
1439 | u8 fw_params[4]; | ||
1440 | u8 *data; | ||
1441 | u8 *fw_file = AF9013_DEFAULT_FIRMWARE; | ||
1442 | |||
1443 | msleep(100); | ||
1444 | /* check whether firmware is already running */ | ||
1445 | ret = af9013_read_reg(state, 0x98be, &val); | ||
1446 | if (ret) | ||
1447 | goto error; | ||
1448 | else | ||
1449 | deb_info("%s: firmware status:%02x\n", __func__, val); | ||
1450 | |||
1451 | if (val == 0x0c) /* fw is running, no need for download */ | ||
1452 | goto exit; | ||
1453 | |||
1454 | info("found a '%s' in cold state, will try to load a firmware", | ||
1455 | af9013_ops.info.name); | ||
1456 | |||
1457 | /* request the firmware, this will block and timeout */ | ||
1458 | ret = request_firmware(&fw, fw_file, &state->i2c->dev); | ||
1459 | if (ret) { | ||
1460 | err("did not find the firmware file. (%s) " | ||
1461 | "Please see linux/Documentation/dvb/ for more details" \ | ||
1462 | " on firmware-problems. (%d)", | ||
1463 | fw_file, ret); | ||
1464 | goto error; | ||
1465 | } | ||
1466 | |||
1467 | info("downloading firmware from file '%s'", fw_file); | ||
1468 | |||
1469 | /* calc checksum */ | ||
1470 | for (i = 0; i < fw->size; i++) | ||
1471 | checksum += fw->data[i]; | ||
1472 | |||
1473 | fw_params[0] = checksum >> 8; | ||
1474 | fw_params[1] = checksum & 0xff; | ||
1475 | fw_params[2] = fw->size >> 8; | ||
1476 | fw_params[3] = fw->size & 0xff; | ||
1477 | |||
1478 | /* write fw checksum & size */ | ||
1479 | ret = af9013_write_ofsm_regs(state, 0x50fc, | ||
1480 | fw_params, sizeof(fw_params)); | ||
1481 | if (ret) | ||
1482 | goto error_release; | ||
1483 | |||
1484 | #define FW_PACKET_MAX_DATA 16 | ||
1485 | |||
1486 | packets = fw->size / FW_PACKET_MAX_DATA; | ||
1487 | remainder = fw->size % FW_PACKET_MAX_DATA; | ||
1488 | len = FW_PACKET_MAX_DATA; | ||
1489 | for (i = 0; i <= packets; i++) { | ||
1490 | if (i == packets) /* set size of the last packet */ | ||
1491 | len = remainder; | ||
1492 | |||
1493 | data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); | ||
1494 | ret = af9013_write_ofsm_regs(state, addr, data, len); | ||
1495 | addr += FW_PACKET_MAX_DATA; | ||
1496 | |||
1497 | if (ret) { | ||
1498 | err("firmware download failed at %d with %d", i, ret); | ||
1499 | goto error_release; | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | /* request boot firmware */ | ||
1504 | ret = af9013_write_reg(state, 0xe205, 1); | ||
1505 | if (ret) | ||
1506 | goto error_release; | ||
1507 | |||
1508 | for (i = 0; i < 15; i++) { | ||
1509 | msleep(100); | ||
1510 | |||
1511 | /* check firmware status */ | ||
1512 | ret = af9013_read_reg(state, 0x98be, &val); | ||
1513 | if (ret) | ||
1514 | goto error_release; | ||
1515 | |||
1516 | deb_info("%s: firmware status:%02x\n", __func__, val); | ||
1517 | |||
1518 | if (val == 0x0c || val == 0x04) /* success or fail */ | ||
1519 | break; | ||
1520 | } | ||
1521 | |||
1522 | if (val == 0x04) { | ||
1523 | err("firmware did not run"); | ||
1524 | ret = -1; | ||
1525 | } else if (val != 0x0c) { | ||
1526 | err("firmware boot timeout"); | ||
1527 | ret = -1; | ||
1528 | } | ||
1529 | |||
1530 | error_release: | ||
1531 | release_firmware(fw); | ||
1532 | error: | ||
1533 | exit: | ||
1534 | if (!ret) | ||
1535 | info("found a '%s' in warm state.", af9013_ops.info.name); | ||
1536 | return ret; | ||
1537 | } | ||
1538 | |||
1539 | static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
1540 | { | ||
1541 | int ret; | ||
1542 | struct af9013_state *state = fe->demodulator_priv; | ||
1543 | deb_info("%s: enable:%d\n", __func__, enable); | ||
1544 | |||
1545 | if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) | ||
1546 | ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); | ||
1547 | else | ||
1548 | ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); | ||
1549 | |||
1550 | return ret; | ||
1551 | } | ||
1552 | |||
1553 | static void af9013_release(struct dvb_frontend *fe) | ||
1554 | { | ||
1555 | struct af9013_state *state = fe->demodulator_priv; | ||
1556 | kfree(state); | ||
1557 | } | ||
1558 | |||
1559 | static struct dvb_frontend_ops af9013_ops; | ||
1560 | |||
1561 | struct dvb_frontend *af9013_attach(const struct af9013_config *config, | ||
1562 | struct i2c_adapter *i2c) | ||
1563 | { | ||
1564 | int ret; | ||
1565 | struct af9013_state *state = NULL; | ||
1566 | u8 buf[3], i; | ||
1567 | |||
1568 | /* allocate memory for the internal state */ | ||
1569 | state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); | ||
1570 | if (state == NULL) | ||
1571 | goto error; | ||
1572 | |||
1573 | /* setup the state */ | ||
1574 | state->i2c = i2c; | ||
1575 | memcpy(&state->config, config, sizeof(struct af9013_config)); | ||
1576 | |||
1577 | /* chip version */ | ||
1578 | ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); | ||
1579 | if (ret) | ||
1580 | goto error; | ||
1581 | |||
1582 | /* ROM version */ | ||
1583 | for (i = 0; i < 2; i++) { | ||
1584 | ret = af9013_read_reg(state, 0x116b + i, &buf[i]); | ||
1585 | if (ret) | ||
1586 | goto error; | ||
1587 | } | ||
1588 | deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, | ||
1589 | buf[2], buf[0], buf[1]); | ||
1590 | |||
1591 | /* download firmware */ | ||
1592 | if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { | ||
1593 | ret = af9013_download_firmware(state); | ||
1594 | if (ret) | ||
1595 | goto error; | ||
1596 | } | ||
1597 | |||
1598 | /* firmware version */ | ||
1599 | for (i = 0; i < 3; i++) { | ||
1600 | ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); | ||
1601 | if (ret) | ||
1602 | goto error; | ||
1603 | } | ||
1604 | info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]); | ||
1605 | |||
1606 | /* settings for mp2if */ | ||
1607 | if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { | ||
1608 | /* AF9015 split PSB to 1.5k + 0.5k */ | ||
1609 | ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); | ||
1610 | } else { | ||
1611 | /* AF9013 change the output bit to data7 */ | ||
1612 | ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); | ||
1613 | if (ret) | ||
1614 | goto error; | ||
1615 | /* AF9013 set mpeg to full speed */ | ||
1616 | ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); | ||
1617 | } | ||
1618 | if (ret) | ||
1619 | goto error; | ||
1620 | ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); | ||
1621 | if (ret) | ||
1622 | goto error; | ||
1623 | |||
1624 | /* set GPIOs */ | ||
1625 | for (i = 0; i < sizeof(state->config.gpio); i++) { | ||
1626 | ret = af9013_set_gpio(state, i, state->config.gpio[i]); | ||
1627 | if (ret) | ||
1628 | goto error; | ||
1629 | } | ||
1630 | |||
1631 | /* create dvb_frontend */ | ||
1632 | memcpy(&state->frontend.ops, &af9013_ops, | ||
1633 | sizeof(struct dvb_frontend_ops)); | ||
1634 | state->frontend.demodulator_priv = state; | ||
1635 | |||
1636 | return &state->frontend; | ||
1637 | error: | ||
1638 | kfree(state); | ||
1639 | return NULL; | ||
1640 | } | ||
1641 | EXPORT_SYMBOL(af9013_attach); | ||
1642 | |||
1643 | static struct dvb_frontend_ops af9013_ops = { | ||
1644 | .info = { | ||
1645 | .name = "Afatech AF9013 DVB-T", | ||
1646 | .type = FE_OFDM, | ||
1647 | .frequency_min = 174000000, | ||
1648 | .frequency_max = 862000000, | ||
1649 | .frequency_stepsize = 250000, | ||
1650 | .frequency_tolerance = 0, | ||
1651 | .caps = | ||
1652 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1653 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1654 | FE_CAN_QPSK | FE_CAN_QAM_16 | | ||
1655 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
1656 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
1657 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
1658 | FE_CAN_HIERARCHY_AUTO | | ||
1659 | FE_CAN_RECOVER | | ||
1660 | FE_CAN_MUTE_TS | ||
1661 | }, | ||
1662 | |||
1663 | .release = af9013_release, | ||
1664 | .init = af9013_init, | ||
1665 | .sleep = af9013_sleep, | ||
1666 | .i2c_gate_ctrl = af9013_i2c_gate_ctrl, | ||
1667 | |||
1668 | .set_frontend = af9013_set_frontend, | ||
1669 | .get_frontend = af9013_get_frontend, | ||
1670 | |||
1671 | .get_tune_settings = af9013_get_tune_settings, | ||
1672 | |||
1673 | .read_status = af9013_read_status, | ||
1674 | .read_ber = af9013_read_ber, | ||
1675 | .read_signal_strength = af9013_read_signal_strength, | ||
1676 | .read_snr = af9013_read_snr, | ||
1677 | .read_ucblocks = af9013_read_ucblocks, | ||
1678 | }; | ||
1679 | |||
1680 | module_param_named(debug, af9013_debug, int, 0644); | ||
1681 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
1682 | |||
1683 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
1684 | MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); | ||
1685 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h new file mode 100644 index 000000000000..28b90c91c766 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _AF9013_H_ | ||
25 | #define _AF9013_H_ | ||
26 | |||
27 | #include <linux/dvb/frontend.h> | ||
28 | |||
29 | enum af9013_ts_mode { | ||
30 | AF9013_OUTPUT_MODE_PARALLEL, | ||
31 | AF9013_OUTPUT_MODE_SERIAL, | ||
32 | AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ | ||
33 | }; | ||
34 | |||
35 | enum af9013_tuner { | ||
36 | AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ | ||
37 | AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ | ||
38 | AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ | ||
39 | AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ | ||
40 | AF9013_TUNER_MT2060 = 130, /* Microtune */ | ||
41 | AF9013_TUNER_MC44S803 = 133, /* Freescale */ | ||
42 | AF9013_TUNER_QT1010 = 134, /* Quantek */ | ||
43 | AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ | ||
44 | AF9013_TUNER_MT2060_2 = 147, /* Microtune */ | ||
45 | AF9013_TUNER_TDA18271 = 156, /* NXP */ | ||
46 | AF9013_TUNER_QT1010A = 162, /* Quantek */ | ||
47 | }; | ||
48 | |||
49 | /* AF9013/5 GPIOs (mostly guessed) | ||
50 | demod#1-gpio#0 - set demod#2 i2c-addr for dual devices | ||
51 | demod#1-gpio#1 - xtal setting (?) | ||
52 | demod#1-gpio#3 - tuner#1 | ||
53 | demod#2-gpio#0 - tuner#2 | ||
54 | demod#2-gpio#1 - xtal setting (?) | ||
55 | */ | ||
56 | #define AF9013_GPIO_ON (1 << 0) | ||
57 | #define AF9013_GPIO_EN (1 << 1) | ||
58 | #define AF9013_GPIO_O (1 << 2) | ||
59 | #define AF9013_GPIO_I (1 << 3) | ||
60 | |||
61 | #define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) | ||
62 | #define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) | ||
63 | |||
64 | #define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) | ||
65 | #define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) | ||
66 | |||
67 | struct af9013_config { | ||
68 | /* demodulator's I2C address */ | ||
69 | u8 demod_address; | ||
70 | |||
71 | /* frequencies in kHz */ | ||
72 | u32 adc_clock; | ||
73 | |||
74 | /* tuner ID */ | ||
75 | u8 tuner; | ||
76 | |||
77 | /* tuner IF */ | ||
78 | u16 tuner_if; | ||
79 | |||
80 | /* TS data output mode */ | ||
81 | u8 output_mode:2; | ||
82 | |||
83 | /* RF spectrum inversion */ | ||
84 | u8 rf_spec_inv:1; | ||
85 | |||
86 | /* API version */ | ||
87 | u8 api_version[4]; | ||
88 | |||
89 | /* GPIOs */ | ||
90 | u8 gpio[4]; | ||
91 | }; | ||
92 | |||
93 | |||
94 | #if defined(CONFIG_DVB_AF9013) || \ | ||
95 | (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) | ||
96 | extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, | ||
97 | struct i2c_adapter *i2c); | ||
98 | #else | ||
99 | static inline struct dvb_frontend *af9013_attach( | ||
100 | const struct af9013_config *config, struct i2c_adapter *i2c) | ||
101 | { | ||
102 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
103 | return NULL; | ||
104 | } | ||
105 | #endif /* CONFIG_DVB_AF9013 */ | ||
106 | |||
107 | #endif /* _AF9013_H_ */ | ||
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h new file mode 100644 index 000000000000..163e251d0b73 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013_priv.h | |||
@@ -0,0 +1,869 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _AF9013_PRIV_ | ||
25 | #define _AF9013_PRIV_ | ||
26 | |||
27 | #define LOG_PREFIX "af9013" | ||
28 | extern int af9013_debug; | ||
29 | |||
30 | #define dprintk(var, level, args...) \ | ||
31 | do { if ((var & level)) printk(args); } while (0) | ||
32 | |||
33 | #define debug_dump(b, l, func) {\ | ||
34 | int loop_; \ | ||
35 | for (loop_ = 0; loop_ < l; loop_++) \ | ||
36 | func("%02x ", b[loop_]); \ | ||
37 | func("\n");\ | ||
38 | } | ||
39 | |||
40 | #define deb_info(args...) dprintk(af9013_debug, 0x01, args) | ||
41 | |||
42 | #undef err | ||
43 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
44 | #undef info | ||
45 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
46 | #undef warn | ||
47 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
48 | |||
49 | #define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" | ||
50 | |||
51 | struct regdesc { | ||
52 | u16 addr; | ||
53 | u8 pos:4; | ||
54 | u8 len:4; | ||
55 | u8 val; | ||
56 | }; | ||
57 | |||
58 | struct snr_table { | ||
59 | u32 val; | ||
60 | u8 snr; | ||
61 | }; | ||
62 | |||
63 | /* QPSK SNR lookup table */ | ||
64 | static struct snr_table qpsk_snr_table[] = { | ||
65 | { 0x0b4771, 0 }, | ||
66 | { 0x0c1aed, 1 }, | ||
67 | { 0x0d0d27, 2 }, | ||
68 | { 0x0e4d19, 3 }, | ||
69 | { 0x0e5da8, 4 }, | ||
70 | { 0x107097, 5 }, | ||
71 | { 0x116975, 6 }, | ||
72 | { 0x1252d9, 7 }, | ||
73 | { 0x131fa4, 8 }, | ||
74 | { 0x13d5e1, 9 }, | ||
75 | { 0x148e53, 10 }, | ||
76 | { 0x15358b, 11 }, | ||
77 | { 0x15dd29, 12 }, | ||
78 | { 0x168112, 13 }, | ||
79 | { 0x170b61, 14 }, | ||
80 | { 0xffffff, 15 }, | ||
81 | }; | ||
82 | |||
83 | /* QAM16 SNR lookup table */ | ||
84 | static struct snr_table qam16_snr_table[] = { | ||
85 | { 0x05eb62, 5 }, | ||
86 | { 0x05fecf, 6 }, | ||
87 | { 0x060b80, 7 }, | ||
88 | { 0x062501, 8 }, | ||
89 | { 0x064865, 9 }, | ||
90 | { 0x069604, 10 }, | ||
91 | { 0x06f356, 11 }, | ||
92 | { 0x07706a, 12 }, | ||
93 | { 0x0804d3, 13 }, | ||
94 | { 0x089d1a, 14 }, | ||
95 | { 0x093e3d, 15 }, | ||
96 | { 0x09e35d, 16 }, | ||
97 | { 0x0a7c3c, 17 }, | ||
98 | { 0x0afaf8, 18 }, | ||
99 | { 0x0b719d, 19 }, | ||
100 | { 0xffffff, 20 }, | ||
101 | }; | ||
102 | |||
103 | /* QAM64 SNR lookup table */ | ||
104 | static struct snr_table qam64_snr_table[] = { | ||
105 | { 0x03109b, 12 }, | ||
106 | { 0x0310d4, 13 }, | ||
107 | { 0x031920, 14 }, | ||
108 | { 0x0322d0, 15 }, | ||
109 | { 0x0339fc, 16 }, | ||
110 | { 0x0364a1, 17 }, | ||
111 | { 0x038bcc, 18 }, | ||
112 | { 0x03c7d3, 19 }, | ||
113 | { 0x0408cc, 20 }, | ||
114 | { 0x043bed, 21 }, | ||
115 | { 0x048061, 22 }, | ||
116 | { 0x04be95, 23 }, | ||
117 | { 0x04fa7d, 24 }, | ||
118 | { 0x052405, 25 }, | ||
119 | { 0x05570d, 26 }, | ||
120 | { 0xffffff, 27 }, | ||
121 | }; | ||
122 | |||
123 | static struct regdesc ofsm_init[] = { | ||
124 | { 0xd73a, 0, 8, 0xa1 }, | ||
125 | { 0xd73b, 0, 8, 0x1f }, | ||
126 | { 0xd73c, 4, 4, 0x0a }, | ||
127 | { 0xd732, 3, 1, 0x00 }, | ||
128 | { 0xd731, 4, 2, 0x03 }, | ||
129 | { 0xd73d, 7, 1, 0x01 }, | ||
130 | { 0xd740, 0, 1, 0x00 }, | ||
131 | { 0xd740, 1, 1, 0x00 }, | ||
132 | { 0xd740, 2, 1, 0x00 }, | ||
133 | { 0xd740, 3, 1, 0x01 }, | ||
134 | { 0xd3c1, 4, 1, 0x01 }, | ||
135 | { 0xd3a2, 0, 8, 0x00 }, | ||
136 | { 0xd3a3, 0, 8, 0x04 }, | ||
137 | { 0xd305, 0, 8, 0x32 }, | ||
138 | { 0xd306, 0, 8, 0x10 }, | ||
139 | { 0xd304, 0, 8, 0x04 }, | ||
140 | { 0x9112, 0, 1, 0x01 }, | ||
141 | { 0x911d, 0, 1, 0x01 }, | ||
142 | { 0x911a, 0, 1, 0x01 }, | ||
143 | { 0x911b, 0, 1, 0x01 }, | ||
144 | { 0x9bce, 0, 4, 0x02 }, | ||
145 | { 0x9116, 0, 1, 0x01 }, | ||
146 | { 0x9bd1, 0, 1, 0x01 }, | ||
147 | { 0xd2e0, 0, 8, 0xd0 }, | ||
148 | { 0xd2e9, 0, 4, 0x0d }, | ||
149 | { 0xd38c, 0, 8, 0xfc }, | ||
150 | { 0xd38d, 0, 8, 0x00 }, | ||
151 | { 0xd38e, 0, 8, 0x7e }, | ||
152 | { 0xd38f, 0, 8, 0x00 }, | ||
153 | { 0xd390, 0, 8, 0x2f }, | ||
154 | { 0xd145, 4, 1, 0x01 }, | ||
155 | { 0xd1a9, 4, 1, 0x01 }, | ||
156 | { 0xd158, 5, 3, 0x01 }, | ||
157 | { 0xd159, 0, 6, 0x06 }, | ||
158 | { 0xd167, 0, 8, 0x00 }, | ||
159 | { 0xd168, 0, 4, 0x07 }, | ||
160 | { 0xd1c3, 5, 3, 0x00 }, | ||
161 | { 0xd1c4, 0, 6, 0x00 }, | ||
162 | { 0xd1c5, 0, 7, 0x10 }, | ||
163 | { 0xd1c6, 0, 3, 0x02 }, | ||
164 | { 0xd080, 2, 5, 0x03 }, | ||
165 | { 0xd081, 4, 4, 0x09 }, | ||
166 | { 0xd098, 4, 4, 0x0f }, | ||
167 | { 0xd098, 0, 4, 0x03 }, | ||
168 | { 0xdbc0, 3, 1, 0x01 }, | ||
169 | { 0xdbc0, 4, 1, 0x01 }, | ||
170 | { 0xdbc7, 0, 8, 0x08 }, | ||
171 | { 0xdbc8, 4, 4, 0x00 }, | ||
172 | { 0xdbc9, 0, 5, 0x01 }, | ||
173 | { 0xd280, 0, 8, 0xe0 }, | ||
174 | { 0xd281, 0, 8, 0xff }, | ||
175 | { 0xd282, 0, 8, 0xff }, | ||
176 | { 0xd283, 0, 8, 0xc3 }, | ||
177 | { 0xd284, 0, 8, 0xff }, | ||
178 | { 0xd285, 0, 4, 0x01 }, | ||
179 | { 0xd0f0, 0, 7, 0x1a }, | ||
180 | { 0xd0f1, 4, 1, 0x01 }, | ||
181 | { 0xd0f2, 0, 8, 0x0c }, | ||
182 | { 0xd103, 0, 4, 0x08 }, | ||
183 | { 0xd0f8, 0, 7, 0x20 }, | ||
184 | { 0xd111, 5, 1, 0x00 }, | ||
185 | { 0xd111, 6, 1, 0x00 }, | ||
186 | { 0x910b, 0, 8, 0x0a }, | ||
187 | { 0x9115, 0, 8, 0x02 }, | ||
188 | { 0x910c, 0, 8, 0x02 }, | ||
189 | { 0x910d, 0, 8, 0x08 }, | ||
190 | { 0x910e, 0, 8, 0x0a }, | ||
191 | { 0x9bf6, 0, 8, 0x06 }, | ||
192 | { 0x9bf8, 0, 8, 0x02 }, | ||
193 | { 0x9bf7, 0, 8, 0x05 }, | ||
194 | { 0x9bf9, 0, 8, 0x0f }, | ||
195 | { 0x9bfc, 0, 8, 0x13 }, | ||
196 | { 0x9bd3, 0, 8, 0xff }, | ||
197 | { 0x9bbe, 0, 1, 0x01 }, | ||
198 | { 0x9bcc, 0, 1, 0x01 }, | ||
199 | }; | ||
200 | |||
201 | /* Panasonic ENV77H11D5 tuner init | ||
202 | AF9013_TUNER_ENV77H11D5 = 129 */ | ||
203 | static struct regdesc tuner_init_env77h11d5[] = { | ||
204 | { 0x9bd5, 0, 8, 0x01 }, | ||
205 | { 0x9bd6, 0, 8, 0x03 }, | ||
206 | { 0x9bbe, 0, 8, 0x01 }, | ||
207 | { 0xd1a0, 1, 1, 0x01 }, | ||
208 | { 0xd000, 0, 1, 0x01 }, | ||
209 | { 0xd000, 1, 1, 0x00 }, | ||
210 | { 0xd001, 1, 1, 0x01 }, | ||
211 | { 0xd001, 0, 1, 0x00 }, | ||
212 | { 0xd001, 5, 1, 0x00 }, | ||
213 | { 0xd002, 0, 5, 0x19 }, | ||
214 | { 0xd003, 0, 5, 0x1a }, | ||
215 | { 0xd004, 0, 5, 0x19 }, | ||
216 | { 0xd005, 0, 5, 0x1a }, | ||
217 | { 0xd00e, 0, 5, 0x10 }, | ||
218 | { 0xd00f, 0, 3, 0x04 }, | ||
219 | { 0xd00f, 3, 3, 0x05 }, | ||
220 | { 0xd010, 0, 3, 0x04 }, | ||
221 | { 0xd010, 3, 3, 0x05 }, | ||
222 | { 0xd016, 4, 4, 0x03 }, | ||
223 | { 0xd01f, 0, 6, 0x0a }, | ||
224 | { 0xd020, 0, 6, 0x0a }, | ||
225 | { 0x9bda, 0, 8, 0x00 }, | ||
226 | { 0x9be3, 0, 8, 0x00 }, | ||
227 | { 0xd015, 0, 8, 0x50 }, | ||
228 | { 0xd016, 0, 1, 0x00 }, | ||
229 | { 0xd044, 0, 8, 0x46 }, | ||
230 | { 0xd045, 0, 1, 0x00 }, | ||
231 | { 0xd008, 0, 8, 0xdf }, | ||
232 | { 0xd009, 0, 2, 0x02 }, | ||
233 | { 0xd006, 0, 8, 0x44 }, | ||
234 | { 0xd007, 0, 2, 0x01 }, | ||
235 | { 0xd00c, 0, 8, 0xeb }, | ||
236 | { 0xd00d, 0, 2, 0x02 }, | ||
237 | { 0xd00a, 0, 8, 0xf4 }, | ||
238 | { 0xd00b, 0, 2, 0x01 }, | ||
239 | { 0x9bba, 0, 8, 0xf9 }, | ||
240 | { 0x9bc3, 0, 8, 0xdf }, | ||
241 | { 0x9bc4, 0, 8, 0x02 }, | ||
242 | { 0x9bc5, 0, 8, 0xeb }, | ||
243 | { 0x9bc6, 0, 8, 0x02 }, | ||
244 | { 0x9bc9, 0, 8, 0x52 }, | ||
245 | { 0xd011, 0, 8, 0x3c }, | ||
246 | { 0xd012, 0, 2, 0x01 }, | ||
247 | { 0xd013, 0, 8, 0xf7 }, | ||
248 | { 0xd014, 0, 2, 0x02 }, | ||
249 | { 0xd040, 0, 8, 0x0b }, | ||
250 | { 0xd041, 0, 2, 0x02 }, | ||
251 | { 0xd042, 0, 8, 0x4d }, | ||
252 | { 0xd043, 0, 2, 0x00 }, | ||
253 | { 0xd045, 1, 1, 0x00 }, | ||
254 | { 0x9bcf, 0, 1, 0x01 }, | ||
255 | { 0xd045, 2, 1, 0x01 }, | ||
256 | { 0xd04f, 0, 8, 0x9a }, | ||
257 | { 0xd050, 0, 1, 0x01 }, | ||
258 | { 0xd051, 0, 8, 0x5a }, | ||
259 | { 0xd052, 0, 1, 0x01 }, | ||
260 | { 0xd053, 0, 8, 0x50 }, | ||
261 | { 0xd054, 0, 8, 0x46 }, | ||
262 | { 0x9bd7, 0, 8, 0x0a }, | ||
263 | { 0x9bd8, 0, 8, 0x14 }, | ||
264 | { 0x9bd9, 0, 8, 0x08 }, | ||
265 | }; | ||
266 | |||
267 | /* Microtune MT2060 tuner init | ||
268 | AF9013_TUNER_MT2060 = 130 */ | ||
269 | static struct regdesc tuner_init_mt2060[] = { | ||
270 | { 0x9bd5, 0, 8, 0x01 }, | ||
271 | { 0x9bd6, 0, 8, 0x07 }, | ||
272 | { 0xd1a0, 1, 1, 0x01 }, | ||
273 | { 0xd000, 0, 1, 0x01 }, | ||
274 | { 0xd000, 1, 1, 0x00 }, | ||
275 | { 0xd001, 1, 1, 0x01 }, | ||
276 | { 0xd001, 0, 1, 0x00 }, | ||
277 | { 0xd001, 5, 1, 0x00 }, | ||
278 | { 0xd002, 0, 5, 0x19 }, | ||
279 | { 0xd003, 0, 5, 0x1a }, | ||
280 | { 0xd004, 0, 5, 0x19 }, | ||
281 | { 0xd005, 0, 5, 0x1a }, | ||
282 | { 0xd00e, 0, 5, 0x10 }, | ||
283 | { 0xd00f, 0, 3, 0x04 }, | ||
284 | { 0xd00f, 3, 3, 0x05 }, | ||
285 | { 0xd010, 0, 3, 0x04 }, | ||
286 | { 0xd010, 3, 3, 0x05 }, | ||
287 | { 0xd016, 4, 4, 0x03 }, | ||
288 | { 0xd01f, 0, 6, 0x0a }, | ||
289 | { 0xd020, 0, 6, 0x0a }, | ||
290 | { 0x9bda, 0, 8, 0x00 }, | ||
291 | { 0x9be3, 0, 8, 0x00 }, | ||
292 | { 0x9bbe, 0, 1, 0x00 }, | ||
293 | { 0x9bcc, 0, 1, 0x00 }, | ||
294 | { 0x9bb9, 0, 8, 0x75 }, | ||
295 | { 0x9bcd, 0, 8, 0x24 }, | ||
296 | { 0x9bff, 0, 8, 0x30 }, | ||
297 | { 0xd015, 0, 8, 0x46 }, | ||
298 | { 0xd016, 0, 1, 0x00 }, | ||
299 | { 0xd044, 0, 8, 0x46 }, | ||
300 | { 0xd045, 0, 1, 0x00 }, | ||
301 | { 0xd008, 0, 8, 0x0f }, | ||
302 | { 0xd009, 0, 2, 0x02 }, | ||
303 | { 0xd006, 0, 8, 0x32 }, | ||
304 | { 0xd007, 0, 2, 0x01 }, | ||
305 | { 0xd00c, 0, 8, 0x36 }, | ||
306 | { 0xd00d, 0, 2, 0x03 }, | ||
307 | { 0xd00a, 0, 8, 0x35 }, | ||
308 | { 0xd00b, 0, 2, 0x01 }, | ||
309 | { 0x9bc7, 0, 8, 0x07 }, | ||
310 | { 0x9bc8, 0, 8, 0x90 }, | ||
311 | { 0x9bc3, 0, 8, 0x0f }, | ||
312 | { 0x9bc4, 0, 8, 0x02 }, | ||
313 | { 0x9bc5, 0, 8, 0x36 }, | ||
314 | { 0x9bc6, 0, 8, 0x03 }, | ||
315 | { 0x9bba, 0, 8, 0xc9 }, | ||
316 | { 0x9bc9, 0, 8, 0x79 }, | ||
317 | { 0xd011, 0, 8, 0x10 }, | ||
318 | { 0xd012, 0, 2, 0x01 }, | ||
319 | { 0xd013, 0, 8, 0x45 }, | ||
320 | { 0xd014, 0, 2, 0x03 }, | ||
321 | { 0xd040, 0, 8, 0x98 }, | ||
322 | { 0xd041, 0, 2, 0x00 }, | ||
323 | { 0xd042, 0, 8, 0xcf }, | ||
324 | { 0xd043, 0, 2, 0x03 }, | ||
325 | { 0xd045, 1, 1, 0x00 }, | ||
326 | { 0x9bcf, 0, 1, 0x01 }, | ||
327 | { 0xd045, 2, 1, 0x01 }, | ||
328 | { 0xd04f, 0, 8, 0x9a }, | ||
329 | { 0xd050, 0, 1, 0x01 }, | ||
330 | { 0xd051, 0, 8, 0x5a }, | ||
331 | { 0xd052, 0, 1, 0x01 }, | ||
332 | { 0xd053, 0, 8, 0x50 }, | ||
333 | { 0xd054, 0, 8, 0x46 }, | ||
334 | { 0x9bd7, 0, 8, 0x0a }, | ||
335 | { 0x9bd8, 0, 8, 0x14 }, | ||
336 | { 0x9bd9, 0, 8, 0x08 }, | ||
337 | { 0x9bd0, 0, 8, 0xcc }, | ||
338 | { 0x9be4, 0, 8, 0xa0 }, | ||
339 | { 0x9bbd, 0, 8, 0x8e }, | ||
340 | { 0x9be2, 0, 8, 0x4d }, | ||
341 | { 0x9bee, 0, 1, 0x01 }, | ||
342 | }; | ||
343 | |||
344 | /* Microtune MT2060 tuner init | ||
345 | AF9013_TUNER_MT2060_2 = 147 */ | ||
346 | static struct regdesc tuner_init_mt2060_2[] = { | ||
347 | { 0x9bd5, 0, 8, 0x01 }, | ||
348 | { 0x9bd6, 0, 8, 0x06 }, | ||
349 | { 0x9bbe, 0, 8, 0x01 }, | ||
350 | { 0xd1a0, 1, 1, 0x01 }, | ||
351 | { 0xd000, 0, 1, 0x01 }, | ||
352 | { 0xd000, 1, 1, 0x00 }, | ||
353 | { 0xd001, 1, 1, 0x01 }, | ||
354 | { 0xd001, 0, 1, 0x00 }, | ||
355 | { 0xd001, 5, 1, 0x00 }, | ||
356 | { 0xd002, 0, 5, 0x19 }, | ||
357 | { 0xd003, 0, 5, 0x1a }, | ||
358 | { 0xd004, 0, 5, 0x19 }, | ||
359 | { 0xd005, 0, 5, 0x1a }, | ||
360 | { 0xd00e, 0, 5, 0x10 }, | ||
361 | { 0xd00f, 0, 3, 0x04 }, | ||
362 | { 0xd00f, 3, 3, 0x05 }, | ||
363 | { 0xd010, 0, 3, 0x04 }, | ||
364 | { 0xd010, 3, 3, 0x05 }, | ||
365 | { 0xd016, 4, 4, 0x03 }, | ||
366 | { 0xd01f, 0, 6, 0x0a }, | ||
367 | { 0xd020, 0, 6, 0x0a }, | ||
368 | { 0xd015, 0, 8, 0x46 }, | ||
369 | { 0xd016, 0, 1, 0x00 }, | ||
370 | { 0xd044, 0, 8, 0x46 }, | ||
371 | { 0xd045, 0, 1, 0x00 }, | ||
372 | { 0xd008, 0, 8, 0x0f }, | ||
373 | { 0xd009, 0, 2, 0x02 }, | ||
374 | { 0xd006, 0, 8, 0x32 }, | ||
375 | { 0xd007, 0, 2, 0x01 }, | ||
376 | { 0xd00c, 0, 8, 0x36 }, | ||
377 | { 0xd00d, 0, 2, 0x03 }, | ||
378 | { 0xd00a, 0, 8, 0x35 }, | ||
379 | { 0xd00b, 0, 2, 0x01 }, | ||
380 | { 0x9bc7, 0, 8, 0x07 }, | ||
381 | { 0x9bc8, 0, 8, 0x90 }, | ||
382 | { 0x9bc3, 0, 8, 0x0f }, | ||
383 | { 0x9bc4, 0, 8, 0x02 }, | ||
384 | { 0x9bc5, 0, 8, 0x36 }, | ||
385 | { 0x9bc6, 0, 8, 0x03 }, | ||
386 | { 0x9bba, 0, 8, 0xc9 }, | ||
387 | { 0x9bc9, 0, 8, 0x79 }, | ||
388 | { 0xd011, 0, 8, 0x10 }, | ||
389 | { 0xd012, 0, 2, 0x01 }, | ||
390 | { 0xd013, 0, 8, 0x45 }, | ||
391 | { 0xd014, 0, 2, 0x03 }, | ||
392 | { 0xd040, 0, 8, 0x98 }, | ||
393 | { 0xd041, 0, 2, 0x00 }, | ||
394 | { 0xd042, 0, 8, 0xcf }, | ||
395 | { 0xd043, 0, 2, 0x03 }, | ||
396 | { 0xd045, 1, 1, 0x00 }, | ||
397 | { 0x9bcf, 0, 8, 0x01 }, | ||
398 | { 0xd045, 2, 1, 0x01 }, | ||
399 | { 0xd04f, 0, 8, 0x9a }, | ||
400 | { 0xd050, 0, 1, 0x01 }, | ||
401 | { 0xd051, 0, 8, 0x5a }, | ||
402 | { 0xd052, 0, 1, 0x01 }, | ||
403 | { 0xd053, 0, 8, 0x96 }, | ||
404 | { 0xd054, 0, 8, 0x46 }, | ||
405 | { 0xd045, 7, 1, 0x00 }, | ||
406 | { 0x9bd7, 0, 8, 0x0a }, | ||
407 | { 0x9bd8, 0, 8, 0x14 }, | ||
408 | { 0x9bd9, 0, 8, 0x08 }, | ||
409 | }; | ||
410 | |||
411 | /* MaxLinear MXL5003 tuner init | ||
412 | AF9013_TUNER_MXL5003D = 3 */ | ||
413 | static struct regdesc tuner_init_mxl5003d[] = { | ||
414 | { 0x9bd5, 0, 8, 0x01 }, | ||
415 | { 0x9bd6, 0, 8, 0x09 }, | ||
416 | { 0xd1a0, 1, 1, 0x01 }, | ||
417 | { 0xd000, 0, 1, 0x01 }, | ||
418 | { 0xd000, 1, 1, 0x00 }, | ||
419 | { 0xd001, 1, 1, 0x01 }, | ||
420 | { 0xd001, 0, 1, 0x00 }, | ||
421 | { 0xd001, 5, 1, 0x00 }, | ||
422 | { 0xd002, 0, 5, 0x19 }, | ||
423 | { 0xd003, 0, 5, 0x1a }, | ||
424 | { 0xd004, 0, 5, 0x19 }, | ||
425 | { 0xd005, 0, 5, 0x1a }, | ||
426 | { 0xd00e, 0, 5, 0x10 }, | ||
427 | { 0xd00f, 0, 3, 0x04 }, | ||
428 | { 0xd00f, 3, 3, 0x05 }, | ||
429 | { 0xd010, 0, 3, 0x04 }, | ||
430 | { 0xd010, 3, 3, 0x05 }, | ||
431 | { 0xd016, 4, 4, 0x03 }, | ||
432 | { 0xd01f, 0, 6, 0x0a }, | ||
433 | { 0xd020, 0, 6, 0x0a }, | ||
434 | { 0x9bda, 0, 8, 0x00 }, | ||
435 | { 0x9be3, 0, 8, 0x00 }, | ||
436 | { 0x9bfc, 0, 8, 0x0f }, | ||
437 | { 0x9bf6, 0, 8, 0x01 }, | ||
438 | { 0x9bbe, 0, 1, 0x01 }, | ||
439 | { 0xd015, 0, 8, 0x33 }, | ||
440 | { 0xd016, 0, 1, 0x00 }, | ||
441 | { 0xd044, 0, 8, 0x40 }, | ||
442 | { 0xd045, 0, 1, 0x00 }, | ||
443 | { 0xd008, 0, 8, 0x0f }, | ||
444 | { 0xd009, 0, 2, 0x02 }, | ||
445 | { 0xd006, 0, 8, 0x6c }, | ||
446 | { 0xd007, 0, 2, 0x00 }, | ||
447 | { 0xd00c, 0, 8, 0x3d }, | ||
448 | { 0xd00d, 0, 2, 0x00 }, | ||
449 | { 0xd00a, 0, 8, 0x45 }, | ||
450 | { 0xd00b, 0, 2, 0x01 }, | ||
451 | { 0x9bc7, 0, 8, 0x07 }, | ||
452 | { 0x9bc8, 0, 8, 0x52 }, | ||
453 | { 0x9bc3, 0, 8, 0x0f }, | ||
454 | { 0x9bc4, 0, 8, 0x02 }, | ||
455 | { 0x9bc5, 0, 8, 0x3d }, | ||
456 | { 0x9bc6, 0, 8, 0x00 }, | ||
457 | { 0x9bba, 0, 8, 0xa2 }, | ||
458 | { 0x9bc9, 0, 8, 0xa0 }, | ||
459 | { 0xd011, 0, 8, 0x56 }, | ||
460 | { 0xd012, 0, 2, 0x00 }, | ||
461 | { 0xd013, 0, 8, 0x50 }, | ||
462 | { 0xd014, 0, 2, 0x00 }, | ||
463 | { 0xd040, 0, 8, 0x56 }, | ||
464 | { 0xd041, 0, 2, 0x00 }, | ||
465 | { 0xd042, 0, 8, 0x50 }, | ||
466 | { 0xd043, 0, 2, 0x00 }, | ||
467 | { 0xd045, 1, 1, 0x00 }, | ||
468 | { 0x9bcf, 0, 8, 0x01 }, | ||
469 | { 0xd045, 2, 1, 0x01 }, | ||
470 | { 0xd04f, 0, 8, 0x9a }, | ||
471 | { 0xd050, 0, 1, 0x01 }, | ||
472 | { 0xd051, 0, 8, 0x5a }, | ||
473 | { 0xd052, 0, 1, 0x01 }, | ||
474 | { 0xd053, 0, 8, 0x50 }, | ||
475 | { 0xd054, 0, 8, 0x46 }, | ||
476 | { 0x9bd7, 0, 8, 0x0a }, | ||
477 | { 0x9bd8, 0, 8, 0x14 }, | ||
478 | { 0x9bd9, 0, 8, 0x08 }, | ||
479 | }; | ||
480 | |||
481 | /* MaxLinear MXL5005 tuner init | ||
482 | AF9013_TUNER_MXL5005D = 13 | ||
483 | AF9013_TUNER_MXL5005R = 30 */ | ||
484 | static struct regdesc tuner_init_mxl5005[] = { | ||
485 | { 0x9bd5, 0, 8, 0x01 }, | ||
486 | { 0x9bd6, 0, 8, 0x07 }, | ||
487 | { 0xd1a0, 1, 1, 0x01 }, | ||
488 | { 0xd000, 0, 1, 0x01 }, | ||
489 | { 0xd000, 1, 1, 0x00 }, | ||
490 | { 0xd001, 1, 1, 0x01 }, | ||
491 | { 0xd001, 0, 1, 0x00 }, | ||
492 | { 0xd001, 5, 1, 0x00 }, | ||
493 | { 0xd002, 0, 5, 0x19 }, | ||
494 | { 0xd003, 0, 5, 0x1a }, | ||
495 | { 0xd004, 0, 5, 0x19 }, | ||
496 | { 0xd005, 0, 5, 0x1a }, | ||
497 | { 0xd00e, 0, 5, 0x10 }, | ||
498 | { 0xd00f, 0, 3, 0x04 }, | ||
499 | { 0xd00f, 3, 3, 0x05 }, | ||
500 | { 0xd010, 0, 3, 0x04 }, | ||
501 | { 0xd010, 3, 3, 0x05 }, | ||
502 | { 0xd016, 4, 4, 0x03 }, | ||
503 | { 0xd01f, 0, 6, 0x0a }, | ||
504 | { 0xd020, 0, 6, 0x0a }, | ||
505 | { 0x9bda, 0, 8, 0x01 }, | ||
506 | { 0x9be3, 0, 8, 0x01 }, | ||
507 | { 0x9bbe, 0, 1, 0x01 }, | ||
508 | { 0x9bcc, 0, 1, 0x01 }, | ||
509 | { 0x9bb9, 0, 8, 0x00 }, | ||
510 | { 0x9bcd, 0, 8, 0x28 }, | ||
511 | { 0x9bff, 0, 8, 0x24 }, | ||
512 | { 0xd015, 0, 8, 0x40 }, | ||
513 | { 0xd016, 0, 1, 0x00 }, | ||
514 | { 0xd044, 0, 8, 0x40 }, | ||
515 | { 0xd045, 0, 1, 0x00 }, | ||
516 | { 0xd008, 0, 8, 0x0f }, | ||
517 | { 0xd009, 0, 2, 0x02 }, | ||
518 | { 0xd006, 0, 8, 0x73 }, | ||
519 | { 0xd007, 0, 2, 0x01 }, | ||
520 | { 0xd00c, 0, 8, 0xfa }, | ||
521 | { 0xd00d, 0, 2, 0x01 }, | ||
522 | { 0xd00a, 0, 8, 0xff }, | ||
523 | { 0xd00b, 0, 2, 0x01 }, | ||
524 | { 0x9bc7, 0, 8, 0x23 }, | ||
525 | { 0x9bc8, 0, 8, 0x55 }, | ||
526 | { 0x9bc3, 0, 8, 0x01 }, | ||
527 | { 0x9bc4, 0, 8, 0x02 }, | ||
528 | { 0x9bc5, 0, 8, 0xfa }, | ||
529 | { 0x9bc6, 0, 8, 0x01 }, | ||
530 | { 0x9bba, 0, 8, 0xff }, | ||
531 | { 0x9bc9, 0, 8, 0xff }, | ||
532 | { 0x9bd3, 0, 8, 0x95 }, | ||
533 | { 0xd011, 0, 8, 0x70 }, | ||
534 | { 0xd012, 0, 2, 0x01 }, | ||
535 | { 0xd013, 0, 8, 0xfb }, | ||
536 | { 0xd014, 0, 2, 0x01 }, | ||
537 | { 0xd040, 0, 8, 0x70 }, | ||
538 | { 0xd041, 0, 2, 0x01 }, | ||
539 | { 0xd042, 0, 8, 0xfb }, | ||
540 | { 0xd043, 0, 2, 0x01 }, | ||
541 | { 0xd045, 1, 1, 0x00 }, | ||
542 | { 0x9bcf, 0, 1, 0x01 }, | ||
543 | { 0xd045, 2, 1, 0x01 }, | ||
544 | { 0xd04f, 0, 8, 0x9a }, | ||
545 | { 0xd050, 0, 1, 0x01 }, | ||
546 | { 0xd051, 0, 8, 0x5a }, | ||
547 | { 0xd052, 0, 1, 0x01 }, | ||
548 | { 0xd053, 0, 8, 0x50 }, | ||
549 | { 0xd054, 0, 8, 0x46 }, | ||
550 | { 0x9bd7, 0, 8, 0x0a }, | ||
551 | { 0x9bd8, 0, 8, 0x14 }, | ||
552 | { 0x9bd9, 0, 8, 0x08 }, | ||
553 | { 0x9bd0, 0, 8, 0x93 }, | ||
554 | { 0x9be4, 0, 8, 0xfe }, | ||
555 | { 0x9bbd, 0, 8, 0x63 }, | ||
556 | { 0x9be2, 0, 8, 0xfe }, | ||
557 | { 0x9bee, 0, 1, 0x01 }, | ||
558 | }; | ||
559 | |||
560 | /* Quantek QT1010 tuner init | ||
561 | AF9013_TUNER_QT1010 = 134 | ||
562 | AF9013_TUNER_QT1010A = 162 */ | ||
563 | static struct regdesc tuner_init_qt1010[] = { | ||
564 | { 0x9bd5, 0, 8, 0x01 }, | ||
565 | { 0x9bd6, 0, 8, 0x09 }, | ||
566 | { 0xd1a0, 1, 1, 0x01 }, | ||
567 | { 0xd000, 0, 1, 0x01 }, | ||
568 | { 0xd000, 1, 1, 0x00 }, | ||
569 | { 0xd001, 1, 1, 0x01 }, | ||
570 | { 0xd001, 0, 1, 0x00 }, | ||
571 | { 0xd001, 5, 1, 0x00 }, | ||
572 | { 0xd002, 0, 5, 0x19 }, | ||
573 | { 0xd003, 0, 5, 0x1a }, | ||
574 | { 0xd004, 0, 5, 0x19 }, | ||
575 | { 0xd005, 0, 5, 0x1a }, | ||
576 | { 0xd00e, 0, 5, 0x10 }, | ||
577 | { 0xd00f, 0, 3, 0x04 }, | ||
578 | { 0xd00f, 3, 3, 0x05 }, | ||
579 | { 0xd010, 0, 3, 0x04 }, | ||
580 | { 0xd010, 3, 3, 0x05 }, | ||
581 | { 0xd016, 4, 4, 0x03 }, | ||
582 | { 0xd01f, 0, 6, 0x0a }, | ||
583 | { 0xd020, 0, 6, 0x0a }, | ||
584 | { 0x9bda, 0, 8, 0x01 }, | ||
585 | { 0x9be3, 0, 8, 0x01 }, | ||
586 | { 0xd015, 0, 8, 0x46 }, | ||
587 | { 0xd016, 0, 1, 0x00 }, | ||
588 | { 0xd044, 0, 8, 0x46 }, | ||
589 | { 0xd045, 0, 1, 0x00 }, | ||
590 | { 0x9bbe, 0, 1, 0x01 }, | ||
591 | { 0x9bcc, 0, 1, 0x01 }, | ||
592 | { 0x9bb9, 0, 8, 0x00 }, | ||
593 | { 0x9bcd, 0, 8, 0x28 }, | ||
594 | { 0x9bff, 0, 8, 0x20 }, | ||
595 | { 0xd008, 0, 8, 0x0f }, | ||
596 | { 0xd009, 0, 2, 0x02 }, | ||
597 | { 0xd006, 0, 8, 0x99 }, | ||
598 | { 0xd007, 0, 2, 0x01 }, | ||
599 | { 0xd00c, 0, 8, 0x0f }, | ||
600 | { 0xd00d, 0, 2, 0x02 }, | ||
601 | { 0xd00a, 0, 8, 0x50 }, | ||
602 | { 0xd00b, 0, 2, 0x01 }, | ||
603 | { 0x9bc7, 0, 8, 0x00 }, | ||
604 | { 0x9bc8, 0, 8, 0x00 }, | ||
605 | { 0x9bc3, 0, 8, 0x0f }, | ||
606 | { 0x9bc4, 0, 8, 0x02 }, | ||
607 | { 0x9bc5, 0, 8, 0x0f }, | ||
608 | { 0x9bc6, 0, 8, 0x02 }, | ||
609 | { 0x9bba, 0, 8, 0xc5 }, | ||
610 | { 0x9bc9, 0, 8, 0xff }, | ||
611 | { 0xd011, 0, 8, 0x58 }, | ||
612 | { 0xd012, 0, 2, 0x02 }, | ||
613 | { 0xd013, 0, 8, 0x89 }, | ||
614 | { 0xd014, 0, 2, 0x01 }, | ||
615 | { 0xd040, 0, 8, 0x58 }, | ||
616 | { 0xd041, 0, 2, 0x02 }, | ||
617 | { 0xd042, 0, 8, 0x89 }, | ||
618 | { 0xd043, 0, 2, 0x01 }, | ||
619 | { 0xd045, 1, 1, 0x00 }, | ||
620 | { 0x9bcf, 0, 1, 0x01 }, | ||
621 | { 0xd045, 2, 1, 0x01 }, | ||
622 | { 0xd04f, 0, 8, 0x9a }, | ||
623 | { 0xd050, 0, 1, 0x01 }, | ||
624 | { 0xd051, 0, 8, 0x5a }, | ||
625 | { 0xd052, 0, 1, 0x01 }, | ||
626 | { 0xd053, 0, 8, 0x50 }, | ||
627 | { 0xd054, 0, 8, 0x46 }, | ||
628 | { 0x9bd7, 0, 8, 0x0a }, | ||
629 | { 0x9bd8, 0, 8, 0x14 }, | ||
630 | { 0x9bd9, 0, 8, 0x08 }, | ||
631 | { 0x9bd0, 0, 8, 0xcd }, | ||
632 | { 0x9be4, 0, 8, 0xbb }, | ||
633 | { 0x9bbd, 0, 8, 0x93 }, | ||
634 | { 0x9be2, 0, 8, 0x80 }, | ||
635 | { 0x9bee, 0, 1, 0x01 }, | ||
636 | }; | ||
637 | |||
638 | /* Freescale MC44S803 tuner init | ||
639 | AF9013_TUNER_MC44S803 = 133 */ | ||
640 | static struct regdesc tuner_init_mc44s803[] = { | ||
641 | { 0x9bd5, 0, 8, 0x01 }, | ||
642 | { 0x9bd6, 0, 8, 0x06 }, | ||
643 | { 0xd1a0, 1, 1, 0x01 }, | ||
644 | { 0xd000, 0, 1, 0x01 }, | ||
645 | { 0xd000, 1, 1, 0x00 }, | ||
646 | { 0xd001, 1, 1, 0x01 }, | ||
647 | { 0xd001, 0, 1, 0x00 }, | ||
648 | { 0xd001, 5, 1, 0x00 }, | ||
649 | { 0xd002, 0, 5, 0x19 }, | ||
650 | { 0xd003, 0, 5, 0x1a }, | ||
651 | { 0xd004, 0, 5, 0x19 }, | ||
652 | { 0xd005, 0, 5, 0x1a }, | ||
653 | { 0xd00e, 0, 5, 0x10 }, | ||
654 | { 0xd00f, 0, 3, 0x04 }, | ||
655 | { 0xd00f, 3, 3, 0x05 }, | ||
656 | { 0xd010, 0, 3, 0x04 }, | ||
657 | { 0xd010, 3, 3, 0x05 }, | ||
658 | { 0xd016, 4, 4, 0x03 }, | ||
659 | { 0xd01f, 0, 6, 0x0a }, | ||
660 | { 0xd020, 0, 6, 0x0a }, | ||
661 | { 0x9bda, 0, 8, 0x00 }, | ||
662 | { 0x9be3, 0, 8, 0x00 }, | ||
663 | { 0x9bf6, 0, 8, 0x01 }, | ||
664 | { 0x9bf8, 0, 8, 0x02 }, | ||
665 | { 0x9bf9, 0, 8, 0x02 }, | ||
666 | { 0x9bfc, 0, 8, 0x1f }, | ||
667 | { 0x9bbe, 0, 1, 0x01 }, | ||
668 | { 0x9bcc, 0, 1, 0x01 }, | ||
669 | { 0x9bb9, 0, 8, 0x00 }, | ||
670 | { 0x9bcd, 0, 8, 0x24 }, | ||
671 | { 0x9bff, 0, 8, 0x24 }, | ||
672 | { 0xd015, 0, 8, 0x46 }, | ||
673 | { 0xd016, 0, 1, 0x00 }, | ||
674 | { 0xd044, 0, 8, 0x46 }, | ||
675 | { 0xd045, 0, 1, 0x00 }, | ||
676 | { 0xd008, 0, 8, 0x01 }, | ||
677 | { 0xd009, 0, 2, 0x02 }, | ||
678 | { 0xd006, 0, 8, 0x7b }, | ||
679 | { 0xd007, 0, 2, 0x00 }, | ||
680 | { 0xd00c, 0, 8, 0x7c }, | ||
681 | { 0xd00d, 0, 2, 0x02 }, | ||
682 | { 0xd00a, 0, 8, 0xfe }, | ||
683 | { 0xd00b, 0, 2, 0x01 }, | ||
684 | { 0x9bc7, 0, 8, 0x08 }, | ||
685 | { 0x9bc8, 0, 8, 0x9a }, | ||
686 | { 0x9bc3, 0, 8, 0x01 }, | ||
687 | { 0x9bc4, 0, 8, 0x02 }, | ||
688 | { 0x9bc5, 0, 8, 0x7c }, | ||
689 | { 0x9bc6, 0, 8, 0x02 }, | ||
690 | { 0x9bba, 0, 8, 0xfc }, | ||
691 | { 0x9bc9, 0, 8, 0xaa }, | ||
692 | { 0xd011, 0, 8, 0x6b }, | ||
693 | { 0xd012, 0, 2, 0x00 }, | ||
694 | { 0xd013, 0, 8, 0x88 }, | ||
695 | { 0xd014, 0, 2, 0x02 }, | ||
696 | { 0xd040, 0, 8, 0x6b }, | ||
697 | { 0xd041, 0, 2, 0x00 }, | ||
698 | { 0xd042, 0, 8, 0x7c }, | ||
699 | { 0xd043, 0, 2, 0x02 }, | ||
700 | { 0xd045, 1, 1, 0x00 }, | ||
701 | { 0x9bcf, 0, 1, 0x01 }, | ||
702 | { 0xd045, 2, 1, 0x01 }, | ||
703 | { 0xd04f, 0, 8, 0x9a }, | ||
704 | { 0xd050, 0, 1, 0x01 }, | ||
705 | { 0xd051, 0, 8, 0x5a }, | ||
706 | { 0xd052, 0, 1, 0x01 }, | ||
707 | { 0xd053, 0, 8, 0x50 }, | ||
708 | { 0xd054, 0, 8, 0x46 }, | ||
709 | { 0x9bd7, 0, 8, 0x0a }, | ||
710 | { 0x9bd8, 0, 8, 0x14 }, | ||
711 | { 0x9bd9, 0, 8, 0x08 }, | ||
712 | { 0x9bd0, 0, 8, 0x9e }, | ||
713 | { 0x9be4, 0, 8, 0xff }, | ||
714 | { 0x9bbd, 0, 8, 0x9e }, | ||
715 | { 0x9be2, 0, 8, 0x25 }, | ||
716 | { 0x9bee, 0, 1, 0x01 }, | ||
717 | { 0xd73b, 3, 1, 0x00 }, | ||
718 | }; | ||
719 | |||
720 | /* unknown, probably for tin can tuner, tuner init | ||
721 | AF9013_TUNER_UNKNOWN = 140 */ | ||
722 | static struct regdesc tuner_init_unknown[] = { | ||
723 | { 0x9bd5, 0, 8, 0x01 }, | ||
724 | { 0x9bd6, 0, 8, 0x02 }, | ||
725 | { 0xd1a0, 1, 1, 0x01 }, | ||
726 | { 0xd000, 0, 1, 0x01 }, | ||
727 | { 0xd000, 1, 1, 0x00 }, | ||
728 | { 0xd001, 1, 1, 0x01 }, | ||
729 | { 0xd001, 0, 1, 0x00 }, | ||
730 | { 0xd001, 5, 1, 0x00 }, | ||
731 | { 0xd002, 0, 5, 0x19 }, | ||
732 | { 0xd003, 0, 5, 0x1a }, | ||
733 | { 0xd004, 0, 5, 0x19 }, | ||
734 | { 0xd005, 0, 5, 0x1a }, | ||
735 | { 0xd00e, 0, 5, 0x10 }, | ||
736 | { 0xd00f, 0, 3, 0x04 }, | ||
737 | { 0xd00f, 3, 3, 0x05 }, | ||
738 | { 0xd010, 0, 3, 0x04 }, | ||
739 | { 0xd010, 3, 3, 0x05 }, | ||
740 | { 0xd016, 4, 4, 0x03 }, | ||
741 | { 0xd01f, 0, 6, 0x0a }, | ||
742 | { 0xd020, 0, 6, 0x0a }, | ||
743 | { 0x9bda, 0, 8, 0x01 }, | ||
744 | { 0x9be3, 0, 8, 0x01 }, | ||
745 | { 0xd1a0, 1, 1, 0x00 }, | ||
746 | { 0x9bbe, 0, 1, 0x01 }, | ||
747 | { 0x9bcc, 0, 1, 0x01 }, | ||
748 | { 0x9bb9, 0, 8, 0x00 }, | ||
749 | { 0x9bcd, 0, 8, 0x18 }, | ||
750 | { 0x9bff, 0, 8, 0x2c }, | ||
751 | { 0xd015, 0, 8, 0x46 }, | ||
752 | { 0xd016, 0, 1, 0x00 }, | ||
753 | { 0xd044, 0, 8, 0x46 }, | ||
754 | { 0xd045, 0, 1, 0x00 }, | ||
755 | { 0xd008, 0, 8, 0xdf }, | ||
756 | { 0xd009, 0, 2, 0x02 }, | ||
757 | { 0xd006, 0, 8, 0x44 }, | ||
758 | { 0xd007, 0, 2, 0x01 }, | ||
759 | { 0xd00c, 0, 8, 0x00 }, | ||
760 | { 0xd00d, 0, 2, 0x02 }, | ||
761 | { 0xd00a, 0, 8, 0xf6 }, | ||
762 | { 0xd00b, 0, 2, 0x01 }, | ||
763 | { 0x9bba, 0, 8, 0xf9 }, | ||
764 | { 0x9bc8, 0, 8, 0xaa }, | ||
765 | { 0x9bc3, 0, 8, 0xdf }, | ||
766 | { 0x9bc4, 0, 8, 0x02 }, | ||
767 | { 0x9bc5, 0, 8, 0x00 }, | ||
768 | { 0x9bc6, 0, 8, 0x02 }, | ||
769 | { 0x9bc9, 0, 8, 0xf0 }, | ||
770 | { 0xd011, 0, 8, 0x3c }, | ||
771 | { 0xd012, 0, 2, 0x01 }, | ||
772 | { 0xd013, 0, 8, 0xf7 }, | ||
773 | { 0xd014, 0, 2, 0x02 }, | ||
774 | { 0xd040, 0, 8, 0x0b }, | ||
775 | { 0xd041, 0, 2, 0x02 }, | ||
776 | { 0xd042, 0, 8, 0x4d }, | ||
777 | { 0xd043, 0, 2, 0x00 }, | ||
778 | { 0xd045, 1, 1, 0x00 }, | ||
779 | { 0x9bcf, 0, 1, 0x01 }, | ||
780 | { 0xd045, 2, 1, 0x01 }, | ||
781 | { 0xd04f, 0, 8, 0x9a }, | ||
782 | { 0xd050, 0, 1, 0x01 }, | ||
783 | { 0xd051, 0, 8, 0x5a }, | ||
784 | { 0xd052, 0, 1, 0x01 }, | ||
785 | { 0xd053, 0, 8, 0x50 }, | ||
786 | { 0xd054, 0, 8, 0x46 }, | ||
787 | { 0x9bd7, 0, 8, 0x0a }, | ||
788 | { 0x9bd8, 0, 8, 0x14 }, | ||
789 | { 0x9bd9, 0, 8, 0x08 }, | ||
790 | }; | ||
791 | |||
792 | /* NXP TDA18271 tuner init | ||
793 | AF9013_TUNER_TDA18271 = 156 */ | ||
794 | static struct regdesc tuner_init_tda18271[] = { | ||
795 | { 0x9bd5, 0, 8, 0x01 }, | ||
796 | { 0x9bd6, 0, 8, 0x04 }, | ||
797 | { 0xd1a0, 1, 1, 0x01 }, | ||
798 | { 0xd000, 0, 1, 0x01 }, | ||
799 | { 0xd000, 1, 1, 0x00 }, | ||
800 | { 0xd001, 1, 1, 0x01 }, | ||
801 | { 0xd001, 0, 1, 0x00 }, | ||
802 | { 0xd001, 5, 1, 0x00 }, | ||
803 | { 0xd002, 0, 5, 0x19 }, | ||
804 | { 0xd003, 0, 5, 0x1a }, | ||
805 | { 0xd004, 0, 5, 0x19 }, | ||
806 | { 0xd005, 0, 5, 0x1a }, | ||
807 | { 0xd00e, 0, 5, 0x10 }, | ||
808 | { 0xd00f, 0, 3, 0x04 }, | ||
809 | { 0xd00f, 3, 3, 0x05 }, | ||
810 | { 0xd010, 0, 3, 0x04 }, | ||
811 | { 0xd010, 3, 3, 0x05 }, | ||
812 | { 0xd016, 4, 4, 0x03 }, | ||
813 | { 0xd01f, 0, 6, 0x0a }, | ||
814 | { 0xd020, 0, 6, 0x0a }, | ||
815 | { 0x9bda, 0, 8, 0x01 }, | ||
816 | { 0x9be3, 0, 8, 0x01 }, | ||
817 | { 0xd1a0, 1, 1, 0x00 }, | ||
818 | { 0x9bbe, 0, 1, 0x01 }, | ||
819 | { 0x9bcc, 0, 1, 0x01 }, | ||
820 | { 0x9bb9, 0, 8, 0x00 }, | ||
821 | { 0x9bcd, 0, 8, 0x18 }, | ||
822 | { 0x9bff, 0, 8, 0x2c }, | ||
823 | { 0xd015, 0, 8, 0x46 }, | ||
824 | { 0xd016, 0, 1, 0x00 }, | ||
825 | { 0xd044, 0, 8, 0x46 }, | ||
826 | { 0xd045, 0, 1, 0x00 }, | ||
827 | { 0xd008, 0, 8, 0xdf }, | ||
828 | { 0xd009, 0, 2, 0x02 }, | ||
829 | { 0xd006, 0, 8, 0x44 }, | ||
830 | { 0xd007, 0, 2, 0x01 }, | ||
831 | { 0xd00c, 0, 8, 0x00 }, | ||
832 | { 0xd00d, 0, 2, 0x02 }, | ||
833 | { 0xd00a, 0, 8, 0xf6 }, | ||
834 | { 0xd00b, 0, 2, 0x01 }, | ||
835 | { 0x9bba, 0, 8, 0xf9 }, | ||
836 | { 0x9bc8, 0, 8, 0xaa }, | ||
837 | { 0x9bc3, 0, 8, 0xdf }, | ||
838 | { 0x9bc4, 0, 8, 0x02 }, | ||
839 | { 0x9bc5, 0, 8, 0x00 }, | ||
840 | { 0x9bc6, 0, 8, 0x02 }, | ||
841 | { 0x9bc9, 0, 8, 0xf0 }, | ||
842 | { 0xd011, 0, 8, 0x3c }, | ||
843 | { 0xd012, 0, 2, 0x01 }, | ||
844 | { 0xd013, 0, 8, 0xf7 }, | ||
845 | { 0xd014, 0, 2, 0x02 }, | ||
846 | { 0xd040, 0, 8, 0x0b }, | ||
847 | { 0xd041, 0, 2, 0x02 }, | ||
848 | { 0xd042, 0, 8, 0x4d }, | ||
849 | { 0xd043, 0, 2, 0x00 }, | ||
850 | { 0xd045, 1, 1, 0x00 }, | ||
851 | { 0x9bcf, 0, 1, 0x01 }, | ||
852 | { 0xd045, 2, 1, 0x01 }, | ||
853 | { 0xd04f, 0, 8, 0x9a }, | ||
854 | { 0xd050, 0, 1, 0x01 }, | ||
855 | { 0xd051, 0, 8, 0x5a }, | ||
856 | { 0xd052, 0, 1, 0x01 }, | ||
857 | { 0xd053, 0, 8, 0x50 }, | ||
858 | { 0xd054, 0, 8, 0x46 }, | ||
859 | { 0x9bd7, 0, 8, 0x0a }, | ||
860 | { 0x9bd8, 0, 8, 0x14 }, | ||
861 | { 0x9bd9, 0, 8, 0x08 }, | ||
862 | { 0x9bd0, 0, 8, 0xa8 }, | ||
863 | { 0x9be4, 0, 8, 0x7f }, | ||
864 | { 0x9bbd, 0, 8, 0xa8 }, | ||
865 | { 0x9be2, 0, 8, 0x20 }, | ||
866 | { 0x9bee, 0, 1, 0x01 }, | ||
867 | }; | ||
868 | |||
869 | #endif /* _AF9013_PRIV_ */ | ||
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c index 0b82cc2a1e16..eabf9a68e7ec 100644 --- a/drivers/media/dvb/frontends/au8522.c +++ b/drivers/media/dvb/frontends/au8522.c | |||
@@ -40,6 +40,8 @@ struct au8522_state { | |||
40 | u32 current_frequency; | 40 | u32 current_frequency; |
41 | fe_modulation_t current_modulation; | 41 | fe_modulation_t current_modulation; |
42 | 42 | ||
43 | u32 fe_status; | ||
44 | unsigned int led_state; | ||
43 | }; | 45 | }; |
44 | 46 | ||
45 | static int debug; | 47 | static int debug; |
@@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe) | |||
538 | return 0; | 540 | return 0; |
539 | } | 541 | } |
540 | 542 | ||
543 | static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) | ||
544 | { | ||
545 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
546 | u8 val; | ||
547 | |||
548 | /* bail out if we cant control an LED */ | ||
549 | if (!led_config || !led_config->gpio_output || | ||
550 | !led_config->gpio_output_enable || !led_config->gpio_output_disable) | ||
551 | return 0; | ||
552 | |||
553 | val = au8522_readreg(state, 0x4000 | | ||
554 | (led_config->gpio_output & ~0xc000)); | ||
555 | if (onoff) { | ||
556 | /* enable GPIO output */ | ||
557 | val &= ~((led_config->gpio_output_enable >> 8) & 0xff); | ||
558 | val |= (led_config->gpio_output_enable & 0xff); | ||
559 | } else { | ||
560 | /* disable GPIO output */ | ||
561 | val &= ~((led_config->gpio_output_disable >> 8) & 0xff); | ||
562 | val |= (led_config->gpio_output_disable & 0xff); | ||
563 | } | ||
564 | return au8522_writereg(state, 0x8000 | | ||
565 | (led_config->gpio_output & ~0xc000), val); | ||
566 | } | ||
567 | |||
568 | /* led = 0 | off | ||
569 | * led = 1 | signal ok | ||
570 | * led = 2 | signal strong | ||
571 | * led < 0 | only light led if leds are currently off | ||
572 | */ | ||
573 | static int au8522_led_ctrl(struct au8522_state *state, int led) | ||
574 | { | ||
575 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
576 | int i, ret = 0; | ||
577 | |||
578 | /* bail out if we cant control an LED */ | ||
579 | if (!led_config || !led_config->gpio_leds || | ||
580 | !led_config->num_led_states || !led_config->led_states) | ||
581 | return 0; | ||
582 | |||
583 | if (led < 0) { | ||
584 | /* if LED is already lit, then leave it as-is */ | ||
585 | if (state->led_state) | ||
586 | return 0; | ||
587 | else | ||
588 | led *= -1; | ||
589 | } | ||
590 | |||
591 | /* toggle LED if changing state */ | ||
592 | if (state->led_state != led) { | ||
593 | u8 val; | ||
594 | |||
595 | dprintk("%s: %d\n", __func__, led); | ||
596 | |||
597 | au8522_led_gpio_enable(state, 1); | ||
598 | |||
599 | val = au8522_readreg(state, 0x4000 | | ||
600 | (led_config->gpio_leds & ~0xc000)); | ||
601 | |||
602 | /* start with all leds off */ | ||
603 | for (i = 0; i < led_config->num_led_states; i++) | ||
604 | val &= ~led_config->led_states[i]; | ||
605 | |||
606 | /* set selected LED state */ | ||
607 | if (led < led_config->num_led_states) | ||
608 | val |= led_config->led_states[led]; | ||
609 | else if (led_config->num_led_states) | ||
610 | val |= | ||
611 | led_config->led_states[led_config->num_led_states - 1]; | ||
612 | |||
613 | ret = au8522_writereg(state, 0x8000 | | ||
614 | (led_config->gpio_leds & ~0xc000), val); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | |||
618 | state->led_state = led; | ||
619 | |||
620 | if (led == 0) | ||
621 | au8522_led_gpio_enable(state, 0); | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
541 | static int au8522_sleep(struct dvb_frontend *fe) | 627 | static int au8522_sleep(struct dvb_frontend *fe) |
542 | { | 628 | { |
543 | struct au8522_state *state = fe->demodulator_priv; | 629 | struct au8522_state *state = fe->demodulator_priv; |
544 | dprintk("%s()\n", __func__); | 630 | dprintk("%s()\n", __func__); |
545 | 631 | ||
632 | /* turn off led */ | ||
633 | au8522_led_ctrl(state, 0); | ||
634 | |||
546 | state->current_frequency = 0; | 635 | state->current_frequency = 0; |
547 | 636 | ||
548 | return 0; | 637 | return 0; |
@@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) | |||
592 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; | 681 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; |
593 | break; | 682 | break; |
594 | } | 683 | } |
684 | state->fe_status = *status; | ||
685 | |||
686 | if (*status & FE_HAS_LOCK) | ||
687 | /* turn on LED, if it isn't on already */ | ||
688 | au8522_led_ctrl(state, -1); | ||
689 | else | ||
690 | /* turn off LED */ | ||
691 | au8522_led_ctrl(state, 0); | ||
595 | 692 | ||
596 | dprintk("%s() status 0x%08x\n", __func__, *status); | 693 | dprintk("%s() status 0x%08x\n", __func__, *status); |
597 | 694 | ||
598 | return 0; | 695 | return 0; |
599 | } | 696 | } |
600 | 697 | ||
698 | static int au8522_led_status(struct au8522_state *state, const u16 *snr) | ||
699 | { | ||
700 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
701 | int led; | ||
702 | u16 strong; | ||
703 | |||
704 | /* bail out if we cant control an LED */ | ||
705 | if (!led_config) | ||
706 | return 0; | ||
707 | |||
708 | if (0 == (state->fe_status & FE_HAS_LOCK)) | ||
709 | return au8522_led_ctrl(state, 0); | ||
710 | else if (state->current_modulation == QAM_256) | ||
711 | strong = led_config->qam256_strong; | ||
712 | else if (state->current_modulation == QAM_64) | ||
713 | strong = led_config->qam64_strong; | ||
714 | else /* (state->current_modulation == VSB_8) */ | ||
715 | strong = led_config->vsb8_strong; | ||
716 | |||
717 | if (*snr >= strong) | ||
718 | led = 2; | ||
719 | else | ||
720 | led = 1; | ||
721 | |||
722 | if ((state->led_state) && | ||
723 | (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) | ||
724 | /* snr didn't change enough to bother | ||
725 | * changing the color of the led */ | ||
726 | return 0; | ||
727 | |||
728 | return au8522_led_ctrl(state, led); | ||
729 | } | ||
730 | |||
601 | static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) | 731 | static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) |
602 | { | 732 | { |
603 | struct au8522_state *state = fe->demodulator_priv; | 733 | struct au8522_state *state = fe->demodulator_priv; |
@@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) | |||
621 | au8522_readreg(state, 0x4311), | 751 | au8522_readreg(state, 0x4311), |
622 | snr); | 752 | snr); |
623 | 753 | ||
754 | if (state->config->led_cfg) | ||
755 | au8522_led_status(state, snr); | ||
756 | |||
624 | return ret; | 757 | return ret; |
625 | } | 758 | } |
626 | 759 | ||
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h index 595915ade8c3..7b94f554a093 100644 --- a/drivers/media/dvb/frontends/au8522.h +++ b/drivers/media/dvb/frontends/au8522.h | |||
@@ -30,6 +30,21 @@ enum au8522_if_freq { | |||
30 | AU8522_IF_3_25MHZ, | 30 | AU8522_IF_3_25MHZ, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct au8522_led_config { | ||
34 | u16 vsb8_strong; | ||
35 | u16 qam64_strong; | ||
36 | u16 qam256_strong; | ||
37 | |||
38 | u16 gpio_output; | ||
39 | /* unset hi bits, set low bits */ | ||
40 | u16 gpio_output_enable; | ||
41 | u16 gpio_output_disable; | ||
42 | |||
43 | u16 gpio_leds; | ||
44 | u8 *led_states; | ||
45 | unsigned int num_led_states; | ||
46 | }; | ||
47 | |||
33 | struct au8522_config { | 48 | struct au8522_config { |
34 | /* the demodulator's i2c address */ | 49 | /* the demodulator's i2c address */ |
35 | u8 demod_address; | 50 | u8 demod_address; |
@@ -39,6 +54,8 @@ struct au8522_config { | |||
39 | #define AU8522_DEMODLOCKING 1 | 54 | #define AU8522_DEMODLOCKING 1 |
40 | u8 status_mode; | 55 | u8 status_mode; |
41 | 56 | ||
57 | struct au8522_led_config *led_cfg; | ||
58 | |||
42 | enum au8522_if_freq vsb_if; | 59 | enum au8522_if_freq vsb_if; |
43 | enum au8522_if_freq qam_if; | 60 | enum au8522_if_freq qam_if; |
44 | }; | 61 | }; |
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 1792adb23c4d..fdcceee91f3a 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h | |||
@@ -33,12 +33,17 @@ struct cx24110_config | |||
33 | u8 demod_address; | 33 | u8 demod_address; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) { | 36 | static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) |
37 | int r = 0; | 37 | { |
38 | u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)}; | 38 | u8 buf[] = { |
39 | (u8)((val >> 24) & 0xff), | ||
40 | (u8)((val >> 16) & 0xff), | ||
41 | (u8)((val >> 8) & 0xff) | ||
42 | }; | ||
43 | |||
39 | if (fe->ops.write) | 44 | if (fe->ops.write) |
40 | r = fe->ops.write(fe, buf, 3); | 45 | return fe->ops.write(fe, buf, 3); |
41 | return r; | 46 | return 0; |
42 | } | 47 | } |
43 | 48 | ||
44 | #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) | 49 | #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) |
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c new file mode 100644 index 000000000000..deb36f469ada --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.c | |||
@@ -0,0 +1,1423 @@ | |||
1 | /* | ||
2 | Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver | ||
3 | |||
4 | Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com> | ||
5 | Copyright (C) 2006-2007 Georg Acher | ||
6 | Copyright (C) 2007-2008 Darron Broad | ||
7 | March 2007 | ||
8 | Fixed some bugs. | ||
9 | Added diseqc support. | ||
10 | Added corrected signal strength support. | ||
11 | August 2007 | ||
12 | Sync with legacy version. | ||
13 | Some clean ups. | ||
14 | Copyright (C) 2008 Igor Liplianin | ||
15 | September, 9th 2008 | ||
16 | Fixed locking on high symbol rates (>30000). | ||
17 | Implement MPEG initialization parameter. | ||
18 | |||
19 | This program is free software; you can redistribute it and/or modify | ||
20 | it under the terms of the GNU General Public License as published by | ||
21 | the Free Software Foundation; either version 2 of the License, or | ||
22 | (at your option) any later version. | ||
23 | |||
24 | This program is distributed in the hope that it will be useful, | ||
25 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | GNU General Public License for more details. | ||
28 | |||
29 | You should have received a copy of the GNU General Public License | ||
30 | along with this program; if not, write to the Free Software | ||
31 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | |||
34 | #include <linux/slab.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/firmware.h> | ||
40 | |||
41 | #include "dvb_frontend.h" | ||
42 | #include "cx24116.h" | ||
43 | |||
44 | static int debug = 0; | ||
45 | #define dprintk(args...) \ | ||
46 | do { \ | ||
47 | if (debug) printk ("cx24116: " args); \ | ||
48 | } while (0) | ||
49 | |||
50 | #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" | ||
51 | #define CX24116_SEARCH_RANGE_KHZ 5000 | ||
52 | |||
53 | /* known registers */ | ||
54 | #define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ | ||
55 | #define CX24116_REG_EXECUTE (0x1f) /* execute command */ | ||
56 | #define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ | ||
57 | #define CX24116_REG_RESET (0x20) /* reset status > 0 */ | ||
58 | #define CX24116_REG_SIGNAL (0x9e) /* signal low */ | ||
59 | #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ | ||
60 | #define CX24116_REG_QUALITY8 (0xa3) | ||
61 | #define CX24116_REG_QSTATUS (0xbc) | ||
62 | #define CX24116_REG_QUALITY0 (0xd5) | ||
63 | #define CX24116_REG_BER0 (0xc9) | ||
64 | #define CX24116_REG_BER8 (0xc8) | ||
65 | #define CX24116_REG_BER16 (0xc7) | ||
66 | #define CX24116_REG_BER24 (0xc6) | ||
67 | #define CX24116_REG_UCB0 (0xcb) | ||
68 | #define CX24116_REG_UCB8 (0xca) | ||
69 | #define CX24116_REG_CLKDIV (0xf3) | ||
70 | #define CX24116_REG_RATEDIV (0xf9) | ||
71 | #define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ | ||
72 | |||
73 | /* FECSTATUS bits */ | ||
74 | #define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */ | ||
75 | #define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */ | ||
76 | #define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ | ||
77 | #define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */ | ||
78 | |||
79 | /* arg buffer size */ | ||
80 | #define CX24116_ARGLEN (0x1e) | ||
81 | |||
82 | /* rolloff */ | ||
83 | #define CX24116_ROLLOFF_020 (0x00) | ||
84 | #define CX24116_ROLLOFF_025 (0x01) | ||
85 | #define CX24116_ROLLOFF_035 (0x02) | ||
86 | |||
87 | /* pilot bit */ | ||
88 | #define CX24116_PILOT_OFF (0x00) | ||
89 | #define CX24116_PILOT_ON (0x40) | ||
90 | |||
91 | /* signal status */ | ||
92 | #define CX24116_HAS_SIGNAL (0x01) | ||
93 | #define CX24116_HAS_CARRIER (0x02) | ||
94 | #define CX24116_HAS_VITERBI (0x04) | ||
95 | #define CX24116_HAS_SYNCLOCK (0x08) | ||
96 | #define CX24116_HAS_UNKNOWN1 (0x10) | ||
97 | #define CX24116_HAS_UNKNOWN2 (0x20) | ||
98 | #define CX24116_STATUS_MASK (0x3f) | ||
99 | #define CX24116_SIGNAL_MASK (0xc0) | ||
100 | |||
101 | #define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ | ||
102 | #define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ | ||
103 | #define CX24116_DISEQC_MESGCACHE (2) /* message cached */ | ||
104 | |||
105 | /* arg offset for DiSEqC */ | ||
106 | #define CX24116_DISEQC_BURST (1) | ||
107 | #define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ | ||
108 | #define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ | ||
109 | #define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ | ||
110 | #define CX24116_DISEQC_MSGLEN (5) | ||
111 | #define CX24116_DISEQC_MSGOFS (6) | ||
112 | |||
113 | /* DiSEqC burst */ | ||
114 | #define CX24116_DISEQC_MINI_A (0) | ||
115 | #define CX24116_DISEQC_MINI_B (1) | ||
116 | |||
117 | /* DiSEqC tone burst */ | ||
118 | static int toneburst = 1; | ||
119 | |||
120 | /* SNR measurements */ | ||
121 | static int esno_snr = 0; | ||
122 | |||
123 | enum cmds | ||
124 | { | ||
125 | CMD_SET_VCO = 0x10, | ||
126 | CMD_TUNEREQUEST = 0x11, | ||
127 | CMD_MPEGCONFIG = 0x13, | ||
128 | CMD_TUNERINIT = 0x14, | ||
129 | CMD_BANDWIDTH = 0x15, | ||
130 | CMD_GETAGC = 0x19, | ||
131 | CMD_LNBCONFIG = 0x20, | ||
132 | CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ | ||
133 | CMD_SET_TONEPRE = 0x22, | ||
134 | CMD_SET_TONE = 0x23, | ||
135 | CMD_UPDFWVERS = 0x35, | ||
136 | CMD_TUNERSLEEP = 0x36, | ||
137 | CMD_AGCCONTROL = 0x3b, /* Unknown */ | ||
138 | }; | ||
139 | |||
140 | /* The Demod/Tuner can't easily provide these, we cache them */ | ||
141 | struct cx24116_tuning | ||
142 | { | ||
143 | u32 frequency; | ||
144 | u32 symbol_rate; | ||
145 | fe_spectral_inversion_t inversion; | ||
146 | fe_code_rate_t fec; | ||
147 | |||
148 | fe_modulation_t modulation; | ||
149 | fe_pilot_t pilot; | ||
150 | fe_rolloff_t rolloff; | ||
151 | |||
152 | /* Demod values */ | ||
153 | u8 fec_val; | ||
154 | u8 fec_mask; | ||
155 | u8 inversion_val; | ||
156 | u8 pilot_val; | ||
157 | u8 rolloff_val; | ||
158 | }; | ||
159 | |||
160 | /* Basic commands that are sent to the firmware */ | ||
161 | struct cx24116_cmd | ||
162 | { | ||
163 | u8 len; | ||
164 | u8 args[CX24116_ARGLEN]; | ||
165 | }; | ||
166 | |||
167 | struct cx24116_state | ||
168 | { | ||
169 | struct i2c_adapter* i2c; | ||
170 | const struct cx24116_config* config; | ||
171 | |||
172 | struct dvb_frontend frontend; | ||
173 | |||
174 | struct cx24116_tuning dcur; | ||
175 | struct cx24116_tuning dnxt; | ||
176 | |||
177 | u8 skip_fw_load; | ||
178 | u8 burst; | ||
179 | struct cx24116_cmd dsec_cmd; | ||
180 | }; | ||
181 | |||
182 | static int cx24116_writereg(struct cx24116_state* state, int reg, int data) | ||
183 | { | ||
184 | u8 buf[] = { reg, data }; | ||
185 | struct i2c_msg msg = { .addr = state->config->demod_address, | ||
186 | .flags = 0, .buf = buf, .len = 2 }; | ||
187 | int err; | ||
188 | |||
189 | if (debug>1) | ||
190 | printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", | ||
191 | __func__,reg, data); | ||
192 | |||
193 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
194 | printk("%s: writereg error(err == %i, reg == 0x%02x," | ||
195 | " value == 0x%02x)\n", __func__, err, reg, data); | ||
196 | return -EREMOTEIO; | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /* Bulk byte writes to a single I2C address, for 32k firmware load */ | ||
203 | static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len) | ||
204 | { | ||
205 | int ret = -EREMOTEIO; | ||
206 | struct i2c_msg msg; | ||
207 | u8 *buf; | ||
208 | |||
209 | buf = kmalloc(len + 1, GFP_KERNEL); | ||
210 | if (buf == NULL) { | ||
211 | printk("Unable to kmalloc\n"); | ||
212 | ret = -ENOMEM; | ||
213 | goto error; | ||
214 | } | ||
215 | |||
216 | *(buf) = reg; | ||
217 | memcpy(buf + 1, data, len); | ||
218 | |||
219 | msg.addr = state->config->demod_address; | ||
220 | msg.flags = 0; | ||
221 | msg.buf = buf; | ||
222 | msg.len = len + 1; | ||
223 | |||
224 | if (debug>1) | ||
225 | printk("cx24116: %s: write regN 0x%02x, len = %d\n", | ||
226 | __func__,reg, len); | ||
227 | |||
228 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
229 | printk("%s: writereg error(err == %i, reg == 0x%02x\n", | ||
230 | __func__, ret, reg); | ||
231 | ret = -EREMOTEIO; | ||
232 | } | ||
233 | |||
234 | error: | ||
235 | kfree(buf); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static int cx24116_readreg(struct cx24116_state* state, u8 reg) | ||
241 | { | ||
242 | int ret; | ||
243 | u8 b0[] = { reg }; | ||
244 | u8 b1[] = { 0 }; | ||
245 | struct i2c_msg msg[] = { | ||
246 | { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
247 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } | ||
248 | }; | ||
249 | |||
250 | ret = i2c_transfer(state->i2c, msg, 2); | ||
251 | |||
252 | if (ret != 2) { | ||
253 | printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | if (debug>1) | ||
258 | printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]); | ||
259 | |||
260 | return b1[0]; | ||
261 | } | ||
262 | |||
263 | static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion) | ||
264 | { | ||
265 | dprintk("%s(%d)\n", __func__, inversion); | ||
266 | |||
267 | switch (inversion) { | ||
268 | case INVERSION_OFF: | ||
269 | state->dnxt.inversion_val = 0x00; | ||
270 | break; | ||
271 | case INVERSION_ON: | ||
272 | state->dnxt.inversion_val = 0x04; | ||
273 | break; | ||
274 | case INVERSION_AUTO: | ||
275 | state->dnxt.inversion_val = 0x0C; | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | state->dnxt.inversion = inversion; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * modfec (modulation and FEC) | ||
288 | * =========================== | ||
289 | * | ||
290 | * MOD FEC mask/val standard | ||
291 | * ---- -------- ----------- -------- | ||
292 | * QPSK FEC_1_2 0x02 0x02+X DVB-S | ||
293 | * QPSK FEC_2_3 0x04 0x02+X DVB-S | ||
294 | * QPSK FEC_3_4 0x08 0x02+X DVB-S | ||
295 | * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) | ||
296 | * QPSK FEC_5_6 0x20 0x02+X DVB-S | ||
297 | * QPSK FEC_6_7 0x40 0x02+X DVB-S | ||
298 | * QPSK FEC_7_8 0x80 0x02+X DVB-S | ||
299 | * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) | ||
300 | * QPSK AUTO 0xff 0x02+X DVB-S | ||
301 | * | ||
302 | * For DVB-S high byte probably represents FEC | ||
303 | * and low byte selects the modulator. The high | ||
304 | * byte is search range mask. Bit 5 may turn | ||
305 | * on DVB-S and remaining bits represent some | ||
306 | * kind of calibration (how/what i do not know). | ||
307 | * | ||
308 | * Eg.(2/3) szap "Zone Horror" | ||
309 | * | ||
310 | * mask/val = 0x04, 0x20 | ||
311 | * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK | ||
312 | * | ||
313 | * mask/val = 0x04, 0x30 | ||
314 | * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK | ||
315 | * | ||
316 | * After tuning FECSTATUS contains actual FEC | ||
317 | * in use numbered 1 through to 8 for 1/2 .. 2/3 etc | ||
318 | * | ||
319 | * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) | ||
320 | * | ||
321 | * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 | ||
322 | * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 | ||
323 | * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 | ||
324 | * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 | ||
325 | * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 | ||
326 | * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 | ||
327 | * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 | ||
328 | * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 | ||
329 | * | ||
330 | * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 | ||
331 | * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 | ||
332 | * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 | ||
333 | * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 | ||
334 | * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 | ||
335 | * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 | ||
336 | * | ||
337 | * For DVB-S2 low bytes selects both modulator | ||
338 | * and FEC. High byte is meaningless here. To | ||
339 | * set pilot, bit 6 (0x40) is set. When inspecting | ||
340 | * FECSTATUS bit 7 (0x80) represents the pilot | ||
341 | * selection whilst not tuned. When tuned, actual FEC | ||
342 | * in use is found in FECSTATUS as per above. Pilot | ||
343 | * value is reset. | ||
344 | */ | ||
345 | |||
346 | /* A table of modulation, fec and configuration bytes for the demod. | ||
347 | * Not all S2 mmodulation schemes are support and not all rates with | ||
348 | * a scheme are support. Especially, no auto detect when in S2 mode. | ||
349 | */ | ||
350 | struct cx24116_modfec { | ||
351 | fe_delivery_system_t delivery_system; | ||
352 | fe_modulation_t modulation; | ||
353 | fe_code_rate_t fec; | ||
354 | u8 mask; /* In DVBS mode this is used to autodetect */ | ||
355 | u8 val; /* Passed to the firmware to indicate mode selection */ | ||
356 | } CX24116_MODFEC_MODES[] = { | ||
357 | /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ | ||
358 | |||
359 | /*mod fec mask val */ | ||
360 | { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, | ||
361 | { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ | ||
362 | { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ | ||
363 | { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ | ||
364 | { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ | ||
365 | { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ | ||
366 | { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ | ||
367 | { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ | ||
368 | { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ | ||
369 | { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, | ||
370 | /* NBC-QPSK */ | ||
371 | { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, | ||
372 | { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, | ||
373 | { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, | ||
374 | { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, | ||
375 | { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, | ||
376 | { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, | ||
377 | { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, | ||
378 | { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, | ||
379 | /* 8PSK */ | ||
380 | { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, | ||
381 | { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, | ||
382 | { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, | ||
383 | { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, | ||
384 | { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, | ||
385 | { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, | ||
386 | /* | ||
387 | * `val' can be found in the FECSTATUS register when tuning. | ||
388 | * FECSTATUS will give the actual FEC in use if tuning was successful. | ||
389 | */ | ||
390 | }; | ||
391 | |||
392 | static int cx24116_lookup_fecmod(struct cx24116_state* state, | ||
393 | fe_modulation_t m, fe_code_rate_t f) | ||
394 | { | ||
395 | int i, ret = -EOPNOTSUPP; | ||
396 | |||
397 | dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); | ||
398 | |||
399 | for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) | ||
400 | { | ||
401 | if( (m == CX24116_MODFEC_MODES[i].modulation) && | ||
402 | (f == CX24116_MODFEC_MODES[i].fec) ) | ||
403 | { | ||
404 | ret = i; | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) | ||
413 | { | ||
414 | int ret = 0; | ||
415 | |||
416 | dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); | ||
417 | |||
418 | ret = cx24116_lookup_fecmod(state, mod, fec); | ||
419 | |||
420 | if(ret < 0) | ||
421 | return ret; | ||
422 | |||
423 | state->dnxt.fec = fec; | ||
424 | state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; | ||
425 | state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; | ||
426 | dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, | ||
427 | state->dnxt.fec_mask, state->dnxt.fec_val); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) | ||
433 | { | ||
434 | dprintk("%s(%d)\n", __func__, rate); | ||
435 | |||
436 | /* check if symbol rate is within limits */ | ||
437 | if ((rate > state->frontend.ops.info.symbol_rate_max) || | ||
438 | (rate < state->frontend.ops.info.symbol_rate_min)) { | ||
439 | dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); | ||
440 | return -EOPNOTSUPP; | ||
441 | } | ||
442 | |||
443 | state->dnxt.symbol_rate = rate; | ||
444 | dprintk("%s() symbol_rate = %d\n", __func__, rate); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); | ||
450 | |||
451 | static int cx24116_firmware_ondemand(struct dvb_frontend* fe) | ||
452 | { | ||
453 | struct cx24116_state *state = fe->demodulator_priv; | ||
454 | const struct firmware *fw; | ||
455 | int ret = 0; | ||
456 | |||
457 | dprintk("%s()\n",__func__); | ||
458 | |||
459 | if (cx24116_readreg(state, 0x20) > 0) | ||
460 | { | ||
461 | |||
462 | if (state->skip_fw_load) | ||
463 | return 0; | ||
464 | |||
465 | /* Load firmware */ | ||
466 | /* request the firmware, this will block until someone uploads it */ | ||
467 | printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); | ||
468 | ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev); | ||
469 | printk("%s: Waiting for firmware upload(2)...\n", __func__); | ||
470 | if (ret) { | ||
471 | printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | /* Make sure we don't recurse back through here during loading */ | ||
476 | state->skip_fw_load = 1; | ||
477 | |||
478 | ret = cx24116_load_firmware(fe, fw); | ||
479 | if (ret) | ||
480 | printk("%s: Writing firmware to device failed\n", __func__); | ||
481 | |||
482 | release_firmware(fw); | ||
483 | |||
484 | printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); | ||
485 | |||
486 | /* Ensure firmware is always loaded if required */ | ||
487 | state->skip_fw_load = 0; | ||
488 | } | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | /* Take a basic firmware command structure, format it and forward it for processing */ | ||
494 | static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) | ||
495 | { | ||
496 | struct cx24116_state *state = fe->demodulator_priv; | ||
497 | int i, ret; | ||
498 | |||
499 | dprintk("%s()\n", __func__); | ||
500 | |||
501 | /* Load the firmware if required */ | ||
502 | if ( (ret = cx24116_firmware_ondemand(fe)) != 0) | ||
503 | { | ||
504 | printk("%s(): Unable initialise the firmware\n", __func__); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /* Write the command */ | ||
509 | for(i = 0; i < cmd->len ; i++) | ||
510 | { | ||
511 | dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); | ||
512 | cx24116_writereg(state, i, cmd->args[i]); | ||
513 | } | ||
514 | |||
515 | /* Start execution and wait for cmd to terminate */ | ||
516 | cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); | ||
517 | while( cx24116_readreg(state, CX24116_REG_EXECUTE) ) | ||
518 | { | ||
519 | msleep(10); | ||
520 | if(i++ > 64) | ||
521 | { | ||
522 | /* Avoid looping forever if the firmware does no respond */ | ||
523 | printk("%s() Firmware not responding\n", __func__); | ||
524 | return -EREMOTEIO; | ||
525 | } | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
531 | { | ||
532 | struct cx24116_state* state = fe->demodulator_priv; | ||
533 | struct cx24116_cmd cmd; | ||
534 | int i, ret; | ||
535 | unsigned char vers[4]; | ||
536 | |||
537 | dprintk("%s\n", __func__); | ||
538 | dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" | ||
539 | ,fw->size | ||
540 | ,fw->data[0] | ||
541 | ,fw->data[1] | ||
542 | ,fw->data[ fw->size-2 ] | ||
543 | ,fw->data[ fw->size-1 ] | ||
544 | ); | ||
545 | |||
546 | /* Toggle 88x SRST pin to reset demod */ | ||
547 | if (state->config->reset_device) | ||
548 | state->config->reset_device(fe); | ||
549 | |||
550 | /* Begin the firmware load process */ | ||
551 | /* Prepare the demod, load the firmware, cleanup after load */ | ||
552 | |||
553 | /* Init PLL */ | ||
554 | cx24116_writereg(state, 0xE5, 0x00); | ||
555 | cx24116_writereg(state, 0xF1, 0x08); | ||
556 | cx24116_writereg(state, 0xF2, 0x13); | ||
557 | |||
558 | /* Start PLL */ | ||
559 | cx24116_writereg(state, 0xe0, 0x03); | ||
560 | cx24116_writereg(state, 0xe0, 0x00); | ||
561 | |||
562 | /* Unknown */ | ||
563 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
564 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
565 | |||
566 | /* Unknown */ | ||
567 | cx24116_writereg(state, 0xF0, 0x03); | ||
568 | cx24116_writereg(state, 0xF4, 0x81); | ||
569 | cx24116_writereg(state, 0xF5, 0x00); | ||
570 | cx24116_writereg(state, 0xF6, 0x00); | ||
571 | |||
572 | /* write the entire firmware as one transaction */ | ||
573 | cx24116_writeregN(state, 0xF7, fw->data, fw->size); | ||
574 | |||
575 | cx24116_writereg(state, 0xF4, 0x10); | ||
576 | cx24116_writereg(state, 0xF0, 0x00); | ||
577 | cx24116_writereg(state, 0xF8, 0x06); | ||
578 | |||
579 | /* Firmware CMD 10: VCO config */ | ||
580 | cmd.args[0x00] = CMD_SET_VCO; | ||
581 | cmd.args[0x01] = 0x05; | ||
582 | cmd.args[0x02] = 0xdc; | ||
583 | cmd.args[0x03] = 0xda; | ||
584 | cmd.args[0x04] = 0xae; | ||
585 | cmd.args[0x05] = 0xaa; | ||
586 | cmd.args[0x06] = 0x04; | ||
587 | cmd.args[0x07] = 0x9d; | ||
588 | cmd.args[0x08] = 0xfc; | ||
589 | cmd.args[0x09] = 0x06; | ||
590 | cmd.len= 0x0a; | ||
591 | ret = cx24116_cmd_execute(fe, &cmd); | ||
592 | if (ret != 0) | ||
593 | return ret; | ||
594 | |||
595 | cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); | ||
596 | |||
597 | /* Firmware CMD 14: Tuner config */ | ||
598 | cmd.args[0x00] = CMD_TUNERINIT; | ||
599 | cmd.args[0x01] = 0x00; | ||
600 | cmd.args[0x02] = 0x00; | ||
601 | cmd.len= 0x03; | ||
602 | ret = cx24116_cmd_execute(fe, &cmd); | ||
603 | if (ret != 0) | ||
604 | return ret; | ||
605 | |||
606 | cx24116_writereg(state, 0xe5, 0x00); | ||
607 | |||
608 | /* Firmware CMD 13: MPEG config */ | ||
609 | cmd.args[0x00] = CMD_MPEGCONFIG; | ||
610 | cmd.args[0x01] = 0x01; | ||
611 | cmd.args[0x02] = 0x75; | ||
612 | cmd.args[0x03] = 0x00; | ||
613 | if (state->config->mpg_clk_pos_pol) | ||
614 | cmd.args[0x04] = state->config->mpg_clk_pos_pol; | ||
615 | else | ||
616 | cmd.args[0x04] = 0x02; | ||
617 | cmd.args[0x05] = 0x00; | ||
618 | cmd.len= 0x06; | ||
619 | ret = cx24116_cmd_execute(fe, &cmd); | ||
620 | if (ret != 0) | ||
621 | return ret; | ||
622 | |||
623 | /* Firmware CMD 35: Get firmware version */ | ||
624 | cmd.args[0x00] = CMD_UPDFWVERS; | ||
625 | cmd.len= 0x02; | ||
626 | for(i=0; i<4; i++) { | ||
627 | cmd.args[0x01] = i; | ||
628 | ret = cx24116_cmd_execute(fe, &cmd); | ||
629 | if (ret != 0) | ||
630 | return ret; | ||
631 | vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX); | ||
632 | } | ||
633 | printk("%s: FW version %i.%i.%i.%i\n", __func__, | ||
634 | vers[0], vers[1], vers[2], vers[3]); | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
640 | { | ||
641 | /* The isl6421 module will override this function in the fops. */ | ||
642 | dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__); | ||
643 | |||
644 | return -EOPNOTSUPP; | ||
645 | } | ||
646 | |||
647 | static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
648 | { | ||
649 | struct cx24116_state *state = fe->demodulator_priv; | ||
650 | |||
651 | int lock = cx24116_readreg(state, CX24116_REG_SSTATUS); | ||
652 | |||
653 | dprintk("%s: status = 0x%02x\n", __func__, lock); | ||
654 | |||
655 | *status = 0; | ||
656 | |||
657 | if (lock & CX24116_HAS_SIGNAL) | ||
658 | *status |= FE_HAS_SIGNAL; | ||
659 | if (lock & CX24116_HAS_CARRIER) | ||
660 | *status |= FE_HAS_CARRIER; | ||
661 | if (lock & CX24116_HAS_VITERBI) | ||
662 | *status |= FE_HAS_VITERBI; | ||
663 | if (lock & CX24116_HAS_SYNCLOCK) | ||
664 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) | ||
670 | { | ||
671 | struct cx24116_state *state = fe->demodulator_priv; | ||
672 | |||
673 | dprintk("%s()\n", __func__); | ||
674 | |||
675 | *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) | | ||
676 | ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) | | ||
677 | ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) | | ||
678 | cx24116_readreg(state, CX24116_REG_BER0 ); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* TODO Determine function and scale appropriately */ | ||
684 | static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
685 | { | ||
686 | struct cx24116_state *state = fe->demodulator_priv; | ||
687 | struct cx24116_cmd cmd; | ||
688 | int ret; | ||
689 | u16 sig_reading; | ||
690 | |||
691 | dprintk("%s()\n", __func__); | ||
692 | |||
693 | /* Firmware CMD 19: Get AGC */ | ||
694 | cmd.args[0x00] = CMD_GETAGC; | ||
695 | cmd.len= 0x01; | ||
696 | ret = cx24116_cmd_execute(fe, &cmd); | ||
697 | if (ret != 0) | ||
698 | return ret; | ||
699 | |||
700 | sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) | | ||
701 | ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 ); | ||
702 | *signal_strength= 0 - sig_reading; | ||
703 | |||
704 | dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ | ||
710 | static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) | ||
711 | { | ||
712 | struct cx24116_state *state = fe->demodulator_priv; | ||
713 | u8 snr_reading; | ||
714 | static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ | ||
715 | 0x00000,0x0199A,0x03333,0x04ccD,0x06667, | ||
716 | 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, | ||
717 | 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; | ||
718 | |||
719 | dprintk("%s()\n", __func__); | ||
720 | |||
721 | snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
722 | |||
723 | if(snr_reading >= 0xa0 /* 100% */) | ||
724 | *snr = 0xffff; | ||
725 | else | ||
726 | *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] + | ||
727 | ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 ); | ||
728 | |||
729 | dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, | ||
730 | snr_reading, *snr); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* The reelbox patches show the value in the registers represents | ||
736 | * ESNO, from 0->30db (values 0->300). We provide this value by | ||
737 | * default. | ||
738 | */ | ||
739 | static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) | ||
740 | { | ||
741 | struct cx24116_state *state = fe->demodulator_priv; | ||
742 | |||
743 | dprintk("%s()\n", __func__); | ||
744 | |||
745 | *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | | ||
746 | cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
747 | |||
748 | dprintk("%s: raw 0x%04x\n", __func__, *snr); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) | ||
754 | { | ||
755 | if (esno_snr == 1) | ||
756 | return cx24116_read_snr_esno(fe, snr); | ||
757 | else | ||
758 | return cx24116_read_snr_pct(fe, snr); | ||
759 | } | ||
760 | |||
761 | static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
762 | { | ||
763 | struct cx24116_state *state = fe->demodulator_priv; | ||
764 | |||
765 | dprintk("%s()\n", __func__); | ||
766 | |||
767 | *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) | | ||
768 | cx24116_readreg(state, CX24116_REG_UCB0); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | /* Overwrite the current tuning params, we are about to tune */ | ||
774 | static void cx24116_clone_params(struct dvb_frontend* fe) | ||
775 | { | ||
776 | struct cx24116_state *state = fe->demodulator_priv; | ||
777 | memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); | ||
778 | } | ||
779 | |||
780 | /* Wait for LNB */ | ||
781 | static int cx24116_wait_for_lnb(struct dvb_frontend* fe) | ||
782 | { | ||
783 | struct cx24116_state *state = fe->demodulator_priv; | ||
784 | int i; | ||
785 | |||
786 | dprintk("%s() qstatus = 0x%02x\n", __func__, | ||
787 | cx24116_readreg(state, CX24116_REG_QSTATUS)); | ||
788 | |||
789 | /* Wait for up to 300 ms */ | ||
790 | for(i = 0; i < 30 ; i++) { | ||
791 | if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) | ||
792 | return 0; | ||
793 | msleep(10); | ||
794 | } | ||
795 | |||
796 | dprintk("%s(): LNB not ready\n", __func__); | ||
797 | |||
798 | return -ETIMEDOUT; /* -EBUSY ? */ | ||
799 | } | ||
800 | |||
801 | static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
802 | { | ||
803 | struct cx24116_cmd cmd; | ||
804 | int ret; | ||
805 | |||
806 | dprintk("%s(%d)\n", __func__, tone); | ||
807 | if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) { | ||
808 | printk("%s: Invalid, tone=%d\n", __func__, tone); | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | /* Wait for LNB ready */ | ||
813 | ret = cx24116_wait_for_lnb(fe); | ||
814 | if(ret != 0) | ||
815 | return ret; | ||
816 | |||
817 | /* Min delay time after DiSEqC send */ | ||
818 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
819 | |||
820 | /* This is always done before the tone is set */ | ||
821 | cmd.args[0x00] = CMD_SET_TONEPRE; | ||
822 | cmd.args[0x01] = 0x00; | ||
823 | cmd.len= 0x02; | ||
824 | ret = cx24116_cmd_execute(fe, &cmd); | ||
825 | if (ret != 0) | ||
826 | return ret; | ||
827 | |||
828 | /* Now we set the tone */ | ||
829 | cmd.args[0x00] = CMD_SET_TONE; | ||
830 | cmd.args[0x01] = 0x00; | ||
831 | cmd.args[0x02] = 0x00; | ||
832 | |||
833 | switch (tone) { | ||
834 | case SEC_TONE_ON: | ||
835 | dprintk("%s: setting tone on\n", __func__); | ||
836 | cmd.args[0x03] = 0x01; | ||
837 | break; | ||
838 | case SEC_TONE_OFF: | ||
839 | dprintk("%s: setting tone off\n",__func__); | ||
840 | cmd.args[0x03] = 0x00; | ||
841 | break; | ||
842 | } | ||
843 | cmd.len= 0x04; | ||
844 | |||
845 | /* Min delay time before DiSEqC send */ | ||
846 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
847 | |||
848 | return cx24116_cmd_execute(fe, &cmd); | ||
849 | } | ||
850 | |||
851 | /* Initialise DiSEqC */ | ||
852 | static int cx24116_diseqc_init(struct dvb_frontend* fe) | ||
853 | { | ||
854 | struct cx24116_state *state = fe->demodulator_priv; | ||
855 | struct cx24116_cmd cmd; | ||
856 | int ret; | ||
857 | |||
858 | /* Firmware CMD 20: LNB/DiSEqC config */ | ||
859 | cmd.args[0x00] = CMD_LNBCONFIG; | ||
860 | cmd.args[0x01] = 0x00; | ||
861 | cmd.args[0x02] = 0x10; | ||
862 | cmd.args[0x03] = 0x00; | ||
863 | cmd.args[0x04] = 0x8f; | ||
864 | cmd.args[0x05] = 0x28; | ||
865 | cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; | ||
866 | cmd.args[0x07] = 0x01; | ||
867 | cmd.len= 0x08; | ||
868 | ret = cx24116_cmd_execute(fe, &cmd); | ||
869 | if (ret != 0) | ||
870 | return ret; | ||
871 | |||
872 | /* Prepare a DiSEqC command */ | ||
873 | state->dsec_cmd.args[0x00] = CMD_LNBSEND; | ||
874 | |||
875 | /* DiSEqC burst */ | ||
876 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
877 | |||
878 | /* Unknown */ | ||
879 | state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; | ||
880 | state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; | ||
881 | state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */ | ||
882 | |||
883 | /* DiSEqC message length */ | ||
884 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; | ||
885 | |||
886 | /* Command length */ | ||
887 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS; | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | /* Send DiSEqC message with derived burst (hack) || previous burst */ | ||
893 | static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) | ||
894 | { | ||
895 | struct cx24116_state *state = fe->demodulator_priv; | ||
896 | int i, ret; | ||
897 | |||
898 | /* Dump DiSEqC message */ | ||
899 | if (debug) { | ||
900 | printk("cx24116: %s(", __func__); | ||
901 | for(i = 0 ; i < d->msg_len ;) { | ||
902 | printk("0x%02x", d->msg[i]); | ||
903 | if(++i < d->msg_len) | ||
904 | printk(", "); | ||
905 | } | ||
906 | printk(") toneburst=%d\n", toneburst); | ||
907 | } | ||
908 | |||
909 | /* Validate length */ | ||
910 | if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) | ||
911 | return -EINVAL; | ||
912 | |||
913 | /* DiSEqC message */ | ||
914 | for (i = 0; i < d->msg_len; i++) | ||
915 | state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; | ||
916 | |||
917 | /* DiSEqC message length */ | ||
918 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; | ||
919 | |||
920 | /* Command length */ | ||
921 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; | ||
922 | |||
923 | /* DiSEqC toneburst */ | ||
924 | if(toneburst == CX24116_DISEQC_MESGCACHE) | ||
925 | /* Message is cached */ | ||
926 | return 0; | ||
927 | |||
928 | else if(toneburst == CX24116_DISEQC_TONEOFF) | ||
929 | /* Message is sent without burst */ | ||
930 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; | ||
931 | |||
932 | else if(toneburst == CX24116_DISEQC_TONECACHE) { | ||
933 | /* | ||
934 | * Message is sent with derived else cached burst | ||
935 | * | ||
936 | * WRITE PORT GROUP COMMAND 38 | ||
937 | * | ||
938 | * 0/A/A: E0 10 38 F0..F3 | ||
939 | * 1/B/B: E0 10 38 F4..F7 | ||
940 | * 2/C/A: E0 10 38 F8..FB | ||
941 | * 3/D/B: E0 10 38 FC..FF | ||
942 | * | ||
943 | * databyte[3]= 8421:8421 | ||
944 | * ABCD:WXYZ | ||
945 | * CLR :SET | ||
946 | * | ||
947 | * WX= PORT SELECT 0..3 (X=TONEBURST) | ||
948 | * Y = VOLTAGE (0=13V, 1=18V) | ||
949 | * Z = BAND (0=LOW, 1=HIGH(22K)) | ||
950 | */ | ||
951 | if(d->msg_len >= 4 && d->msg[2] == 0x38) | ||
952 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2); | ||
953 | if(debug) | ||
954 | dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]); | ||
955 | } | ||
956 | |||
957 | /* Wait for LNB ready */ | ||
958 | ret = cx24116_wait_for_lnb(fe); | ||
959 | if(ret != 0) | ||
960 | return ret; | ||
961 | |||
962 | /* Wait for voltage/min repeat delay */ | ||
963 | msleep(100); | ||
964 | |||
965 | /* Command */ | ||
966 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
967 | if(ret != 0) | ||
968 | return ret; | ||
969 | /* | ||
970 | * Wait for send | ||
971 | * | ||
972 | * Eutelsat spec: | ||
973 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
974 | * 13.5ms per byte + | ||
975 | * >15ms delay + | ||
976 | * 12.5ms burst + | ||
977 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
978 | */ | ||
979 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) ); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /* Send DiSEqC burst */ | ||
985 | static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
986 | { | ||
987 | struct cx24116_state *state = fe->demodulator_priv; | ||
988 | int ret; | ||
989 | |||
990 | dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst); | ||
991 | |||
992 | /* DiSEqC burst */ | ||
993 | if (burst == SEC_MINI_A) | ||
994 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
995 | else if(burst == SEC_MINI_B) | ||
996 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; | ||
997 | else | ||
998 | return -EINVAL; | ||
999 | |||
1000 | /* DiSEqC toneburst */ | ||
1001 | if(toneburst != CX24116_DISEQC_MESGCACHE) | ||
1002 | /* Burst is cached */ | ||
1003 | return 0; | ||
1004 | |||
1005 | /* Burst is to be sent with cached message */ | ||
1006 | |||
1007 | /* Wait for LNB ready */ | ||
1008 | ret = cx24116_wait_for_lnb(fe); | ||
1009 | if(ret != 0) | ||
1010 | return ret; | ||
1011 | |||
1012 | /* Wait for voltage/min repeat delay */ | ||
1013 | msleep(100); | ||
1014 | |||
1015 | /* Command */ | ||
1016 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
1017 | if(ret != 0) | ||
1018 | return ret; | ||
1019 | |||
1020 | /* | ||
1021 | * Wait for send | ||
1022 | * | ||
1023 | * Eutelsat spec: | ||
1024 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
1025 | * 13.5ms per byte + | ||
1026 | * >15ms delay + | ||
1027 | * 12.5ms burst + | ||
1028 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
1029 | */ | ||
1030 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static void cx24116_release(struct dvb_frontend* fe) | ||
1036 | { | ||
1037 | struct cx24116_state* state = fe->demodulator_priv; | ||
1038 | dprintk("%s\n",__func__); | ||
1039 | kfree(state); | ||
1040 | } | ||
1041 | |||
1042 | static struct dvb_frontend_ops cx24116_ops; | ||
1043 | |||
1044 | struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
1045 | struct i2c_adapter* i2c) | ||
1046 | { | ||
1047 | struct cx24116_state* state = NULL; | ||
1048 | int ret; | ||
1049 | |||
1050 | dprintk("%s\n",__func__); | ||
1051 | |||
1052 | /* allocate memory for the internal state */ | ||
1053 | state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); | ||
1054 | if (state == NULL) { | ||
1055 | printk("Unable to kmalloc\n"); | ||
1056 | goto error1; | ||
1057 | } | ||
1058 | |||
1059 | /* setup the state */ | ||
1060 | memset(state, 0, sizeof(struct cx24116_state)); | ||
1061 | |||
1062 | state->config = config; | ||
1063 | state->i2c = i2c; | ||
1064 | |||
1065 | /* check if the demod is present */ | ||
1066 | ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); | ||
1067 | if (ret != 0x0501) { | ||
1068 | printk("Invalid probe, probably not a CX24116 device\n"); | ||
1069 | goto error2; | ||
1070 | } | ||
1071 | |||
1072 | /* create dvb_frontend */ | ||
1073 | memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops)); | ||
1074 | state->frontend.demodulator_priv = state; | ||
1075 | return &state->frontend; | ||
1076 | |||
1077 | error2: kfree(state); | ||
1078 | error1: return NULL; | ||
1079 | } | ||
1080 | /* | ||
1081 | * Initialise or wake up device | ||
1082 | * | ||
1083 | * Power config will reset and load initial firmware if required | ||
1084 | */ | ||
1085 | static int cx24116_initfe(struct dvb_frontend* fe) | ||
1086 | { | ||
1087 | struct cx24116_state* state = fe->demodulator_priv; | ||
1088 | struct cx24116_cmd cmd; | ||
1089 | int ret; | ||
1090 | |||
1091 | dprintk("%s()\n",__func__); | ||
1092 | |||
1093 | /* Power on */ | ||
1094 | cx24116_writereg(state, 0xe0, 0); | ||
1095 | cx24116_writereg(state, 0xe1, 0); | ||
1096 | cx24116_writereg(state, 0xea, 0); | ||
1097 | |||
1098 | /* Firmware CMD 36: Power config */ | ||
1099 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1100 | cmd.args[0x01] = 0; | ||
1101 | cmd.len= 0x02; | ||
1102 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1103 | if(ret != 0) | ||
1104 | return ret; | ||
1105 | |||
1106 | return cx24116_diseqc_init(fe); | ||
1107 | } | ||
1108 | |||
1109 | /* | ||
1110 | * Put device to sleep | ||
1111 | */ | ||
1112 | static int cx24116_sleep(struct dvb_frontend* fe) | ||
1113 | { | ||
1114 | struct cx24116_state* state = fe->demodulator_priv; | ||
1115 | struct cx24116_cmd cmd; | ||
1116 | int ret; | ||
1117 | |||
1118 | dprintk("%s()\n",__func__); | ||
1119 | |||
1120 | /* Firmware CMD 36: Power config */ | ||
1121 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1122 | cmd.args[0x01] = 1; | ||
1123 | cmd.len= 0x02; | ||
1124 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1125 | if(ret != 0) | ||
1126 | return ret; | ||
1127 | |||
1128 | /* Power off (Shutdown clocks) */ | ||
1129 | cx24116_writereg(state, 0xea, 0xff); | ||
1130 | cx24116_writereg(state, 0xe1, 1); | ||
1131 | cx24116_writereg(state, 0xe0, 1); | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1137 | { | ||
1138 | dprintk("%s(..)\n", __func__); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1143 | { | ||
1144 | dprintk("%s(..)\n", __func__); | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | /* dvb-core told us to tune, the tv property cache will be complete, | ||
1149 | * it's safe for is to pull values and use them for tuning purposes. | ||
1150 | */ | ||
1151 | static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
1152 | { | ||
1153 | struct cx24116_state *state = fe->demodulator_priv; | ||
1154 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1155 | struct cx24116_cmd cmd; | ||
1156 | fe_status_t tunerstat; | ||
1157 | int i, status, ret, retune; | ||
1158 | |||
1159 | dprintk("%s()\n",__func__); | ||
1160 | |||
1161 | switch(c->delivery_system) { | ||
1162 | case SYS_DVBS: | ||
1163 | dprintk("%s: DVB-S delivery system selected\n",__func__); | ||
1164 | |||
1165 | /* Only QPSK is supported for DVB-S */ | ||
1166 | if(c->modulation != QPSK) { | ||
1167 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1168 | __func__, c->modulation); | ||
1169 | return -EOPNOTSUPP; | ||
1170 | } | ||
1171 | |||
1172 | /* Pilot doesn't exist in DVB-S, turn bit off */ | ||
1173 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1174 | retune = 1; | ||
1175 | |||
1176 | /* DVB-S only supports 0.35 */ | ||
1177 | if(c->rolloff != ROLLOFF_35) { | ||
1178 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1179 | __func__, c->rolloff); | ||
1180 | return -EOPNOTSUPP; | ||
1181 | } | ||
1182 | state->dnxt.rolloff_val = CX24116_ROLLOFF_035; | ||
1183 | break; | ||
1184 | |||
1185 | case SYS_DVBS2: | ||
1186 | dprintk("%s: DVB-S2 delivery system selected\n",__func__); | ||
1187 | |||
1188 | /* | ||
1189 | * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, | ||
1190 | * but not hardware auto detection | ||
1191 | */ | ||
1192 | if(c->modulation != PSK_8 && c->modulation != QPSK) { | ||
1193 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1194 | __func__, c->modulation); | ||
1195 | return -EOPNOTSUPP; | ||
1196 | } | ||
1197 | |||
1198 | switch(c->pilot) { | ||
1199 | case PILOT_AUTO: /* Not supported but emulated */ | ||
1200 | retune = 2; /* Fall-through */ | ||
1201 | case PILOT_OFF: | ||
1202 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1203 | break; | ||
1204 | case PILOT_ON: | ||
1205 | state->dnxt.pilot_val = CX24116_PILOT_ON; | ||
1206 | break; | ||
1207 | default: | ||
1208 | dprintk("%s: unsupported pilot mode selected (%d)\n", | ||
1209 | __func__, c->pilot); | ||
1210 | return -EOPNOTSUPP; | ||
1211 | } | ||
1212 | |||
1213 | switch(c->rolloff) { | ||
1214 | case ROLLOFF_20: | ||
1215 | state->dnxt.rolloff_val= CX24116_ROLLOFF_020; | ||
1216 | break; | ||
1217 | case ROLLOFF_25: | ||
1218 | state->dnxt.rolloff_val= CX24116_ROLLOFF_025; | ||
1219 | break; | ||
1220 | case ROLLOFF_35: | ||
1221 | state->dnxt.rolloff_val= CX24116_ROLLOFF_035; | ||
1222 | break; | ||
1223 | case ROLLOFF_AUTO: /* Rolloff must be explicit */ | ||
1224 | default: | ||
1225 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1226 | __func__, c->rolloff); | ||
1227 | return -EOPNOTSUPP; | ||
1228 | } | ||
1229 | break; | ||
1230 | |||
1231 | default: | ||
1232 | dprintk("%s: unsupported delivery system selected (%d)\n", | ||
1233 | __func__, c->delivery_system); | ||
1234 | return -EOPNOTSUPP; | ||
1235 | } | ||
1236 | state->dnxt.modulation = c->modulation; | ||
1237 | state->dnxt.frequency = c->frequency; | ||
1238 | state->dnxt.pilot = c->pilot; | ||
1239 | state->dnxt.rolloff = c->rolloff; | ||
1240 | |||
1241 | if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) | ||
1242 | return ret; | ||
1243 | |||
1244 | /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ | ||
1245 | if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) | ||
1246 | return ret; | ||
1247 | |||
1248 | if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0) | ||
1249 | return ret; | ||
1250 | |||
1251 | /* discard the 'current' tuning parameters and prepare to tune */ | ||
1252 | cx24116_clone_params(fe); | ||
1253 | |||
1254 | dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); | ||
1255 | dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); | ||
1256 | dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, | ||
1257 | state->dcur.pilot, state->dcur.pilot_val); | ||
1258 | dprintk("%s: retune = %d\n", __func__, retune); | ||
1259 | dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, | ||
1260 | state->dcur.rolloff, state->dcur.rolloff_val); | ||
1261 | dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); | ||
1262 | dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, | ||
1263 | state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); | ||
1264 | dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, | ||
1265 | state->dcur.inversion, state->dcur.inversion_val); | ||
1266 | |||
1267 | /* This is also done in advise/acquire on HVR4000 but not on LITE */ | ||
1268 | if (state->config->set_ts_params) | ||
1269 | state->config->set_ts_params(fe, 0); | ||
1270 | |||
1271 | /* Set/Reset B/W */ | ||
1272 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1273 | cmd.args[0x01] = 0x01; | ||
1274 | cmd.len= 0x02; | ||
1275 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1276 | if (ret != 0) | ||
1277 | return ret; | ||
1278 | |||
1279 | /* Prepare a tune request */ | ||
1280 | cmd.args[0x00] = CMD_TUNEREQUEST; | ||
1281 | |||
1282 | /* Frequency */ | ||
1283 | cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; | ||
1284 | cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; | ||
1285 | cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); | ||
1286 | |||
1287 | /* Symbol Rate */ | ||
1288 | cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; | ||
1289 | cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); | ||
1290 | |||
1291 | /* Automatic Inversion */ | ||
1292 | cmd.args[0x06] = state->dcur.inversion_val; | ||
1293 | |||
1294 | /* Modulation / FEC / Pilot */ | ||
1295 | cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; | ||
1296 | |||
1297 | cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; | ||
1298 | cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; | ||
1299 | cmd.args[0x0a] = 0x00; | ||
1300 | cmd.args[0x0b] = 0x00; | ||
1301 | cmd.args[0x0c] = state->dcur.rolloff_val; | ||
1302 | cmd.args[0x0d] = state->dcur.fec_mask; | ||
1303 | |||
1304 | if (state->dcur.symbol_rate > 30000000) { | ||
1305 | cmd.args[0x0e] = 0x04; | ||
1306 | cmd.args[0x0f] = 0x00; | ||
1307 | cmd.args[0x10] = 0x01; | ||
1308 | cmd.args[0x11] = 0x77; | ||
1309 | cmd.args[0x12] = 0x36; | ||
1310 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); | ||
1311 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); | ||
1312 | } else { | ||
1313 | cmd.args[0x0e] = 0x06; | ||
1314 | cmd.args[0x0f] = 0x00; | ||
1315 | cmd.args[0x10] = 0x00; | ||
1316 | cmd.args[0x11] = 0xFA; | ||
1317 | cmd.args[0x12] = 0x24; | ||
1318 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
1319 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
1320 | } | ||
1321 | |||
1322 | cmd.len= 0x13; | ||
1323 | |||
1324 | /* We need to support pilot and non-pilot tuning in the | ||
1325 | * driver automatically. This is a workaround for because | ||
1326 | * the demod does not support autodetect. | ||
1327 | */ | ||
1328 | do { | ||
1329 | /* Reset status register */ | ||
1330 | status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK; | ||
1331 | cx24116_writereg(state, CX24116_REG_SSTATUS, status); | ||
1332 | |||
1333 | /* Tune */ | ||
1334 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1335 | if( ret != 0 ) | ||
1336 | break; | ||
1337 | |||
1338 | /* | ||
1339 | * Wait for up to 500 ms before retrying | ||
1340 | * | ||
1341 | * If we are able to tune then generally it occurs within 100ms. | ||
1342 | * If it takes longer, try a different toneburst setting. | ||
1343 | */ | ||
1344 | for(i = 0; i < 50 ; i++) { | ||
1345 | cx24116_read_status(fe, &tunerstat); | ||
1346 | status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); | ||
1347 | if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { | ||
1348 | dprintk("%s: Tuned\n",__func__); | ||
1349 | goto tuned; | ||
1350 | } | ||
1351 | msleep(10); | ||
1352 | } | ||
1353 | |||
1354 | dprintk("%s: Not tuned\n",__func__); | ||
1355 | |||
1356 | /* Toggle pilot bit when in auto-pilot */ | ||
1357 | if(state->dcur.pilot == PILOT_AUTO) | ||
1358 | cmd.args[0x07] ^= CX24116_PILOT_ON; | ||
1359 | } | ||
1360 | while(--retune); | ||
1361 | |||
1362 | tuned: /* Set/Reset B/W */ | ||
1363 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1364 | cmd.args[0x01] = 0x00; | ||
1365 | cmd.len= 0x02; | ||
1366 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1367 | if (ret != 0) | ||
1368 | return ret; | ||
1369 | |||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | static struct dvb_frontend_ops cx24116_ops = { | ||
1374 | |||
1375 | .info = { | ||
1376 | .name = "Conexant CX24116/CX24118", | ||
1377 | .type = FE_QPSK, | ||
1378 | .frequency_min = 950000, | ||
1379 | .frequency_max = 2150000, | ||
1380 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ | ||
1381 | .frequency_tolerance = 5000, | ||
1382 | .symbol_rate_min = 1000000, | ||
1383 | .symbol_rate_max = 45000000, | ||
1384 | .caps = FE_CAN_INVERSION_AUTO | | ||
1385 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1386 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
1387 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1388 | FE_CAN_QPSK | FE_CAN_RECOVER | ||
1389 | }, | ||
1390 | |||
1391 | .release = cx24116_release, | ||
1392 | |||
1393 | .init = cx24116_initfe, | ||
1394 | .sleep = cx24116_sleep, | ||
1395 | .read_status = cx24116_read_status, | ||
1396 | .read_ber = cx24116_read_ber, | ||
1397 | .read_signal_strength = cx24116_read_signal_strength, | ||
1398 | .read_snr = cx24116_read_snr, | ||
1399 | .read_ucblocks = cx24116_read_ucblocks, | ||
1400 | .set_tone = cx24116_set_tone, | ||
1401 | .set_voltage = cx24116_set_voltage, | ||
1402 | .diseqc_send_master_cmd = cx24116_send_diseqc_msg, | ||
1403 | .diseqc_send_burst = cx24116_diseqc_send_burst, | ||
1404 | |||
1405 | .set_property = cx24116_set_property, | ||
1406 | .get_property = cx24116_get_property, | ||
1407 | .set_frontend = cx24116_set_frontend, | ||
1408 | }; | ||
1409 | |||
1410 | module_param(debug, int, 0644); | ||
1411 | MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); | ||
1412 | |||
1413 | module_param(toneburst, int, 0644); | ||
1414 | MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); | ||
1415 | |||
1416 | module_param(esno_snr, int, 0644); | ||
1417 | MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); | ||
1418 | |||
1419 | MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); | ||
1420 | MODULE_AUTHOR("Steven Toth"); | ||
1421 | MODULE_LICENSE("GPL"); | ||
1422 | |||
1423 | EXPORT_SYMBOL(cx24116_attach); | ||
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h new file mode 100644 index 000000000000..8dbcec268394 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver | ||
3 | |||
4 | Copyright (C) 2006 Steven Toth <stoth@linuxtv.com> | ||
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 as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef CX24116_H | ||
22 | #define CX24116_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | struct cx24116_config | ||
27 | { | ||
28 | /* the demodulator's i2c address */ | ||
29 | u8 demod_address; | ||
30 | |||
31 | /* Need to set device param for start_dma */ | ||
32 | int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); | ||
33 | |||
34 | /* Need to reset device during firmware loading */ | ||
35 | int (*reset_device)(struct dvb_frontend* fe); | ||
36 | |||
37 | /* Need to set MPEG parameters */ | ||
38 | u8 mpg_clk_pos_pol:0x02; | ||
39 | }; | ||
40 | |||
41 | #if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE) | ||
42 | extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
43 | struct i2c_adapter* i2c); | ||
44 | #else | ||
45 | static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
46 | struct i2c_adapter* i2c) | ||
47 | { | ||
48 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
49 | return NULL; | ||
50 | } | ||
51 | #endif // CONFIG_DVB_CX24116 | ||
52 | |||
53 | #endif /* CX24116_H */ | ||
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index 3eedfdf505bc..21f2c5161af4 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h | |||
@@ -41,6 +41,7 @@ struct dib0070_config { | |||
41 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 41 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, |
42 | struct i2c_adapter *i2c, | 42 | struct i2c_adapter *i2c, |
43 | struct dib0070_config *cfg); | 43 | struct dib0070_config *cfg); |
44 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | ||
44 | #else | 45 | #else |
45 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 46 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, |
46 | struct i2c_adapter *i2c, | 47 | struct i2c_adapter *i2c, |
@@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | |||
49 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 50 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
50 | return NULL; | 51 | return NULL; |
51 | } | 52 | } |
53 | |||
54 | static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) | ||
55 | { | ||
56 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
57 | return -ENODEV; | ||
58 | } | ||
52 | #endif | 59 | #endif |
53 | 60 | ||
54 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); | 61 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); |
55 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | ||
56 | 62 | ||
57 | #endif | 63 | #endif |
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 5f1375e30dfc..0109720353bd 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c | |||
@@ -1284,7 +1284,10 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di | |||
1284 | } | 1284 | } |
1285 | EXPORT_SYMBOL(dib7000m_get_i2c_master); | 1285 | EXPORT_SYMBOL(dib7000m_get_i2c_master); |
1286 | 1286 | ||
1287 | int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]) | 1287 | #if 0 |
1288 | /* used with some prototype boards */ | ||
1289 | int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, | ||
1290 | u8 default_addr, struct dib7000m_config cfg[]) | ||
1288 | { | 1291 | { |
1289 | struct dib7000m_state st = { .i2c_adap = i2c }; | 1292 | struct dib7000m_state st = { .i2c_adap = i2c }; |
1290 | int k = 0; | 1293 | int k = 0; |
@@ -1329,6 +1332,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau | |||
1329 | return 0; | 1332 | return 0; |
1330 | } | 1333 | } |
1331 | EXPORT_SYMBOL(dib7000m_i2c_enumeration); | 1334 | EXPORT_SYMBOL(dib7000m_i2c_enumeration); |
1335 | #endif | ||
1332 | 1336 | ||
1333 | static struct dvb_frontend_ops dib7000m_ops; | 1337 | static struct dvb_frontend_ops dib7000m_ops; |
1334 | struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) | 1338 | struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) |
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1a0142e0d741..8217e5b38f47 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c | |||
@@ -1333,7 +1333,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, | |||
1333 | /* Ensure the output mode remains at the previous default if it's | 1333 | /* Ensure the output mode remains at the previous default if it's |
1334 | * not specifically set by the caller. | 1334 | * not specifically set by the caller. |
1335 | */ | 1335 | */ |
1336 | if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) | 1336 | if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && |
1337 | (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) | ||
1337 | st->cfg.output_mode = OUTMODE_MPEG2_FIFO; | 1338 | st->cfg.output_mode = OUTMODE_MPEG2_FIFO; |
1338 | 1339 | ||
1339 | demod = &st->demod; | 1340 | demod = &st->demod; |
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 07c4d12ed5b7..3e8126857127 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h | |||
@@ -41,6 +41,14 @@ struct dib7000p_config { | |||
41 | extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | 41 | extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, |
42 | u8 i2c_addr, | 42 | u8 i2c_addr, |
43 | struct dib7000p_config *cfg); | 43 | struct dib7000p_config *cfg); |
44 | extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, | ||
45 | enum dibx000_i2c_interface, | ||
46 | int); | ||
47 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, | ||
48 | int no_of_demods, u8 default_addr, | ||
49 | struct dib7000p_config cfg[]); | ||
50 | extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | ||
51 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); | ||
44 | #else | 52 | #else |
45 | static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | 53 | static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, |
46 | u8 i2c_addr, | 54 | u8 i2c_addr, |
@@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | |||
49 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 57 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
50 | return NULL; | 58 | return NULL; |
51 | } | 59 | } |
52 | #endif | ||
53 | 60 | ||
54 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); | 61 | static inline |
62 | struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, | ||
63 | enum dibx000_i2c_interface i, int x) | ||
64 | { | ||
65 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
66 | return NULL; | ||
67 | } | ||
68 | |||
69 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, | ||
70 | int no_of_demods, u8 default_addr, | ||
71 | struct dib7000p_config cfg[]) | ||
72 | { | ||
73 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
74 | return -ENODEV; | ||
75 | } | ||
76 | |||
77 | extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) | ||
78 | { | ||
79 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
80 | return -ENODEV; | ||
81 | } | ||
82 | |||
83 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) | ||
84 | { | ||
85 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
86 | return -ENODEV; | ||
87 | } | ||
88 | #endif | ||
55 | 89 | ||
56 | extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); | ||
57 | extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); | 90 | extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); |
58 | extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | ||
59 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); | ||
60 | 91 | ||
61 | #endif | 92 | #endif |
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 3cbed874a6f8..b9ca5c8d2dd9 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c | |||
@@ -38,35 +38,32 @@ static const char mod_name[] = "drx397xD"; | |||
38 | #define F_SET_0D0h 1 | 38 | #define F_SET_0D0h 1 |
39 | #define F_SET_0D4h 2 | 39 | #define F_SET_0D4h 2 |
40 | 40 | ||
41 | typedef enum fw_ix { | 41 | enum fw_ix { |
42 | #define _FW_ENTRY(a, b) b | 42 | #define _FW_ENTRY(a, b) b |
43 | #include "drx397xD_fw.h" | 43 | #include "drx397xD_fw.h" |
44 | } fw_ix_t; | 44 | }; |
45 | 45 | ||
46 | /* chip specifics */ | 46 | /* chip specifics */ |
47 | struct drx397xD_state { | 47 | struct drx397xD_state { |
48 | struct i2c_adapter *i2c; | 48 | struct i2c_adapter *i2c; |
49 | struct dvb_frontend frontend; | 49 | struct dvb_frontend frontend; |
50 | struct drx397xD_config config; | 50 | struct drx397xD_config config; |
51 | fw_ix_t chip_rev; | 51 | enum fw_ix chip_rev; |
52 | int flags; | 52 | int flags; |
53 | u32 bandwidth_parm; /* internal bandwidth conversions */ | 53 | u32 bandwidth_parm; /* internal bandwidth conversions */ |
54 | u32 f_osc; /* w90: actual osc frequency [Hz] */ | 54 | u32 f_osc; /* w90: actual osc frequency [Hz] */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /******************************************************************************* | 57 | /* Firmware */ |
58 | * Firmware | ||
59 | ******************************************************************************/ | ||
60 | |||
61 | static const char *blob_name[] = { | 58 | static const char *blob_name[] = { |
62 | #define _BLOB_ENTRY(a, b) a | 59 | #define _BLOB_ENTRY(a, b) a |
63 | #include "drx397xD_fw.h" | 60 | #include "drx397xD_fw.h" |
64 | }; | 61 | }; |
65 | 62 | ||
66 | typedef enum blob_ix { | 63 | enum blob_ix { |
67 | #define _BLOB_ENTRY(a, b) b | 64 | #define _BLOB_ENTRY(a, b) b |
68 | #include "drx397xD_fw.h" | 65 | #include "drx397xD_fw.h" |
69 | } blob_ix_t; | 66 | }; |
70 | 67 | ||
71 | static struct { | 68 | static struct { |
72 | const char *name; | 69 | const char *name; |
@@ -85,7 +82,7 @@ static struct { | |||
85 | }; | 82 | }; |
86 | 83 | ||
87 | /* use only with writer lock aquired */ | 84 | /* use only with writer lock aquired */ |
88 | static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) | 85 | static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix) |
89 | { | 86 | { |
90 | memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); | 87 | memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); |
91 | if (fw[ix].file) | 88 | if (fw[ix].file) |
@@ -94,9 +91,9 @@ static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) | |||
94 | 91 | ||
95 | static void drx_release_fw(struct drx397xD_state *s) | 92 | static void drx_release_fw(struct drx397xD_state *s) |
96 | { | 93 | { |
97 | fw_ix_t ix = s->chip_rev; | 94 | enum fw_ix ix = s->chip_rev; |
98 | 95 | ||
99 | pr_debug("%s\n", __FUNCTION__); | 96 | pr_debug("%s\n", __func__); |
100 | 97 | ||
101 | write_lock(&fw[ix].lock); | 98 | write_lock(&fw[ix].lock); |
102 | if (fw[ix].refcnt) { | 99 | if (fw[ix].refcnt) { |
@@ -107,13 +104,13 @@ static void drx_release_fw(struct drx397xD_state *s) | |||
107 | write_unlock(&fw[ix].lock); | 104 | write_unlock(&fw[ix].lock); |
108 | } | 105 | } |
109 | 106 | ||
110 | static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) | 107 | static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) |
111 | { | 108 | { |
112 | const u8 *data; | 109 | const u8 *data; |
113 | size_t size, len; | 110 | size_t size, len; |
114 | int i = 0, j, rc = -EINVAL; | 111 | int i = 0, j, rc = -EINVAL; |
115 | 112 | ||
116 | pr_debug("%s\n", __FUNCTION__); | 113 | pr_debug("%s\n", __func__); |
117 | 114 | ||
118 | if (ix < 0 || ix >= ARRAY_SIZE(fw)) | 115 | if (ix < 0 || ix >= ARRAY_SIZE(fw)) |
119 | return -EINVAL; | 116 | return -EINVAL; |
@@ -175,32 +172,34 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) | |||
175 | goto exit_corrupt; | 172 | goto exit_corrupt; |
176 | } | 173 | } |
177 | } while (i < size); | 174 | } while (i < size); |
178 | exit_corrupt: | 175 | |
176 | exit_corrupt: | ||
179 | printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); | 177 | printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); |
180 | exit_err: | 178 | exit_err: |
181 | _drx_release_fw(s, ix); | 179 | _drx_release_fw(s, ix); |
182 | fw[ix].refcnt--; | 180 | fw[ix].refcnt--; |
183 | exit_ok: | 181 | exit_ok: |
184 | fw[ix].refcnt++; | 182 | fw[ix].refcnt++; |
185 | write_unlock(&fw[ix].lock); | 183 | write_unlock(&fw[ix].lock); |
184 | |||
186 | return rc; | 185 | return rc; |
187 | } | 186 | } |
188 | 187 | ||
189 | /******************************************************************************* | 188 | /* i2c bus IO */ |
190 | * i2c bus IO | 189 | static int write_fw(struct drx397xD_state *s, enum blob_ix ix) |
191 | ******************************************************************************/ | ||
192 | |||
193 | static int write_fw(struct drx397xD_state *s, blob_ix_t ix) | ||
194 | { | 190 | { |
195 | struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; | ||
196 | const u8 *data; | 191 | const u8 *data; |
197 | int len, rc = 0, i = 0; | 192 | int len, rc = 0, i = 0; |
193 | struct i2c_msg msg = { | ||
194 | .addr = s->config.demod_address, | ||
195 | .flags = 0 | ||
196 | }; | ||
198 | 197 | ||
199 | if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { | 198 | if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { |
200 | pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); | 199 | pr_debug("%s drx_fw_ix_t out of range\n", __func__); |
201 | return -EINVAL; | 200 | return -EINVAL; |
202 | } | 201 | } |
203 | pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); | 202 | pr_debug("%s %s\n", __func__, blob_name[ix]); |
204 | 203 | ||
205 | read_lock(&fw[s->chip_rev].lock); | 204 | read_lock(&fw[s->chip_rev].lock); |
206 | data = fw[s->chip_rev].data[ix]; | 205 | data = fw[s->chip_rev].data[ix]; |
@@ -229,33 +228,33 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) | |||
229 | goto exit_rc; | 228 | goto exit_rc; |
230 | } | 229 | } |
231 | } | 230 | } |
232 | exit_rc: | 231 | exit_rc: |
233 | read_unlock(&fw[s->chip_rev].lock); | 232 | read_unlock(&fw[s->chip_rev].lock); |
233 | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | /* Function is not endian safe, use the RD16 wrapper below */ | 237 | /* Function is not endian safe, use the RD16 wrapper below */ |
238 | static int _read16(struct drx397xD_state *s, u32 i2c_adr) | 238 | static int _read16(struct drx397xD_state *s, __le32 i2c_adr) |
239 | { | 239 | { |
240 | int rc; | 240 | int rc; |
241 | u8 a[4]; | 241 | u8 a[4]; |
242 | u16 v; | 242 | __le16 v; |
243 | struct i2c_msg msg[2] = { | 243 | struct i2c_msg msg[2] = { |
244 | { | 244 | { |
245 | .addr = s->config.demod_address, | 245 | .addr = s->config.demod_address, |
246 | .flags = 0, | 246 | .flags = 0, |
247 | .buf = a, | 247 | .buf = a, |
248 | .len = sizeof(a) | 248 | .len = sizeof(a) |
249 | } | 249 | }, { |
250 | , { | 250 | .addr = s->config.demod_address, |
251 | .addr = s->config.demod_address, | 251 | .flags = I2C_M_RD, |
252 | .flags = I2C_M_RD, | 252 | .buf = (u8 *)&v, |
253 | .buf = (u8 *) & v, | 253 | .len = sizeof(v) |
254 | .len = sizeof(v) | 254 | } |
255 | } | ||
256 | }; | 255 | }; |
257 | 256 | ||
258 | *(u32 *) a = i2c_adr; | 257 | *(__le32 *) a = i2c_adr; |
259 | 258 | ||
260 | rc = i2c_transfer(s->i2c, msg, 2); | 259 | rc = i2c_transfer(s->i2c, msg, 2); |
261 | if (rc != 2) | 260 | if (rc != 2) |
@@ -265,7 +264,7 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr) | |||
265 | } | 264 | } |
266 | 265 | ||
267 | /* Function is not endian safe, use the WR16.. wrappers below */ | 266 | /* Function is not endian safe, use the WR16.. wrappers below */ |
268 | static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) | 267 | static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val) |
269 | { | 268 | { |
270 | u8 a[6]; | 269 | u8 a[6]; |
271 | int rc; | 270 | int rc; |
@@ -276,28 +275,28 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) | |||
276 | .len = sizeof(a) | 275 | .len = sizeof(a) |
277 | }; | 276 | }; |
278 | 277 | ||
279 | *(u32 *) a = i2c_adr; | 278 | *(__le32 *)a = i2c_adr; |
280 | *(u16 *) & a[4] = val; | 279 | *(__le16 *)&a[4] = val; |
281 | 280 | ||
282 | rc = i2c_transfer(s->i2c, &msg, 1); | 281 | rc = i2c_transfer(s->i2c, &msg, 1); |
283 | if (rc != 1) | 282 | if (rc != 1) |
284 | return -EIO; | 283 | return -EIO; |
284 | |||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | #define WR16(ss,adr, val) \ | 288 | #define WR16(ss, adr, val) \ |
289 | _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) | 289 | _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) |
290 | #define WR16_E0(ss,adr, val) \ | 290 | #define WR16_E0(ss, adr, val) \ |
291 | _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) | 291 | _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) |
292 | #define RD16(ss,adr) \ | 292 | #define RD16(ss, adr) \ |
293 | _read16(ss, I2C_ADR_C0(adr)) | 293 | _read16(ss, I2C_ADR_C0(adr)) |
294 | 294 | ||
295 | #define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc | 295 | #define EXIT_RC(cmd) \ |
296 | 296 | if ((rc = (cmd)) < 0) \ | |
297 | /******************************************************************************* | 297 | goto exit_rc |
298 | * Tuner callback | ||
299 | ******************************************************************************/ | ||
300 | 298 | ||
299 | /* Tuner callback */ | ||
301 | static int PLL_Set(struct drx397xD_state *s, | 300 | static int PLL_Set(struct drx397xD_state *s, |
302 | struct dvb_frontend_parameters *fep, int *df_tuner) | 301 | struct dvb_frontend_parameters *fep, int *df_tuner) |
303 | { | 302 | { |
@@ -305,7 +304,7 @@ static int PLL_Set(struct drx397xD_state *s, | |||
305 | u32 f_tuner, f = fep->frequency; | 304 | u32 f_tuner, f = fep->frequency; |
306 | int rc; | 305 | int rc; |
307 | 306 | ||
308 | pr_debug("%s\n", __FUNCTION__); | 307 | pr_debug("%s\n", __func__); |
309 | 308 | ||
310 | if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || | 309 | if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || |
311 | (f < s->frontend.ops.tuner_ops.info.frequency_min)) | 310 | (f < s->frontend.ops.tuner_ops.info.frequency_min)) |
@@ -325,28 +324,26 @@ static int PLL_Set(struct drx397xD_state *s, | |||
325 | return rc; | 324 | return rc; |
326 | 325 | ||
327 | *df_tuner = f_tuner - f; | 326 | *df_tuner = f_tuner - f; |
328 | pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, | 327 | pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, |
329 | f_tuner); | 328 | f_tuner); |
330 | 329 | ||
331 | return 0; | 330 | return 0; |
332 | } | 331 | } |
333 | 332 | ||
334 | /******************************************************************************* | 333 | /* Demodulator helper functions */ |
335 | * Demodulator helper functions | ||
336 | ******************************************************************************/ | ||
337 | |||
338 | static int SC_WaitForReady(struct drx397xD_state *s) | 334 | static int SC_WaitForReady(struct drx397xD_state *s) |
339 | { | 335 | { |
340 | int cnt = 1000; | 336 | int cnt = 1000; |
341 | int rc; | 337 | int rc; |
342 | 338 | ||
343 | pr_debug("%s\n", __FUNCTION__); | 339 | pr_debug("%s\n", __func__); |
344 | 340 | ||
345 | while (cnt--) { | 341 | while (cnt--) { |
346 | rc = RD16(s, 0x820043); | 342 | rc = RD16(s, 0x820043); |
347 | if (rc == 0) | 343 | if (rc == 0) |
348 | return 0; | 344 | return 0; |
349 | } | 345 | } |
346 | |||
350 | return -1; | 347 | return -1; |
351 | } | 348 | } |
352 | 349 | ||
@@ -354,13 +351,14 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd) | |||
354 | { | 351 | { |
355 | int rc; | 352 | int rc; |
356 | 353 | ||
357 | pr_debug("%s\n", __FUNCTION__); | 354 | pr_debug("%s\n", __func__); |
358 | 355 | ||
359 | WR16(s, 0x820043, cmd); | 356 | WR16(s, 0x820043, cmd); |
360 | SC_WaitForReady(s); | 357 | SC_WaitForReady(s); |
361 | rc = RD16(s, 0x820042); | 358 | rc = RD16(s, 0x820042); |
362 | if ((rc & 0xffff) == 0xffff) | 359 | if ((rc & 0xffff) == 0xffff) |
363 | return -1; | 360 | return -1; |
361 | |||
364 | return 0; | 362 | return 0; |
365 | } | 363 | } |
366 | 364 | ||
@@ -368,7 +366,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) | |||
368 | { | 366 | { |
369 | int rc, cnt = 1000; | 367 | int rc, cnt = 1000; |
370 | 368 | ||
371 | pr_debug("%s\n", __FUNCTION__); | 369 | pr_debug("%s\n", __func__); |
372 | 370 | ||
373 | rc = WR16(s, 0x420032, cmd); | 371 | rc = WR16(s, 0x420032, cmd); |
374 | if (rc < 0) | 372 | if (rc < 0) |
@@ -383,22 +381,24 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) | |||
383 | if (rc < 0) | 381 | if (rc < 0) |
384 | return rc; | 382 | return rc; |
385 | } while (--cnt); | 383 | } while (--cnt); |
384 | |||
386 | return rc; | 385 | return rc; |
387 | } | 386 | } |
388 | 387 | ||
389 | static int HI_CfgCommand(struct drx397xD_state *s) | 388 | static int HI_CfgCommand(struct drx397xD_state *s) |
390 | { | 389 | { |
391 | 390 | ||
392 | pr_debug("%s\n", __FUNCTION__); | 391 | pr_debug("%s\n", __func__); |
393 | 392 | ||
394 | WR16(s, 0x420033, 0x3973); | 393 | WR16(s, 0x420033, 0x3973); |
395 | WR16(s, 0x420034, s->config.w50); // code 4, log 4 | 394 | WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */ |
396 | WR16(s, 0x420035, s->config.w52); // code 15, log 9 | 395 | WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */ |
397 | WR16(s, 0x420036, s->config.demod_address << 1); | 396 | WR16(s, 0x420036, s->config.demod_address << 1); |
398 | WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1 | 397 | WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */ |
399 | // WR16(s, 0x420033, 0x3973); | 398 | /* WR16(s, 0x420033, 0x3973); */ |
400 | if ((s->config.w56 & 8) == 0) | 399 | if ((s->config.w56 & 8) == 0) |
401 | return HI_Command(s, 3); | 400 | return HI_Command(s, 3); |
401 | |||
402 | return WR16(s, 0x420032, 0x3); | 402 | return WR16(s, 0x420032, 0x3); |
403 | } | 403 | } |
404 | 404 | ||
@@ -419,7 +419,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) | |||
419 | u16 w0C = agc->w0C; | 419 | u16 w0C = agc->w0C; |
420 | int quot, rem, i, rc = -EINVAL; | 420 | int quot, rem, i, rc = -EINVAL; |
421 | 421 | ||
422 | pr_debug("%s\n", __FUNCTION__); | 422 | pr_debug("%s\n", __func__); |
423 | 423 | ||
424 | if (agc->w04 > 0x3ff) | 424 | if (agc->w04 > 0x3ff) |
425 | goto exit_rc; | 425 | goto exit_rc; |
@@ -468,7 +468,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) | |||
468 | i = slowIncrDecLUT_15272[rem / 28]; | 468 | i = slowIncrDecLUT_15272[rem / 28]; |
469 | EXIT_RC(WR16(s, 0x0c2002b, i)); | 469 | EXIT_RC(WR16(s, 0x0c2002b, i)); |
470 | rc = WR16(s, 0x0c2002c, i); | 470 | rc = WR16(s, 0x0c2002c, i); |
471 | exit_rc: | 471 | exit_rc: |
472 | return rc; | 472 | return rc; |
473 | } | 473 | } |
474 | 474 | ||
@@ -478,7 +478,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
478 | u16 w06 = agc->w06; | 478 | u16 w06 = agc->w06; |
479 | int rc = -1; | 479 | int rc = -1; |
480 | 480 | ||
481 | pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); | 481 | pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); |
482 | 482 | ||
483 | if (w04 > 0x3ff) | 483 | if (w04 > 0x3ff) |
484 | goto exit_rc; | 484 | goto exit_rc; |
@@ -498,7 +498,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
498 | rc &= ~2; | 498 | rc &= ~2; |
499 | break; | 499 | break; |
500 | case 0: | 500 | case 0: |
501 | // loc_8000659 | 501 | /* loc_8000659 */ |
502 | s->config.w9C &= ~2; | 502 | s->config.w9C &= ~2; |
503 | EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); | 503 | EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); |
504 | EXIT_RC(RD16(s, 0x0c20010)); | 504 | EXIT_RC(RD16(s, 0x0c20010)); |
@@ -522,7 +522,8 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
522 | rc |= 2; | 522 | rc |= 2; |
523 | } | 523 | } |
524 | rc = WR16(s, 0x0c20013, rc); | 524 | rc = WR16(s, 0x0c20013, rc); |
525 | exit_rc: | 525 | |
526 | exit_rc: | ||
526 | return rc; | 527 | return rc; |
527 | } | 528 | } |
528 | 529 | ||
@@ -554,7 +555,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) | |||
554 | int lockstat; | 555 | int lockstat; |
555 | u32 clk, clk_limit; | 556 | u32 clk, clk_limit; |
556 | 557 | ||
557 | pr_debug("%s\n", __FUNCTION__); | 558 | pr_debug("%s\n", __func__); |
558 | 559 | ||
559 | if (s->config.d5C == 0) { | 560 | if (s->config.d5C == 0) { |
560 | EXIT_RC(WR16(s, 0x08200e8, 0x010)); | 561 | EXIT_RC(WR16(s, 0x08200e8, 0x010)); |
@@ -598,11 +599,12 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) | |||
598 | 599 | ||
599 | if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { | 600 | if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { |
600 | s->f_osc = clk; | 601 | s->f_osc = clk; |
601 | pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, | 602 | pr_debug("%s: osc %d %d [Hz]\n", __func__, |
602 | s->config.f_osc * 1000, clk - s->config.f_osc * 1000); | 603 | s->config.f_osc * 1000, clk - s->config.f_osc * 1000); |
603 | } | 604 | } |
604 | rc = WR16(s, 0x08200e8, 0); | 605 | rc = WR16(s, 0x08200e8, 0); |
605 | exit_rc: | 606 | |
607 | exit_rc: | ||
606 | return rc; | 608 | return rc; |
607 | } | 609 | } |
608 | 610 | ||
@@ -610,7 +612,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) | |||
610 | { | 612 | { |
611 | int rc, si, bp; | 613 | int rc, si, bp; |
612 | 614 | ||
613 | pr_debug("%s\n", __FUNCTION__); | 615 | pr_debug("%s\n", __func__); |
614 | 616 | ||
615 | si = s->config.wA0; | 617 | si = s->config.wA0; |
616 | if (s->config.w98 == 0) { | 618 | if (s->config.w98 == 0) { |
@@ -620,17 +622,17 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) | |||
620 | si &= ~1; | 622 | si &= ~1; |
621 | bp = 0x200; | 623 | bp = 0x200; |
622 | } | 624 | } |
623 | if (s->config.w9A == 0) { | 625 | if (s->config.w9A == 0) |
624 | si |= 0x80; | 626 | si |= 0x80; |
625 | } else { | 627 | else |
626 | si &= ~0x80; | 628 | si &= ~0x80; |
627 | } | ||
628 | 629 | ||
629 | EXIT_RC(WR16(s, 0x2150045, 0)); | 630 | EXIT_RC(WR16(s, 0x2150045, 0)); |
630 | EXIT_RC(WR16(s, 0x2150010, si)); | 631 | EXIT_RC(WR16(s, 0x2150010, si)); |
631 | EXIT_RC(WR16(s, 0x2150011, bp)); | 632 | EXIT_RC(WR16(s, 0x2150011, bp)); |
632 | rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); | 633 | rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); |
633 | exit_rc: | 634 | |
635 | exit_rc: | ||
634 | return rc; | 636 | return rc; |
635 | } | 637 | } |
636 | 638 | ||
@@ -646,7 +648,7 @@ static int drx_tune(struct drx397xD_state *s, | |||
646 | 648 | ||
647 | int rc, df_tuner; | 649 | int rc, df_tuner; |
648 | int a, b, c, d; | 650 | int a, b, c, d; |
649 | pr_debug("%s %d\n", __FUNCTION__, s->config.d60); | 651 | pr_debug("%s %d\n", __func__, s->config.d60); |
650 | 652 | ||
651 | if (s->config.d60 != 2) | 653 | if (s->config.d60 != 2) |
652 | goto set_tuner; | 654 | goto set_tuner; |
@@ -658,7 +660,7 @@ static int drx_tune(struct drx397xD_state *s, | |||
658 | rc = ConfigureMPEGOutput(s, 0); | 660 | rc = ConfigureMPEGOutput(s, 0); |
659 | if (rc < 0) | 661 | if (rc < 0) |
660 | goto set_tuner; | 662 | goto set_tuner; |
661 | set_tuner: | 663 | set_tuner: |
662 | 664 | ||
663 | rc = PLL_Set(s, fep, &df_tuner); | 665 | rc = PLL_Set(s, fep, &df_tuner); |
664 | if (rc < 0) { | 666 | if (rc < 0) { |
@@ -835,16 +837,16 @@ static int drx_tune(struct drx397xD_state *s, | |||
835 | rc = WR16(s, 0x2010012, 0); | 837 | rc = WR16(s, 0x2010012, 0); |
836 | if (rc < 0) | 838 | if (rc < 0) |
837 | goto exit_rc; | 839 | goto exit_rc; |
838 | // QPSK QAM16 QAM64 | 840 | /* QPSK QAM16 QAM64 */ |
839 | ebx = 0x19f; // 62 | 841 | ebx = 0x19f; /* 62 */ |
840 | ebp = 0x1fb; // 15 | 842 | ebp = 0x1fb; /* 15 */ |
841 | v20 = 0x16a; // 62 | 843 | v20 = 0x16a; /* 62 */ |
842 | v1E = 0x195; // 62 | 844 | v1E = 0x195; /* 62 */ |
843 | v16 = 0x1bb; // 15 | 845 | v16 = 0x1bb; /* 15 */ |
844 | v14 = 0x1ef; // 15 | 846 | v14 = 0x1ef; /* 15 */ |
845 | v12 = 5; // 16 | 847 | v12 = 5; /* 16 */ |
846 | v10 = 5; // 16 | 848 | v10 = 5; /* 16 */ |
847 | v0E = 5; // 16 | 849 | v0E = 5; /* 16 */ |
848 | } | 850 | } |
849 | 851 | ||
850 | switch (fep->u.ofdm.constellation) { | 852 | switch (fep->u.ofdm.constellation) { |
@@ -997,17 +999,17 @@ static int drx_tune(struct drx397xD_state *s, | |||
997 | case BANDWIDTH_8_MHZ: /* 0 */ | 999 | case BANDWIDTH_8_MHZ: /* 0 */ |
998 | case BANDWIDTH_AUTO: | 1000 | case BANDWIDTH_AUTO: |
999 | rc = WR16(s, 0x0c2003f, 0x32); | 1001 | rc = WR16(s, 0x0c2003f, 0x32); |
1000 | s->bandwidth_parm = ebx = 0x8b8249; // 9142857 | 1002 | s->bandwidth_parm = ebx = 0x8b8249; |
1001 | edx = 0; | 1003 | edx = 0; |
1002 | break; | 1004 | break; |
1003 | case BANDWIDTH_7_MHZ: | 1005 | case BANDWIDTH_7_MHZ: |
1004 | rc = WR16(s, 0x0c2003f, 0x3b); | 1006 | rc = WR16(s, 0x0c2003f, 0x3b); |
1005 | s->bandwidth_parm = ebx = 0x7a1200; // 8000000 | 1007 | s->bandwidth_parm = ebx = 0x7a1200; |
1006 | edx = 0x4807; | 1008 | edx = 0x4807; |
1007 | break; | 1009 | break; |
1008 | case BANDWIDTH_6_MHZ: | 1010 | case BANDWIDTH_6_MHZ: |
1009 | rc = WR16(s, 0x0c2003f, 0x47); | 1011 | rc = WR16(s, 0x0c2003f, 0x47); |
1010 | s->bandwidth_parm = ebx = 0x68a1b6; // 6857142 | 1012 | s->bandwidth_parm = ebx = 0x68a1b6; |
1011 | edx = 0x0f07; | 1013 | edx = 0x0f07; |
1012 | break; | 1014 | break; |
1013 | }; | 1015 | }; |
@@ -1060,8 +1062,6 @@ static int drx_tune(struct drx397xD_state *s, | |||
1060 | WR16(s, 0x0820040, 1); | 1062 | WR16(s, 0x0820040, 1); |
1061 | SC_SendCommand(s, 1); | 1063 | SC_SendCommand(s, 1); |
1062 | 1064 | ||
1063 | // rc = WR16(s, 0x2150000, 1); | ||
1064 | // if (rc < 0) goto exit_rc; | ||
1065 | 1065 | ||
1066 | rc = WR16(s, 0x2150000, 2); | 1066 | rc = WR16(s, 0x2150000, 2); |
1067 | rc = WR16(s, 0x2150016, a); | 1067 | rc = WR16(s, 0x2150016, a); |
@@ -1069,7 +1069,8 @@ static int drx_tune(struct drx397xD_state *s, | |||
1069 | rc = WR16(s, 0x2150036, 0); | 1069 | rc = WR16(s, 0x2150036, 0); |
1070 | rc = WR16(s, 0x2150000, 1); | 1070 | rc = WR16(s, 0x2150000, 1); |
1071 | s->config.d60 = 2; | 1071 | s->config.d60 = 2; |
1072 | exit_rc: | 1072 | |
1073 | exit_rc: | ||
1073 | return rc; | 1074 | return rc; |
1074 | } | 1075 | } |
1075 | 1076 | ||
@@ -1082,7 +1083,7 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1082 | struct drx397xD_state *s = fe->demodulator_priv; | 1083 | struct drx397xD_state *s = fe->demodulator_priv; |
1083 | int rc; | 1084 | int rc; |
1084 | 1085 | ||
1085 | pr_debug("%s\n", __FUNCTION__); | 1086 | pr_debug("%s\n", __func__); |
1086 | 1087 | ||
1087 | s->config.rfagc.d00 = 2; /* 0x7c */ | 1088 | s->config.rfagc.d00 = 2; /* 0x7c */ |
1088 | s->config.rfagc.w04 = 0; | 1089 | s->config.rfagc.w04 = 0; |
@@ -1102,18 +1103,18 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1102 | 1103 | ||
1103 | /* HI_CfgCommand */ | 1104 | /* HI_CfgCommand */ |
1104 | s->config.w50 = 4; | 1105 | s->config.w50 = 4; |
1105 | s->config.w52 = 9; // 0xf; | 1106 | s->config.w52 = 9; |
1106 | 1107 | ||
1107 | s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ | 1108 | s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ |
1108 | s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ | 1109 | s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ |
1109 | s->config.w92 = 12000; // 20000; | 1110 | s->config.w92 = 12000; |
1110 | 1111 | ||
1111 | s->config.w9C = 0x000e; | 1112 | s->config.w9C = 0x000e; |
1112 | s->config.w9E = 0x0000; | 1113 | s->config.w9E = 0x0000; |
1113 | 1114 | ||
1114 | /* ConfigureMPEGOutput params */ | 1115 | /* ConfigureMPEGOutput params */ |
1115 | s->config.wA0 = 4; | 1116 | s->config.wA0 = 4; |
1116 | s->config.w98 = 1; // 0; | 1117 | s->config.w98 = 1; |
1117 | s->config.w9A = 1; | 1118 | s->config.w9A = 1; |
1118 | 1119 | ||
1119 | /* get chip revision */ | 1120 | /* get chip revision */ |
@@ -1248,7 +1249,7 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1248 | rc = WR16(s, 0x0c20012, 1); | 1249 | rc = WR16(s, 0x0c20012, 1); |
1249 | } | 1250 | } |
1250 | 1251 | ||
1251 | write_DRXD_InitFE_1: | 1252 | write_DRXD_InitFE_1: |
1252 | 1253 | ||
1253 | rc = write_fw(s, DRXD_InitFE_1); | 1254 | rc = write_fw(s, DRXD_InitFE_1); |
1254 | if (rc < 0) | 1255 | if (rc < 0) |
@@ -1311,7 +1312,8 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1311 | s->config.d5C = 0; | 1312 | s->config.d5C = 0; |
1312 | s->config.d60 = 1; | 1313 | s->config.d60 = 1; |
1313 | s->config.d48 = 1; | 1314 | s->config.d48 = 1; |
1314 | error: | 1315 | |
1316 | error: | ||
1315 | return rc; | 1317 | return rc; |
1316 | } | 1318 | } |
1317 | 1319 | ||
@@ -1326,7 +1328,8 @@ static int drx397x_set_frontend(struct dvb_frontend *fe, | |||
1326 | { | 1328 | { |
1327 | struct drx397xD_state *s = fe->demodulator_priv; | 1329 | struct drx397xD_state *s = fe->demodulator_priv; |
1328 | 1330 | ||
1329 | s->config.s20d24 = 1; // 0; | 1331 | s->config.s20d24 = 1; |
1332 | |||
1330 | return drx_tune(s, params); | 1333 | return drx_tune(s, params); |
1331 | } | 1334 | } |
1332 | 1335 | ||
@@ -1337,18 +1340,16 @@ static int drx397x_get_tune_settings(struct dvb_frontend *fe, | |||
1337 | fe_tune_settings->min_delay_ms = 10000; | 1340 | fe_tune_settings->min_delay_ms = 10000; |
1338 | fe_tune_settings->step_size = 0; | 1341 | fe_tune_settings->step_size = 0; |
1339 | fe_tune_settings->max_drift = 0; | 1342 | fe_tune_settings->max_drift = 0; |
1343 | |||
1340 | return 0; | 1344 | return 0; |
1341 | } | 1345 | } |
1342 | 1346 | ||
1343 | static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | 1347 | static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status) |
1344 | { | 1348 | { |
1345 | struct drx397xD_state *s = fe->demodulator_priv; | 1349 | struct drx397xD_state *s = fe->demodulator_priv; |
1346 | int lockstat; | 1350 | int lockstat; |
1347 | 1351 | ||
1348 | GetLockStatus(s, &lockstat); | 1352 | GetLockStatus(s, &lockstat); |
1349 | /* TODO */ | ||
1350 | // if (lockstat & 1) | ||
1351 | // CorrectSysClockDeviation(s); | ||
1352 | 1353 | ||
1353 | *status = 0; | 1354 | *status = 0; |
1354 | if (lockstat & 2) { | 1355 | if (lockstat & 2) { |
@@ -1356,9 +1357,8 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | |||
1356 | ConfigureMPEGOutput(s, 1); | 1357 | ConfigureMPEGOutput(s, 1); |
1357 | *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; | 1358 | *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; |
1358 | } | 1359 | } |
1359 | if (lockstat & 4) { | 1360 | if (lockstat & 4) |
1360 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; | 1361 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; |
1361 | } | ||
1362 | 1362 | ||
1363 | return 0; | 1363 | return 0; |
1364 | } | 1364 | } |
@@ -1366,16 +1366,18 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | |||
1366 | static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) | 1366 | static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) |
1367 | { | 1367 | { |
1368 | *ber = 0; | 1368 | *ber = 0; |
1369 | |||
1369 | return 0; | 1370 | return 0; |
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr) | 1373 | static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr) |
1373 | { | 1374 | { |
1374 | *snr = 0; | 1375 | *snr = 0; |
1376 | |||
1375 | return 0; | 1377 | return 0; |
1376 | } | 1378 | } |
1377 | 1379 | ||
1378 | static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | 1380 | static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
1379 | { | 1381 | { |
1380 | struct drx397xD_state *s = fe->demodulator_priv; | 1382 | struct drx397xD_state *s = fe->demodulator_priv; |
1381 | int rc; | 1383 | int rc; |
@@ -1401,6 +1403,7 @@ static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | |||
1401 | * The following does the same but with less rounding errors: | 1403 | * The following does the same but with less rounding errors: |
1402 | */ | 1404 | */ |
1403 | *strength = ~(7720 + (rc * 30744 >> 10)); | 1405 | *strength = ~(7720 + (rc * 30744 >> 10)); |
1406 | |||
1404 | return 0; | 1407 | return 0; |
1405 | } | 1408 | } |
1406 | 1409 | ||
@@ -1408,6 +1411,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe, | |||
1408 | unsigned int *ucblocks) | 1411 | unsigned int *ucblocks) |
1409 | { | 1412 | { |
1410 | *ucblocks = 0; | 1413 | *ucblocks = 0; |
1414 | |||
1411 | return 0; | 1415 | return 0; |
1412 | } | 1416 | } |
1413 | 1417 | ||
@@ -1436,22 +1440,22 @@ static struct dvb_frontend_ops drx397x_ops = { | |||
1436 | .frequency_max = 855250000, | 1440 | .frequency_max = 855250000, |
1437 | .frequency_stepsize = 166667, | 1441 | .frequency_stepsize = 166667, |
1438 | .frequency_tolerance = 0, | 1442 | .frequency_tolerance = 0, |
1439 | .caps = /* 0x0C01B2EAE */ | 1443 | .caps = /* 0x0C01B2EAE */ |
1440 | FE_CAN_FEC_1_2 | // = 0x2, | 1444 | FE_CAN_FEC_1_2 | /* = 0x2, */ |
1441 | FE_CAN_FEC_2_3 | // = 0x4, | 1445 | FE_CAN_FEC_2_3 | /* = 0x4, */ |
1442 | FE_CAN_FEC_3_4 | // = 0x8, | 1446 | FE_CAN_FEC_3_4 | /* = 0x8, */ |
1443 | FE_CAN_FEC_5_6 | // = 0x20, | 1447 | FE_CAN_FEC_5_6 | /* = 0x20, */ |
1444 | FE_CAN_FEC_7_8 | // = 0x80, | 1448 | FE_CAN_FEC_7_8 | /* = 0x80, */ |
1445 | FE_CAN_FEC_AUTO | // = 0x200, | 1449 | FE_CAN_FEC_AUTO | /* = 0x200, */ |
1446 | FE_CAN_QPSK | // = 0x400, | 1450 | FE_CAN_QPSK | /* = 0x400, */ |
1447 | FE_CAN_QAM_16 | // = 0x800, | 1451 | FE_CAN_QAM_16 | /* = 0x800, */ |
1448 | FE_CAN_QAM_64 | // = 0x2000, | 1452 | FE_CAN_QAM_64 | /* = 0x2000, */ |
1449 | FE_CAN_QAM_AUTO | // = 0x10000, | 1453 | FE_CAN_QAM_AUTO | /* = 0x10000, */ |
1450 | FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000, | 1454 | FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ |
1451 | FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000, | 1455 | FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ |
1452 | FE_CAN_HIERARCHY_AUTO | // = 0x100000, | 1456 | FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ |
1453 | FE_CAN_RECOVER | // = 0x40000000, | 1457 | FE_CAN_RECOVER | /* = 0x40000000, */ |
1454 | FE_CAN_MUTE_TS // = 0x80000000 | 1458 | FE_CAN_MUTE_TS /* = 0x80000000 */ |
1455 | }, | 1459 | }, |
1456 | 1460 | ||
1457 | .release = drx397x_release, | 1461 | .release = drx397x_release, |
@@ -1472,33 +1476,35 @@ static struct dvb_frontend_ops drx397x_ops = { | |||
1472 | struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, | 1476 | struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, |
1473 | struct i2c_adapter *i2c) | 1477 | struct i2c_adapter *i2c) |
1474 | { | 1478 | { |
1475 | struct drx397xD_state *s = NULL; | 1479 | struct drx397xD_state *state; |
1476 | 1480 | ||
1477 | /* allocate memory for the internal state */ | 1481 | /* allocate memory for the internal state */ |
1478 | s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); | 1482 | state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); |
1479 | if (s == NULL) | 1483 | if (!state) |
1480 | goto error; | 1484 | goto error; |
1481 | 1485 | ||
1482 | /* setup the state */ | 1486 | /* setup the state */ |
1483 | s->i2c = i2c; | 1487 | state->i2c = i2c; |
1484 | memcpy(&s->config, config, sizeof(struct drx397xD_config)); | 1488 | memcpy(&state->config, config, sizeof(struct drx397xD_config)); |
1485 | 1489 | ||
1486 | /* check if the demod is there */ | 1490 | /* check if the demod is there */ |
1487 | if (RD16(s, 0x2410019) < 0) | 1491 | if (RD16(state, 0x2410019) < 0) |
1488 | goto error; | 1492 | goto error; |
1489 | 1493 | ||
1490 | /* create dvb_frontend */ | 1494 | /* create dvb_frontend */ |
1491 | memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); | 1495 | memcpy(&state->frontend.ops, &drx397x_ops, |
1492 | s->frontend.demodulator_priv = s; | 1496 | sizeof(struct dvb_frontend_ops)); |
1497 | state->frontend.demodulator_priv = state; | ||
1498 | |||
1499 | return &state->frontend; | ||
1500 | error: | ||
1501 | kfree(state); | ||
1493 | 1502 | ||
1494 | return &s->frontend; | ||
1495 | error: | ||
1496 | kfree(s); | ||
1497 | return NULL; | 1503 | return NULL; |
1498 | } | 1504 | } |
1505 | EXPORT_SYMBOL(drx397xD_attach); | ||
1499 | 1506 | ||
1500 | MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); | 1507 | MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); |
1501 | MODULE_AUTHOR("Henk Vergonet"); | 1508 | MODULE_AUTHOR("Henk Vergonet"); |
1502 | MODULE_LICENSE("GPL"); | 1509 | MODULE_LICENSE("GPL"); |
1503 | 1510 | ||
1504 | EXPORT_SYMBOL(drx397xD_attach); | ||
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h index ddc7a07971b7..ba05d17290c6 100644 --- a/drivers/media/dvb/frontends/drx397xD.h +++ b/drivers/media/dvb/frontends/drx397xD.h | |||
@@ -28,7 +28,7 @@ | |||
28 | #define DRX_F_OFFSET 36000000 | 28 | #define DRX_F_OFFSET 36000000 |
29 | 29 | ||
30 | #define I2C_ADR_C0(x) \ | 30 | #define I2C_ADR_C0(x) \ |
31 | ( (u32)cpu_to_le32( \ | 31 | ( cpu_to_le32( \ |
32 | (u32)( \ | 32 | (u32)( \ |
33 | (((u32)(x) & (u32)0x000000ffUL) ) | \ | 33 | (((u32)(x) & (u32)0x000000ffUL) ) | \ |
34 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ | 34 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ |
@@ -38,7 +38,7 @@ | |||
38 | ) | 38 | ) |
39 | 39 | ||
40 | #define I2C_ADR_E0(x) \ | 40 | #define I2C_ADR_E0(x) \ |
41 | ( (u32)cpu_to_le32( \ | 41 | ( cpu_to_le32( \ |
42 | (u32)( \ | 42 | (u32)( \ |
43 | (((u32)(x) & (u32)0x000000ffUL) ) | \ | 43 | (((u32)(x) & (u32)0x000000ffUL) ) | \ |
44 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ | 44 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ |
@@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config | |||
122 | static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, | 122 | static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, |
123 | struct i2c_adapter *i2c) | 123 | struct i2c_adapter *i2c) |
124 | { | 124 | { |
125 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | 125 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
126 | return NULL; | 126 | return NULL; |
127 | } | 127 | } |
128 | #endif /* CONFIG_DVB_DRX397XD */ | 128 | #endif /* CONFIG_DVB_DRX397XD */ |
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index fed09dfb2b7c..db8a937cc630 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c | |||
@@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten | |||
75 | 75 | ||
76 | static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | 76 | static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) |
77 | { | 77 | { |
78 | if (fe->ops->tuner_ops->set_params) { | 78 | if (fe->ops.tuner_ops.set_params) { |
79 | fe->ops->tuner_ops->set_params(fe, p); | 79 | fe->ops.tuner_ops.set_params(fe, p); |
80 | if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0); | 80 | if (fe->ops.i2c_gate_ctrl) |
81 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
81 | } | 82 | } |
82 | 83 | ||
83 | return 0; | 84 | return 0; |
@@ -131,7 +132,7 @@ error: | |||
131 | 132 | ||
132 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; | 133 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; |
133 | 134 | ||
134 | struct dvb_frontend* dvb_dummy_fe_qpsk_attach() | 135 | struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) |
135 | { | 136 | { |
136 | struct dvb_dummy_fe_state* state = NULL; | 137 | struct dvb_dummy_fe_state* state = NULL; |
137 | 138 | ||
@@ -151,7 +152,7 @@ error: | |||
151 | 152 | ||
152 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; | 153 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; |
153 | 154 | ||
154 | struct dvb_frontend* dvb_dummy_fe_qam_attach() | 155 | struct dvb_frontend *dvb_dummy_fe_qam_attach(void) |
155 | { | 156 | { |
156 | struct dvb_dummy_fe_state* state = NULL; | 157 | struct dvb_dummy_fe_state* state = NULL; |
157 | 158 | ||
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h new file mode 100644 index 000000000000..fa79b7c83dd2 --- /dev/null +++ b/drivers/media/dvb/frontends/eds1547.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /* eds1547.h Earda EDS-1547 tuner support | ||
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 | |||
12 | #ifndef EDS1547 | ||
13 | #define EDS1547 | ||
14 | |||
15 | static u8 stv0288_earda_inittab[] = { | ||
16 | 0x01, 0x57, | ||
17 | 0x02, 0x20, | ||
18 | 0x03, 0x8e, | ||
19 | 0x04, 0x8e, | ||
20 | 0x05, 0x12, | ||
21 | 0x06, 0x00, | ||
22 | 0x07, 0x00, | ||
23 | 0x09, 0x00, | ||
24 | 0x0a, 0x04, | ||
25 | 0x0b, 0x00, | ||
26 | 0x0c, 0x00, | ||
27 | 0x0d, 0x00, | ||
28 | 0x0e, 0xd4, | ||
29 | 0x0f, 0x30, | ||
30 | 0x11, 0x44, | ||
31 | 0x12, 0x03, | ||
32 | 0x13, 0x48, | ||
33 | 0x14, 0x84, | ||
34 | 0x15, 0x45, | ||
35 | 0x16, 0xb7, | ||
36 | 0x17, 0x9c, | ||
37 | 0x18, 0x00, | ||
38 | 0x19, 0xa6, | ||
39 | 0x1a, 0x88, | ||
40 | 0x1b, 0x8f, | ||
41 | 0x1c, 0xf0, | ||
42 | 0x20, 0x0b, | ||
43 | 0x21, 0x54, | ||
44 | 0x22, 0x00, | ||
45 | 0x23, 0x00, | ||
46 | 0x2b, 0xff, | ||
47 | 0x2c, 0xf7, | ||
48 | 0x30, 0x00, | ||
49 | 0x31, 0x1e, | ||
50 | 0x32, 0x14, | ||
51 | 0x33, 0x0f, | ||
52 | 0x34, 0x09, | ||
53 | 0x35, 0x0c, | ||
54 | 0x36, 0x05, | ||
55 | 0x37, 0x2f, | ||
56 | 0x38, 0x16, | ||
57 | 0x39, 0xbd, | ||
58 | 0x3a, 0x00, | ||
59 | 0x3b, 0x13, | ||
60 | 0x3c, 0x11, | ||
61 | 0x3d, 0x30, | ||
62 | 0x40, 0x63, | ||
63 | 0x41, 0x04, | ||
64 | 0x42, 0x60, | ||
65 | 0x43, 0x00, | ||
66 | 0x44, 0x00, | ||
67 | 0x45, 0x00, | ||
68 | 0x46, 0x00, | ||
69 | 0x47, 0x00, | ||
70 | 0x4a, 0x00, | ||
71 | 0x50, 0x10, | ||
72 | 0x51, 0x36, | ||
73 | 0x52, 0x09, | ||
74 | 0x53, 0x94, | ||
75 | 0x54, 0x62, | ||
76 | 0x55, 0x29, | ||
77 | 0x56, 0x64, | ||
78 | 0x57, 0x2b, | ||
79 | 0x58, 0x54, | ||
80 | 0x59, 0x86, | ||
81 | 0x5a, 0x00, | ||
82 | 0x5b, 0x9b, | ||
83 | 0x5c, 0x08, | ||
84 | 0x5d, 0x7f, | ||
85 | 0x5e, 0x00, | ||
86 | 0x5f, 0xff, | ||
87 | 0x70, 0x00, | ||
88 | 0x71, 0x00, | ||
89 | 0x72, 0x00, | ||
90 | 0x74, 0x00, | ||
91 | 0x75, 0x00, | ||
92 | 0x76, 0x00, | ||
93 | 0x81, 0x00, | ||
94 | 0x82, 0x3f, | ||
95 | 0x83, 0x3f, | ||
96 | 0x84, 0x00, | ||
97 | 0x85, 0x00, | ||
98 | 0x88, 0x00, | ||
99 | 0x89, 0x00, | ||
100 | 0x8a, 0x00, | ||
101 | 0x8b, 0x00, | ||
102 | 0x8c, 0x00, | ||
103 | 0x90, 0x00, | ||
104 | 0x91, 0x00, | ||
105 | 0x92, 0x00, | ||
106 | 0x93, 0x00, | ||
107 | 0x94, 0x1c, | ||
108 | 0x97, 0x00, | ||
109 | 0xa0, 0x48, | ||
110 | 0xa1, 0x00, | ||
111 | 0xb0, 0xb8, | ||
112 | 0xb1, 0x3a, | ||
113 | 0xb2, 0x10, | ||
114 | 0xb3, 0x82, | ||
115 | 0xb4, 0x80, | ||
116 | 0xb5, 0x82, | ||
117 | 0xb6, 0x82, | ||
118 | 0xb7, 0x82, | ||
119 | 0xb8, 0x20, | ||
120 | 0xb9, 0x00, | ||
121 | 0xf0, 0x00, | ||
122 | 0xf1, 0x00, | ||
123 | 0xf2, 0xc0, | ||
124 | 0xff,0xff, | ||
125 | }; | ||
126 | |||
127 | static struct stv0288_config earda_config = { | ||
128 | .demod_address = 0x68, | ||
129 | .min_delay_ms = 100, | ||
130 | .inittab = stv0288_earda_inittab, | ||
131 | }; | ||
132 | |||
133 | #endif | ||
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c new file mode 100644 index 000000000000..855852fddf22 --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.c | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2008 Sirius International (Hong Kong) Limited | ||
5 | Timothy Lee <timothy.lee@siriushk.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | #include "lgs8gl5.h" | ||
30 | |||
31 | |||
32 | #define REG_RESET 0x02 | ||
33 | #define REG_RESET_OFF 0x01 | ||
34 | #define REG_03 0x03 | ||
35 | #define REG_04 0x04 | ||
36 | #define REG_07 0x07 | ||
37 | #define REG_09 0x09 | ||
38 | #define REG_0A 0x0a | ||
39 | #define REG_0B 0x0b | ||
40 | #define REG_0C 0x0c | ||
41 | #define REG_37 0x37 | ||
42 | #define REG_STRENGTH 0x4b | ||
43 | #define REG_STRENGTH_MASK 0x7f | ||
44 | #define REG_STRENGTH_CARRIER 0x80 | ||
45 | #define REG_INVERSION 0x7c | ||
46 | #define REG_INVERSION_ON 0x80 | ||
47 | #define REG_7D 0x7d | ||
48 | #define REG_7E 0x7e | ||
49 | #define REG_A2 0xa2 | ||
50 | #define REG_STATUS 0xa4 | ||
51 | #define REG_STATUS_SYNC 0x04 | ||
52 | #define REG_STATUS_LOCK 0x01 | ||
53 | |||
54 | |||
55 | struct lgs8gl5_state { | ||
56 | struct i2c_adapter *i2c; | ||
57 | const struct lgs8gl5_config *config; | ||
58 | struct dvb_frontend frontend; | ||
59 | }; | ||
60 | |||
61 | |||
62 | static int debug; | ||
63 | #define dprintk(args...) \ | ||
64 | do { \ | ||
65 | if (debug) \ | ||
66 | printk(KERN_DEBUG "lgs8gl5: " args); \ | ||
67 | } while (0) | ||
68 | |||
69 | |||
70 | /* Writes into demod's register */ | ||
71 | static int | ||
72 | lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
73 | { | ||
74 | int ret; | ||
75 | u8 buf[] = {reg, data}; | ||
76 | struct i2c_msg msg = { | ||
77 | .addr = state->config->demod_address, | ||
78 | .flags = 0, | ||
79 | .buf = buf, | ||
80 | .len = 2 | ||
81 | }; | ||
82 | |||
83 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
84 | if (ret != 1) | ||
85 | dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", | ||
86 | __func__, reg, data, ret); | ||
87 | return (ret != 1) ? -1 : 0; | ||
88 | } | ||
89 | |||
90 | |||
91 | /* Reads from demod's register */ | ||
92 | static int | ||
93 | lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) | ||
94 | { | ||
95 | int ret; | ||
96 | u8 b0[] = {reg}; | ||
97 | u8 b1[] = {0}; | ||
98 | struct i2c_msg msg[2] = { | ||
99 | { | ||
100 | .addr = state->config->demod_address, | ||
101 | .flags = 0, | ||
102 | .buf = b0, | ||
103 | .len = 1 | ||
104 | }, | ||
105 | { | ||
106 | .addr = state->config->demod_address, | ||
107 | .flags = I2C_M_RD, | ||
108 | .buf = b1, | ||
109 | .len = 1 | ||
110 | } | ||
111 | }; | ||
112 | |||
113 | ret = i2c_transfer(state->i2c, msg, 2); | ||
114 | if (ret != 2) | ||
115 | return -EIO; | ||
116 | |||
117 | return b1[0]; | ||
118 | } | ||
119 | |||
120 | |||
121 | static int | ||
122 | lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
123 | { | ||
124 | lgs8gl5_read_reg(state, reg); | ||
125 | lgs8gl5_write_reg(state, reg, data); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | |||
130 | /* Writes into alternate device's register */ | ||
131 | /* TODO: Find out what that device is for! */ | ||
132 | static int | ||
133 | lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
134 | { | ||
135 | int ret; | ||
136 | u8 b0[] = {reg}; | ||
137 | u8 b1[] = {0}; | ||
138 | u8 b2[] = {reg, data}; | ||
139 | struct i2c_msg msg[3] = { | ||
140 | { | ||
141 | .addr = state->config->demod_address + 2, | ||
142 | .flags = 0, | ||
143 | .buf = b0, | ||
144 | .len = 1 | ||
145 | }, | ||
146 | { | ||
147 | .addr = state->config->demod_address + 2, | ||
148 | .flags = I2C_M_RD, | ||
149 | .buf = b1, | ||
150 | .len = 1 | ||
151 | }, | ||
152 | { | ||
153 | .addr = state->config->demod_address + 2, | ||
154 | .flags = 0, | ||
155 | .buf = b2, | ||
156 | .len = 2 | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | ret = i2c_transfer(state->i2c, msg, 3); | ||
161 | return (ret != 3) ? -1 : 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | static void | ||
166 | lgs8gl5_soft_reset(struct lgs8gl5_state *state) | ||
167 | { | ||
168 | u8 val; | ||
169 | |||
170 | dprintk("%s\n", __func__); | ||
171 | |||
172 | val = lgs8gl5_read_reg(state, REG_RESET); | ||
173 | lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); | ||
174 | lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); | ||
175 | msleep(5); | ||
176 | } | ||
177 | |||
178 | |||
179 | /* Starts demodulation */ | ||
180 | static void | ||
181 | lgs8gl5_start_demod(struct lgs8gl5_state *state) | ||
182 | { | ||
183 | u8 val; | ||
184 | int n; | ||
185 | |||
186 | dprintk("%s\n", __func__); | ||
187 | |||
188 | lgs8gl5_update_alt_reg(state, 0xc2, 0x28); | ||
189 | lgs8gl5_soft_reset(state); | ||
190 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
191 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
192 | lgs8gl5_write_reg(state, REG_09, 0x0e); | ||
193 | lgs8gl5_write_reg(state, REG_0A, 0xe5); | ||
194 | lgs8gl5_write_reg(state, REG_0B, 0x35); | ||
195 | lgs8gl5_write_reg(state, REG_0C, 0x30); | ||
196 | |||
197 | lgs8gl5_update_reg(state, REG_03, 0x00); | ||
198 | lgs8gl5_update_reg(state, REG_7E, 0x01); | ||
199 | lgs8gl5_update_alt_reg(state, 0xc5, 0x00); | ||
200 | lgs8gl5_update_reg(state, REG_04, 0x02); | ||
201 | lgs8gl5_update_reg(state, REG_37, 0x01); | ||
202 | lgs8gl5_soft_reset(state); | ||
203 | |||
204 | /* Wait for carrier */ | ||
205 | for (n = 0; n < 10; n++) { | ||
206 | val = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
207 | dprintk("Wait for carrier[%d] 0x%02X\n", n, val); | ||
208 | if (val & REG_STRENGTH_CARRIER) | ||
209 | break; | ||
210 | msleep(4); | ||
211 | } | ||
212 | if (!(val & REG_STRENGTH_CARRIER)) | ||
213 | return; | ||
214 | |||
215 | /* Wait for lock */ | ||
216 | for (n = 0; n < 20; n++) { | ||
217 | val = lgs8gl5_read_reg(state, REG_STATUS); | ||
218 | dprintk("Wait for lock[%d] 0x%02X\n", n, val); | ||
219 | if (val & REG_STATUS_LOCK) | ||
220 | break; | ||
221 | msleep(12); | ||
222 | } | ||
223 | if (!(val & REG_STATUS_LOCK)) | ||
224 | return; | ||
225 | |||
226 | lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); | ||
227 | lgs8gl5_soft_reset(state); | ||
228 | } | ||
229 | |||
230 | |||
231 | static int | ||
232 | lgs8gl5_init(struct dvb_frontend *fe) | ||
233 | { | ||
234 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
235 | |||
236 | dprintk("%s\n", __func__); | ||
237 | |||
238 | lgs8gl5_update_alt_reg(state, 0xc2, 0x28); | ||
239 | lgs8gl5_soft_reset(state); | ||
240 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
241 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
242 | lgs8gl5_write_reg(state, REG_09, 0x0e); | ||
243 | lgs8gl5_write_reg(state, REG_0A, 0xe5); | ||
244 | lgs8gl5_write_reg(state, REG_0B, 0x35); | ||
245 | lgs8gl5_write_reg(state, REG_0C, 0x30); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | |||
251 | static int | ||
252 | lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
253 | { | ||
254 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
255 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
256 | u8 flags = lgs8gl5_read_reg(state, REG_STATUS); | ||
257 | |||
258 | *status = 0; | ||
259 | |||
260 | if ((level & REG_STRENGTH_MASK) > 0) | ||
261 | *status |= FE_HAS_SIGNAL; | ||
262 | if (level & REG_STRENGTH_CARRIER) | ||
263 | *status |= FE_HAS_CARRIER; | ||
264 | if (flags & REG_STATUS_SYNC) | ||
265 | *status |= FE_HAS_SYNC; | ||
266 | if (flags & REG_STATUS_LOCK) | ||
267 | *status |= FE_HAS_LOCK; | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | |||
273 | static int | ||
274 | lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
275 | { | ||
276 | *ber = 0; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | |||
282 | static int | ||
283 | lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) | ||
284 | { | ||
285 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
286 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
287 | *signal_strength = (level & REG_STRENGTH_MASK) << 8; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | static int | ||
294 | lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
295 | { | ||
296 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
297 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
298 | *snr = (level & REG_STRENGTH_MASK) << 8; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | |||
304 | static int | ||
305 | lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
306 | { | ||
307 | *ucblocks = 0; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | |||
313 | static int | ||
314 | lgs8gl5_set_frontend(struct dvb_frontend *fe, | ||
315 | struct dvb_frontend_parameters *p) | ||
316 | { | ||
317 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
318 | |||
319 | dprintk("%s\n", __func__); | ||
320 | |||
321 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) | ||
322 | return -EINVAL; | ||
323 | |||
324 | if (fe->ops.tuner_ops.set_params) { | ||
325 | fe->ops.tuner_ops.set_params(fe, p); | ||
326 | if (fe->ops.i2c_gate_ctrl) | ||
327 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
328 | } | ||
329 | |||
330 | /* lgs8gl5_set_inversion(state, p->inversion); */ | ||
331 | |||
332 | lgs8gl5_start_demod(state); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | |||
338 | static int | ||
339 | lgs8gl5_get_frontend(struct dvb_frontend *fe, | ||
340 | struct dvb_frontend_parameters *p) | ||
341 | { | ||
342 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
343 | u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); | ||
344 | struct dvb_ofdm_parameters *o = &p->u.ofdm; | ||
345 | |||
346 | p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; | ||
347 | |||
348 | o->code_rate_HP = FEC_1_2; | ||
349 | o->code_rate_LP = FEC_7_8; | ||
350 | o->guard_interval = GUARD_INTERVAL_1_32; | ||
351 | o->transmission_mode = TRANSMISSION_MODE_2K; | ||
352 | o->constellation = QAM_64; | ||
353 | o->hierarchy_information = HIERARCHY_NONE; | ||
354 | o->bandwidth = BANDWIDTH_8_MHZ; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | |||
360 | static int | ||
361 | lgs8gl5_get_tune_settings(struct dvb_frontend *fe, | ||
362 | struct dvb_frontend_tune_settings *fesettings) | ||
363 | { | ||
364 | fesettings->min_delay_ms = 240; | ||
365 | fesettings->step_size = 0; | ||
366 | fesettings->max_drift = 0; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | |||
371 | static void | ||
372 | lgs8gl5_release(struct dvb_frontend *fe) | ||
373 | { | ||
374 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
375 | kfree(state); | ||
376 | } | ||
377 | |||
378 | |||
379 | static struct dvb_frontend_ops lgs8gl5_ops; | ||
380 | |||
381 | |||
382 | struct dvb_frontend* | ||
383 | lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) | ||
384 | { | ||
385 | struct lgs8gl5_state *state = NULL; | ||
386 | |||
387 | dprintk("%s\n", __func__); | ||
388 | |||
389 | /* Allocate memory for the internal state */ | ||
390 | state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); | ||
391 | if (state == NULL) | ||
392 | goto error; | ||
393 | |||
394 | /* Setup the state */ | ||
395 | state->config = config; | ||
396 | state->i2c = i2c; | ||
397 | |||
398 | /* Check if the demod is there */ | ||
399 | if (lgs8gl5_read_reg(state, REG_RESET) < 0) | ||
400 | goto error; | ||
401 | |||
402 | /* Create dvb_frontend */ | ||
403 | memcpy(&state->frontend.ops, &lgs8gl5_ops, | ||
404 | sizeof(struct dvb_frontend_ops)); | ||
405 | state->frontend.demodulator_priv = state; | ||
406 | return &state->frontend; | ||
407 | |||
408 | error: | ||
409 | kfree(state); | ||
410 | return NULL; | ||
411 | } | ||
412 | EXPORT_SYMBOL(lgs8gl5_attach); | ||
413 | |||
414 | |||
415 | static struct dvb_frontend_ops lgs8gl5_ops = { | ||
416 | .info = { | ||
417 | .name = "Legend Silicon LGS-8GL5 DMB-TH", | ||
418 | .type = FE_OFDM, | ||
419 | .frequency_min = 474000000, | ||
420 | .frequency_max = 858000000, | ||
421 | .frequency_stepsize = 10000, | ||
422 | .frequency_tolerance = 0, | ||
423 | .caps = FE_CAN_FEC_AUTO | | ||
424 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | | ||
425 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
426 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
427 | FE_CAN_BANDWIDTH_AUTO | | ||
428 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
429 | FE_CAN_HIERARCHY_AUTO | | ||
430 | FE_CAN_RECOVER | ||
431 | }, | ||
432 | |||
433 | .release = lgs8gl5_release, | ||
434 | |||
435 | .init = lgs8gl5_init, | ||
436 | |||
437 | .set_frontend = lgs8gl5_set_frontend, | ||
438 | .get_frontend = lgs8gl5_get_frontend, | ||
439 | .get_tune_settings = lgs8gl5_get_tune_settings, | ||
440 | |||
441 | .read_status = lgs8gl5_read_status, | ||
442 | .read_ber = lgs8gl5_read_ber, | ||
443 | .read_signal_strength = lgs8gl5_read_signal_strength, | ||
444 | .read_snr = lgs8gl5_read_snr, | ||
445 | .read_ucblocks = lgs8gl5_read_ucblocks, | ||
446 | }; | ||
447 | |||
448 | |||
449 | module_param(debug, int, 0644); | ||
450 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
451 | |||
452 | MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); | ||
453 | MODULE_AUTHOR("Timothy Lee"); | ||
454 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h new file mode 100644 index 000000000000..d14176787a7d --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2008 Sirius International (Hong Kong) Limited | ||
5 | Timothy Lee <timothy.lee@siriushk.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef LGS8GL5_H | ||
24 | #define LGS8GL5_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | struct lgs8gl5_config { | ||
29 | /* the demodulator's i2c address */ | ||
30 | u8 demod_address; | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_DVB_LGS8GL5) || \ | ||
34 | (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) | ||
35 | extern struct dvb_frontend *lgs8gl5_attach( | ||
36 | const struct lgs8gl5_config *config, struct i2c_adapter *i2c); | ||
37 | #else | ||
38 | static inline struct dvb_frontend *lgs8gl5_attach( | ||
39 | const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { | ||
40 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
41 | return NULL; | ||
42 | } | ||
43 | #endif /* CONFIG_DVB_LGS8GL5 */ | ||
44 | |||
45 | #endif /* LGS8GL5_H */ | ||
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index af298358e822..a8429ebfa8a2 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c | |||
@@ -80,7 +80,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len) | 83 | static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) |
84 | { | 84 | { |
85 | int err; | 85 | int err; |
86 | struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; | 86 | struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; |
@@ -111,7 +111,7 @@ static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, | |||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len) | 114 | static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) |
115 | { | 115 | { |
116 | u8 reg2 [] = { reg }; | 116 | u8 reg2 [] = { reg }; |
117 | 117 | ||
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 6afe12aaca4e..16cf2fdd5d7d 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c | |||
@@ -88,7 +88,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, | |||
88 | return 0; | 88 | return 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len) | 91 | static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) |
92 | { | 92 | { |
93 | int err; | 93 | int err; |
94 | struct i2c_msg msg; | 94 | struct i2c_msg msg; |
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 747d3fa2e5e5..2e9fd2893ede 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c | |||
@@ -59,7 +59,7 @@ struct s5h1420_state { | |||
59 | * it does not support repeated-start, workaround: write addr-1 | 59 | * it does not support repeated-start, workaround: write addr-1 |
60 | * and then read | 60 | * and then read |
61 | */ | 61 | */ |
62 | u8 shadow[255]; | 62 | u8 shadow[256]; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); | 65 | static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); |
@@ -94,8 +94,11 @@ static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) | |||
94 | if (ret != 3) | 94 | if (ret != 3) |
95 | return ret; | 95 | return ret; |
96 | } else { | 96 | } else { |
97 | ret = i2c_transfer(state->i2c, &msg[1], 2); | 97 | ret = i2c_transfer(state->i2c, &msg[1], 1); |
98 | if (ret != 2) | 98 | if (ret != 1) |
99 | return ret; | ||
100 | ret = i2c_transfer(state->i2c, &msg[2], 1); | ||
101 | if (ret != 1) | ||
99 | return ret; | 102 | return ret; |
100 | } | 103 | } |
101 | 104 | ||
@@ -823,7 +826,7 @@ static int s5h1420_init (struct dvb_frontend* fe) | |||
823 | struct s5h1420_state* state = fe->demodulator_priv; | 826 | struct s5h1420_state* state = fe->demodulator_priv; |
824 | 827 | ||
825 | /* disable power down and do reset */ | 828 | /* disable power down and do reset */ |
826 | state->CON_1_val = 0x10; | 829 | state->CON_1_val = state->config->serial_mpeg << 4; |
827 | s5h1420_writereg(state, 0x02, state->CON_1_val); | 830 | s5h1420_writereg(state, 0x02, state->CON_1_val); |
828 | msleep(10); | 831 | msleep(10); |
829 | s5h1420_reset(state); | 832 | s5h1420_reset(state); |
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index 4c913f142bc4..ff308136d865 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h | |||
@@ -32,10 +32,12 @@ struct s5h1420_config | |||
32 | u8 demod_address; | 32 | u8 demod_address; |
33 | 33 | ||
34 | /* does the inversion require inversion? */ | 34 | /* does the inversion require inversion? */ |
35 | u8 invert : 1; | 35 | u8 invert:1; |
36 | 36 | ||
37 | u8 repeated_start_workaround : 1; | 37 | u8 repeated_start_workaround:1; |
38 | u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */ | 38 | u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */ |
39 | |||
40 | u8 serial_mpeg:1; | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) | 43 | #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) |
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c new file mode 100644 index 000000000000..3ddbe69c45ce --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.c | |||
@@ -0,0 +1,974 @@ | |||
1 | /* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator | ||
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 | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/jiffies.h> | ||
18 | #include <asm/div64.h> | ||
19 | |||
20 | #include "dvb_frontend.h" | ||
21 | #include "si21xx.h" | ||
22 | |||
23 | #define REVISION_REG 0x00 | ||
24 | #define SYSTEM_MODE_REG 0x01 | ||
25 | #define TS_CTRL_REG_1 0x02 | ||
26 | #define TS_CTRL_REG_2 0x03 | ||
27 | #define PIN_CTRL_REG_1 0x04 | ||
28 | #define PIN_CTRL_REG_2 0x05 | ||
29 | #define LOCK_STATUS_REG_1 0x0f | ||
30 | #define LOCK_STATUS_REG_2 0x10 | ||
31 | #define ACQ_STATUS_REG 0x11 | ||
32 | #define ACQ_CTRL_REG_1 0x13 | ||
33 | #define ACQ_CTRL_REG_2 0x14 | ||
34 | #define PLL_DIVISOR_REG 0x15 | ||
35 | #define COARSE_TUNE_REG 0x16 | ||
36 | #define FINE_TUNE_REG_L 0x17 | ||
37 | #define FINE_TUNE_REG_H 0x18 | ||
38 | |||
39 | #define ANALOG_AGC_POWER_LEVEL_REG 0x28 | ||
40 | #define CFO_ESTIMATOR_CTRL_REG_1 0x29 | ||
41 | #define CFO_ESTIMATOR_CTRL_REG_2 0x2a | ||
42 | #define CFO_ESTIMATOR_CTRL_REG_3 0x2b | ||
43 | |||
44 | #define SYM_RATE_ESTIMATE_REG_L 0x31 | ||
45 | #define SYM_RATE_ESTIMATE_REG_M 0x32 | ||
46 | #define SYM_RATE_ESTIMATE_REG_H 0x33 | ||
47 | |||
48 | #define CFO_ESTIMATOR_OFFSET_REG_L 0x36 | ||
49 | #define CFO_ESTIMATOR_OFFSET_REG_H 0x37 | ||
50 | #define CFO_ERROR_REG_L 0x38 | ||
51 | #define CFO_ERROR_REG_H 0x39 | ||
52 | #define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a | ||
53 | |||
54 | #define SYM_RATE_REG_L 0x3f | ||
55 | #define SYM_RATE_REG_M 0x40 | ||
56 | #define SYM_RATE_REG_H 0x41 | ||
57 | #define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 | ||
58 | #define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 | ||
59 | |||
60 | #define C_N_ESTIMATOR_CTRL_REG 0x7c | ||
61 | #define C_N_ESTIMATOR_THRSHLD_REG 0x7d | ||
62 | #define C_N_ESTIMATOR_LEVEL_REG_L 0x7e | ||
63 | #define C_N_ESTIMATOR_LEVEL_REG_H 0x7f | ||
64 | |||
65 | #define BLIND_SCAN_CTRL_REG 0x80 | ||
66 | |||
67 | #define LSA_CTRL_REG_1 0x8D | ||
68 | #define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f | ||
69 | #define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 | ||
70 | #define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 | ||
71 | #define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 | ||
72 | #define INBAND_POWER_THRSHLD_REG 0x93 | ||
73 | #define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 | ||
74 | |||
75 | #define VIT_SRCH_CTRL_REG_1 0xa0 | ||
76 | #define VIT_SRCH_CTRL_REG_2 0xa1 | ||
77 | #define VIT_SRCH_CTRL_REG_3 0xa2 | ||
78 | #define VIT_SRCH_STATUS_REG 0xa3 | ||
79 | #define VITERBI_BER_COUNT_REG_L 0xab | ||
80 | #define REED_SOLOMON_CTRL_REG 0xb0 | ||
81 | #define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 | ||
82 | #define PRBS_CTRL_REG 0xb5 | ||
83 | |||
84 | #define LNB_CTRL_REG_1 0xc0 | ||
85 | #define LNB_CTRL_REG_2 0xc1 | ||
86 | #define LNB_CTRL_REG_3 0xc2 | ||
87 | #define LNB_CTRL_REG_4 0xc3 | ||
88 | #define LNB_CTRL_STATUS_REG 0xc4 | ||
89 | #define LNB_FIFO_REGS_0 0xc5 | ||
90 | #define LNB_FIFO_REGS_1 0xc6 | ||
91 | #define LNB_FIFO_REGS_2 0xc7 | ||
92 | #define LNB_FIFO_REGS_3 0xc8 | ||
93 | #define LNB_FIFO_REGS_4 0xc9 | ||
94 | #define LNB_FIFO_REGS_5 0xca | ||
95 | #define LNB_SUPPLY_CTRL_REG_1 0xcb | ||
96 | #define LNB_SUPPLY_CTRL_REG_2 0xcc | ||
97 | #define LNB_SUPPLY_CTRL_REG_3 0xcd | ||
98 | #define LNB_SUPPLY_CTRL_REG_4 0xce | ||
99 | #define LNB_SUPPLY_STATUS_REG 0xcf | ||
100 | |||
101 | #define FALSE 0 | ||
102 | #define TRUE 1 | ||
103 | #define FAIL -1 | ||
104 | #define PASS 0 | ||
105 | |||
106 | #define ALLOWABLE_FS_COUNT 10 | ||
107 | #define STATUS_BER 0 | ||
108 | #define STATUS_UCBLOCKS 1 | ||
109 | |||
110 | static int debug; | ||
111 | #define dprintk(args...) \ | ||
112 | do { \ | ||
113 | if (debug) \ | ||
114 | printk(KERN_DEBUG "si21xx: " args); \ | ||
115 | } while (0) | ||
116 | |||
117 | enum { | ||
118 | ACTIVE_HIGH, | ||
119 | ACTIVE_LOW | ||
120 | }; | ||
121 | enum { | ||
122 | BYTE_WIDE, | ||
123 | BIT_WIDE | ||
124 | }; | ||
125 | enum { | ||
126 | CLK_GAPPED_MODE, | ||
127 | CLK_CONTINUOUS_MODE | ||
128 | }; | ||
129 | enum { | ||
130 | RISING_EDGE, | ||
131 | FALLING_EDGE | ||
132 | }; | ||
133 | enum { | ||
134 | MSB_FIRST, | ||
135 | LSB_FIRST | ||
136 | }; | ||
137 | enum { | ||
138 | SERIAL, | ||
139 | PARALLEL | ||
140 | }; | ||
141 | |||
142 | struct si21xx_state { | ||
143 | struct i2c_adapter *i2c; | ||
144 | const struct si21xx_config *config; | ||
145 | struct dvb_frontend frontend; | ||
146 | u8 initialised:1; | ||
147 | int errmode; | ||
148 | int fs; /*Sampling rate of the ADC in MHz*/ | ||
149 | }; | ||
150 | |||
151 | /* register default initialization */ | ||
152 | static u8 serit_sp1511lhb_inittab[] = { | ||
153 | 0x01, 0x28, /* set i2c_inc_disable */ | ||
154 | 0x20, 0x03, | ||
155 | 0x27, 0x20, | ||
156 | 0xe0, 0x45, | ||
157 | 0xe1, 0x08, | ||
158 | 0xfe, 0x01, | ||
159 | 0x01, 0x28, | ||
160 | 0x89, 0x09, | ||
161 | 0x04, 0x80, | ||
162 | 0x05, 0x01, | ||
163 | 0x06, 0x00, | ||
164 | 0x20, 0x03, | ||
165 | 0x24, 0x88, | ||
166 | 0x29, 0x09, | ||
167 | 0x2a, 0x0f, | ||
168 | 0x2c, 0x10, | ||
169 | 0x2d, 0x19, | ||
170 | 0x2e, 0x08, | ||
171 | 0x2f, 0x10, | ||
172 | 0x30, 0x19, | ||
173 | 0x34, 0x20, | ||
174 | 0x35, 0x03, | ||
175 | 0x45, 0x02, | ||
176 | 0x46, 0x45, | ||
177 | 0x47, 0xd0, | ||
178 | 0x48, 0x00, | ||
179 | 0x49, 0x40, | ||
180 | 0x4a, 0x03, | ||
181 | 0x4c, 0xfd, | ||
182 | 0x4f, 0x2e, | ||
183 | 0x50, 0x2e, | ||
184 | 0x51, 0x10, | ||
185 | 0x52, 0x10, | ||
186 | 0x56, 0x92, | ||
187 | 0x59, 0x00, | ||
188 | 0x5a, 0x2d, | ||
189 | 0x5b, 0x33, | ||
190 | 0x5c, 0x1f, | ||
191 | 0x5f, 0x76, | ||
192 | 0x62, 0xc0, | ||
193 | 0x63, 0xc0, | ||
194 | 0x64, 0xf3, | ||
195 | 0x65, 0xf3, | ||
196 | 0x79, 0x40, | ||
197 | 0x6a, 0x40, | ||
198 | 0x6b, 0x0a, | ||
199 | 0x6c, 0x80, | ||
200 | 0x6d, 0x27, | ||
201 | 0x71, 0x06, | ||
202 | 0x75, 0x60, | ||
203 | 0x78, 0x00, | ||
204 | 0x79, 0xb5, | ||
205 | 0x7c, 0x05, | ||
206 | 0x7d, 0x1a, | ||
207 | 0x87, 0x55, | ||
208 | 0x88, 0x72, | ||
209 | 0x8f, 0x08, | ||
210 | 0x90, 0xe0, | ||
211 | 0x94, 0x40, | ||
212 | 0xa0, 0x3f, | ||
213 | 0xa1, 0xc0, | ||
214 | 0xa4, 0xcc, | ||
215 | 0xa5, 0x66, | ||
216 | 0xa6, 0x66, | ||
217 | 0xa7, 0x7b, | ||
218 | 0xa8, 0x7b, | ||
219 | 0xa9, 0x7b, | ||
220 | 0xaa, 0x9a, | ||
221 | 0xed, 0x04, | ||
222 | 0xad, 0x00, | ||
223 | 0xae, 0x03, | ||
224 | 0xcc, 0xab, | ||
225 | 0x01, 0x08, | ||
226 | 0xff, 0xff | ||
227 | }; | ||
228 | |||
229 | /* low level read/writes */ | ||
230 | static int si21_writeregs(struct si21xx_state *state, u8 reg1, | ||
231 | u8 *data, int len) | ||
232 | { | ||
233 | int ret; | ||
234 | u8 buf[60];/* = { reg1, data };*/ | ||
235 | struct i2c_msg msg = { | ||
236 | .addr = state->config->demod_address, | ||
237 | .flags = 0, | ||
238 | .buf = buf, | ||
239 | .len = len + 1 | ||
240 | }; | ||
241 | |||
242 | msg.buf[0] = reg1; | ||
243 | memcpy(msg.buf + 1, data, len); | ||
244 | |||
245 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
246 | |||
247 | if (ret != 1) | ||
248 | dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " | ||
249 | "ret == %i)\n", __func__, reg1, data[0], ret); | ||
250 | |||
251 | return (ret != 1) ? -EREMOTEIO : 0; | ||
252 | } | ||
253 | |||
254 | static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) | ||
255 | { | ||
256 | int ret; | ||
257 | u8 buf[] = { reg, data }; | ||
258 | struct i2c_msg msg = { | ||
259 | .addr = state->config->demod_address, | ||
260 | .flags = 0, | ||
261 | .buf = buf, | ||
262 | .len = 2 | ||
263 | }; | ||
264 | |||
265 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
266 | |||
267 | if (ret != 1) | ||
268 | dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " | ||
269 | "ret == %i)\n", __func__, reg, data, ret); | ||
270 | |||
271 | return (ret != 1) ? -EREMOTEIO : 0; | ||
272 | } | ||
273 | |||
274 | static int si21_write(struct dvb_frontend *fe, u8 *buf, int len) | ||
275 | { | ||
276 | struct si21xx_state *state = fe->demodulator_priv; | ||
277 | |||
278 | if (len != 2) | ||
279 | return -EINVAL; | ||
280 | |||
281 | return si21_writereg(state, buf[0], buf[1]); | ||
282 | } | ||
283 | |||
284 | static u8 si21_readreg(struct si21xx_state *state, u8 reg) | ||
285 | { | ||
286 | int ret; | ||
287 | u8 b0[] = { reg }; | ||
288 | u8 b1[] = { 0 }; | ||
289 | struct i2c_msg msg[] = { | ||
290 | { | ||
291 | .addr = state->config->demod_address, | ||
292 | .flags = 0, | ||
293 | .buf = b0, | ||
294 | .len = 1 | ||
295 | }, { | ||
296 | .addr = state->config->demod_address, | ||
297 | .flags = I2C_M_RD, | ||
298 | .buf = b1, | ||
299 | .len = 1 | ||
300 | } | ||
301 | }; | ||
302 | |||
303 | ret = i2c_transfer(state->i2c, msg, 2); | ||
304 | |||
305 | if (ret != 2) | ||
306 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
307 | __func__, reg, ret); | ||
308 | |||
309 | return b1[0]; | ||
310 | } | ||
311 | |||
312 | static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) | ||
313 | { | ||
314 | int ret; | ||
315 | struct i2c_msg msg[] = { | ||
316 | { | ||
317 | .addr = state->config->demod_address, | ||
318 | .flags = 0, | ||
319 | .buf = ®1, | ||
320 | .len = 1 | ||
321 | }, { | ||
322 | .addr = state->config->demod_address, | ||
323 | .flags = I2C_M_RD, | ||
324 | .buf = b, | ||
325 | .len = len | ||
326 | } | ||
327 | }; | ||
328 | |||
329 | ret = i2c_transfer(state->i2c, msg, 2); | ||
330 | |||
331 | if (ret != 2) | ||
332 | dprintk("%s: readreg error (ret == %i)\n", __func__, ret); | ||
333 | |||
334 | return ret == 2 ? 0 : -1; | ||
335 | } | ||
336 | |||
337 | static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) | ||
338 | { | ||
339 | unsigned long start = jiffies; | ||
340 | |||
341 | dprintk("%s\n", __func__); | ||
342 | |||
343 | while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { | ||
344 | if (jiffies - start > timeout) { | ||
345 | dprintk("%s: timeout!!\n", __func__); | ||
346 | return -ETIMEDOUT; | ||
347 | } | ||
348 | msleep(10); | ||
349 | }; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) | ||
355 | { | ||
356 | struct si21xx_state *state = fe->demodulator_priv; | ||
357 | u32 sym_rate, data_rate; | ||
358 | int i; | ||
359 | u8 sym_rate_bytes[3]; | ||
360 | |||
361 | dprintk("%s : srate = %i\n", __func__ , srate); | ||
362 | |||
363 | if ((srate < 1000000) || (srate > 45000000)) | ||
364 | return -EINVAL; | ||
365 | |||
366 | data_rate = srate; | ||
367 | sym_rate = 0; | ||
368 | |||
369 | for (i = 0; i < 4; ++i) { | ||
370 | sym_rate /= 100; | ||
371 | sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / | ||
372 | state->fs; | ||
373 | data_rate /= 100; | ||
374 | } | ||
375 | for (i = 0; i < 3; ++i) | ||
376 | sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); | ||
377 | |||
378 | si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, | ||
384 | struct dvb_diseqc_master_cmd *m) | ||
385 | { | ||
386 | struct si21xx_state *state = fe->demodulator_priv; | ||
387 | u8 lnb_status; | ||
388 | u8 LNB_CTRL_1; | ||
389 | int status; | ||
390 | |||
391 | dprintk("%s\n", __func__); | ||
392 | |||
393 | status = PASS; | ||
394 | LNB_CTRL_1 = 0; | ||
395 | |||
396 | status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); | ||
397 | status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); | ||
398 | |||
399 | /*fill the FIFO*/ | ||
400 | status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); | ||
401 | |||
402 | LNB_CTRL_1 = (lnb_status & 0x70); | ||
403 | LNB_CTRL_1 |= m->msg_len; | ||
404 | |||
405 | LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ | ||
406 | |||
407 | status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); | ||
408 | |||
409 | return status; | ||
410 | } | ||
411 | |||
412 | static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, | ||
413 | fe_sec_mini_cmd_t burst) | ||
414 | { | ||
415 | struct si21xx_state *state = fe->demodulator_priv; | ||
416 | u8 val; | ||
417 | |||
418 | dprintk("%s\n", __func__); | ||
419 | |||
420 | if (si21xx_wait_diseqc_idle(state, 100) < 0) | ||
421 | return -ETIMEDOUT; | ||
422 | |||
423 | val = (0x80 | si21_readreg(state, 0xc1)); | ||
424 | if (si21_writereg(state, LNB_CTRL_REG_1, | ||
425 | burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) | ||
426 | return -EREMOTEIO; | ||
427 | |||
428 | if (si21xx_wait_diseqc_idle(state, 100) < 0) | ||
429 | return -ETIMEDOUT; | ||
430 | |||
431 | if (si21_writereg(state, LNB_CTRL_REG_1, val)) | ||
432 | return -EREMOTEIO; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | /* 30.06.2008 */ | ||
437 | static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
438 | { | ||
439 | struct si21xx_state *state = fe->demodulator_priv; | ||
440 | u8 val; | ||
441 | |||
442 | dprintk("%s\n", __func__); | ||
443 | val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); | ||
444 | |||
445 | switch (tone) { | ||
446 | case SEC_TONE_ON: | ||
447 | return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); | ||
448 | |||
449 | case SEC_TONE_OFF: | ||
450 | return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); | ||
451 | |||
452 | default: | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) | ||
458 | { | ||
459 | struct si21xx_state *state = fe->demodulator_priv; | ||
460 | |||
461 | u8 val; | ||
462 | dprintk("%s: %s\n", __func__, | ||
463 | volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
464 | volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
465 | |||
466 | |||
467 | val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); | ||
468 | |||
469 | switch (volt) { | ||
470 | case SEC_VOLTAGE_18: | ||
471 | return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); | ||
472 | break; | ||
473 | case SEC_VOLTAGE_13: | ||
474 | return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); | ||
475 | break; | ||
476 | default: | ||
477 | return -EINVAL; | ||
478 | }; | ||
479 | } | ||
480 | |||
481 | static int si21xx_init(struct dvb_frontend *fe) | ||
482 | { | ||
483 | struct si21xx_state *state = fe->demodulator_priv; | ||
484 | int i; | ||
485 | int status = 0; | ||
486 | u8 reg1; | ||
487 | u8 val; | ||
488 | u8 reg2[2]; | ||
489 | |||
490 | dprintk("%s\n", __func__); | ||
491 | |||
492 | for (i = 0; ; i += 2) { | ||
493 | reg1 = serit_sp1511lhb_inittab[i]; | ||
494 | val = serit_sp1511lhb_inittab[i+1]; | ||
495 | if (reg1 == 0xff && val == 0xff) | ||
496 | break; | ||
497 | si21_writeregs(state, reg1, &val, 1); | ||
498 | } | ||
499 | |||
500 | /*DVB QPSK SYSTEM MODE REG*/ | ||
501 | reg1 = 0x08; | ||
502 | si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); | ||
503 | |||
504 | /*transport stream config*/ | ||
505 | /* | ||
506 | mode = PARALLEL; | ||
507 | sdata_form = LSB_FIRST; | ||
508 | clk_edge = FALLING_EDGE; | ||
509 | clk_mode = CLK_GAPPED_MODE; | ||
510 | strt_len = BYTE_WIDE; | ||
511 | sync_pol = ACTIVE_HIGH; | ||
512 | val_pol = ACTIVE_HIGH; | ||
513 | err_pol = ACTIVE_HIGH; | ||
514 | sclk_rate = 0x00; | ||
515 | parity = 0x00 ; | ||
516 | data_delay = 0x00; | ||
517 | clk_delay = 0x00; | ||
518 | pclk_smooth = 0x00; | ||
519 | */ | ||
520 | reg2[0] = | ||
521 | PARALLEL + (LSB_FIRST << 1) | ||
522 | + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) | ||
523 | + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) | ||
524 | + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); | ||
525 | |||
526 | reg2[1] = 0; | ||
527 | /* sclk_rate + (parity << 2) | ||
528 | + (data_delay << 3) + (clk_delay << 4) | ||
529 | + (pclk_smooth << 5); | ||
530 | */ | ||
531 | status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); | ||
532 | if (status != 0) | ||
533 | dprintk(" %s : TS Set Error\n", __func__); | ||
534 | |||
535 | return 0; | ||
536 | |||
537 | } | ||
538 | |||
539 | static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
540 | { | ||
541 | struct si21xx_state *state = fe->demodulator_priv; | ||
542 | u8 regs_read[2]; | ||
543 | u8 reg_read; | ||
544 | u8 i; | ||
545 | u8 lock; | ||
546 | u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); | ||
547 | |||
548 | si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); | ||
549 | reg_read = 0; | ||
550 | |||
551 | for (i = 0; i < 7; ++i) | ||
552 | reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); | ||
553 | |||
554 | lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); | ||
555 | |||
556 | dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); | ||
557 | *status = 0; | ||
558 | |||
559 | if (signal > 10) | ||
560 | *status |= FE_HAS_SIGNAL; | ||
561 | |||
562 | if (lock & 0x2) | ||
563 | *status |= FE_HAS_CARRIER; | ||
564 | |||
565 | if (lock & 0x20) | ||
566 | *status |= FE_HAS_VITERBI; | ||
567 | |||
568 | if (lock & 0x40) | ||
569 | *status |= FE_HAS_SYNC; | ||
570 | |||
571 | if ((lock & 0x7b) == 0x7b) | ||
572 | *status |= FE_HAS_LOCK; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
578 | { | ||
579 | struct si21xx_state *state = fe->demodulator_priv; | ||
580 | |||
581 | /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, | ||
582 | (u8*)agclevel, 0x01);*/ | ||
583 | |||
584 | u16 signal = (3 * si21_readreg(state, 0x27) * | ||
585 | si21_readreg(state, 0x28)); | ||
586 | |||
587 | dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, | ||
588 | si21_readreg(state, 0x27), | ||
589 | si21_readreg(state, 0x28), (int) signal); | ||
590 | |||
591 | signal <<= 4; | ||
592 | *strength = signal; | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
598 | { | ||
599 | struct si21xx_state *state = fe->demodulator_priv; | ||
600 | |||
601 | dprintk("%s\n", __func__); | ||
602 | |||
603 | if (state->errmode != STATUS_BER) | ||
604 | return 0; | ||
605 | |||
606 | *ber = (si21_readreg(state, 0x1d) << 8) | | ||
607 | si21_readreg(state, 0x1e); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
613 | { | ||
614 | struct si21xx_state *state = fe->demodulator_priv; | ||
615 | |||
616 | s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | | ||
617 | si21_readreg(state, 0x25)); | ||
618 | xsnr = 3 * (xsnr - 0xa100); | ||
619 | *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; | ||
620 | |||
621 | dprintk("%s\n", __func__); | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
627 | { | ||
628 | struct si21xx_state *state = fe->demodulator_priv; | ||
629 | |||
630 | dprintk("%s\n", __func__); | ||
631 | |||
632 | if (state->errmode != STATUS_UCBLOCKS) | ||
633 | *ucblocks = 0; | ||
634 | else | ||
635 | *ucblocks = (si21_readreg(state, 0x1d) << 8) | | ||
636 | si21_readreg(state, 0x1e); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | /* initiates a channel acquisition sequence | ||
642 | using the specified symbol rate and code rate */ | ||
643 | static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, | ||
644 | fe_code_rate_t crate) | ||
645 | { | ||
646 | |||
647 | struct si21xx_state *state = fe->demodulator_priv; | ||
648 | u8 coderates[] = { | ||
649 | 0x0, 0x01, 0x02, 0x04, 0x00, | ||
650 | 0x8, 0x10, 0x20, 0x00, 0x3f | ||
651 | }; | ||
652 | |||
653 | u8 coderate_ptr; | ||
654 | int status; | ||
655 | u8 start_acq = 0x80; | ||
656 | u8 reg, regs[3]; | ||
657 | |||
658 | dprintk("%s\n", __func__); | ||
659 | |||
660 | status = PASS; | ||
661 | coderate_ptr = coderates[crate]; | ||
662 | |||
663 | si21xx_set_symbolrate(fe, symbrate); | ||
664 | |||
665 | /* write code rates to use in the Viterbi search */ | ||
666 | status |= si21_writeregs(state, | ||
667 | VIT_SRCH_CTRL_REG_1, | ||
668 | &coderate_ptr, 0x01); | ||
669 | |||
670 | /* clear acq_start bit */ | ||
671 | status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); | ||
672 | reg &= ~start_acq; | ||
673 | status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); | ||
674 | |||
675 | /* use new Carrier Frequency Offset Estimator (QuickLock) */ | ||
676 | regs[0] = 0xCB; | ||
677 | regs[1] = 0x40; | ||
678 | regs[2] = 0xCB; | ||
679 | |||
680 | status |= si21_writeregs(state, | ||
681 | TWO_DB_BNDWDTH_THRSHLD_REG, | ||
682 | ®s[0], 0x03); | ||
683 | reg = 0x56; | ||
684 | status |= si21_writeregs(state, | ||
685 | LSA_CTRL_REG_1, ®, 1); | ||
686 | reg = 0x05; | ||
687 | status |= si21_writeregs(state, | ||
688 | BLIND_SCAN_CTRL_REG, ®, 1); | ||
689 | /* start automatic acq */ | ||
690 | status |= si21_writeregs(state, | ||
691 | ACQ_CTRL_REG_2, &start_acq, 0x01); | ||
692 | |||
693 | return status; | ||
694 | } | ||
695 | |||
696 | static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
697 | { | ||
698 | dprintk("%s(..)\n", __func__); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
703 | { | ||
704 | dprintk("%s(..)\n", __func__); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int si21xx_set_frontend(struct dvb_frontend *fe, | ||
709 | struct dvb_frontend_parameters *dfp) | ||
710 | { | ||
711 | struct si21xx_state *state = fe->demodulator_priv; | ||
712 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
713 | |||
714 | /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) | ||
715 | datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ | ||
716 | |||
717 | /* in MHz */ | ||
718 | unsigned char coarse_tune_freq; | ||
719 | int fine_tune_freq; | ||
720 | unsigned char sample_rate = 0; | ||
721 | /* boolean */ | ||
722 | unsigned int inband_interferer_ind; | ||
723 | |||
724 | /* INTERMEDIATE VALUES */ | ||
725 | int icoarse_tune_freq; /* MHz */ | ||
726 | int ifine_tune_freq; /* MHz */ | ||
727 | unsigned int band_high; | ||
728 | unsigned int band_low; | ||
729 | unsigned int x1; | ||
730 | unsigned int x2; | ||
731 | int i; | ||
732 | unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = { | ||
733 | FALSE, FALSE, FALSE, FALSE, FALSE, | ||
734 | FALSE, FALSE, FALSE, FALSE, FALSE | ||
735 | }; | ||
736 | unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = { | ||
737 | FALSE, FALSE, FALSE, FALSE, FALSE, | ||
738 | FALSE, FALSE, FALSE, FALSE, FALSE | ||
739 | }; | ||
740 | |||
741 | int status; | ||
742 | |||
743 | /* allowable sample rates for ADC in MHz */ | ||
744 | int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, | ||
745 | 196, 204, 205, 206, 207 | ||
746 | }; | ||
747 | /* in MHz */ | ||
748 | int if_limit_high; | ||
749 | int if_limit_low; | ||
750 | int lnb_lo; | ||
751 | int lnb_uncertanity; | ||
752 | |||
753 | int rf_freq; | ||
754 | int data_rate; | ||
755 | unsigned char regs[4]; | ||
756 | |||
757 | dprintk("%s : FE_SET_FRONTEND\n", __func__); | ||
758 | |||
759 | if (c->delivery_system != SYS_DVBS) { | ||
760 | dprintk("%s: unsupported delivery system selected (%d)\n", | ||
761 | __func__, c->delivery_system); | ||
762 | return -EOPNOTSUPP; | ||
763 | } | ||
764 | |||
765 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) | ||
766 | inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE; | ||
767 | |||
768 | if_limit_high = -700000; | ||
769 | if_limit_low = -100000; | ||
770 | /* in MHz */ | ||
771 | lnb_lo = 0; | ||
772 | lnb_uncertanity = 0; | ||
773 | |||
774 | rf_freq = 10 * c->frequency ; | ||
775 | data_rate = c->symbol_rate / 100; | ||
776 | |||
777 | status = PASS; | ||
778 | |||
779 | band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) | ||
780 | + (data_rate * 135)) / 200; | ||
781 | |||
782 | band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) | ||
783 | + (data_rate * 135)) / 200; | ||
784 | |||
785 | |||
786 | icoarse_tune_freq = 100000 * | ||
787 | (((rf_freq - lnb_lo) - | ||
788 | (if_limit_low + if_limit_high) / 2) | ||
789 | / 100000); | ||
790 | |||
791 | ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; | ||
792 | |||
793 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
794 | x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * | ||
795 | (afs[i] * 2500) + afs[i] * 2500; | ||
796 | |||
797 | x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * | ||
798 | (afs[i] * 2500); | ||
799 | |||
800 | if (((band_low < x1) && (x1 < band_high)) || | ||
801 | ((band_low < x2) && (x2 < band_high))) | ||
802 | inband_interferer_div4[i] = TRUE; | ||
803 | |||
804 | } | ||
805 | |||
806 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
807 | x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * | ||
808 | (afs[i] * 5000) + afs[i] * 5000; | ||
809 | |||
810 | x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * | ||
811 | (afs[i] * 5000); | ||
812 | |||
813 | if (((band_low < x1) && (x1 < band_high)) || | ||
814 | ((band_low < x2) && (x2 < band_high))) | ||
815 | inband_interferer_div2[i] = TRUE; | ||
816 | } | ||
817 | |||
818 | inband_interferer_ind = TRUE; | ||
819 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) | ||
820 | inband_interferer_ind &= inband_interferer_div2[i] | | ||
821 | inband_interferer_div4[i]; | ||
822 | |||
823 | if (inband_interferer_ind) { | ||
824 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
825 | if (inband_interferer_div2[i] == FALSE) { | ||
826 | sample_rate = (u8) afs[i]; | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | } else { | ||
831 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
832 | if ((inband_interferer_div2[i] | | ||
833 | inband_interferer_div4[i]) == FALSE) { | ||
834 | sample_rate = (u8) afs[i]; | ||
835 | break; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | } | ||
840 | |||
841 | if (sample_rate > 207 || sample_rate < 192) | ||
842 | sample_rate = 200; | ||
843 | |||
844 | fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / | ||
845 | ((sample_rate) * 1000)); | ||
846 | |||
847 | coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); | ||
848 | |||
849 | regs[0] = sample_rate; | ||
850 | regs[1] = coarse_tune_freq; | ||
851 | regs[2] = fine_tune_freq & 0xFF; | ||
852 | regs[3] = fine_tune_freq >> 8 & 0xFF; | ||
853 | |||
854 | status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); | ||
855 | |||
856 | state->fs = sample_rate;/*ADC MHz*/ | ||
857 | si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | static int si21xx_sleep(struct dvb_frontend *fe) | ||
863 | { | ||
864 | struct si21xx_state *state = fe->demodulator_priv; | ||
865 | u8 regdata; | ||
866 | |||
867 | dprintk("%s\n", __func__); | ||
868 | |||
869 | si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); | ||
870 | regdata |= 1 << 6; | ||
871 | si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); | ||
872 | state->initialised = 0; | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static void si21xx_release(struct dvb_frontend *fe) | ||
878 | { | ||
879 | struct si21xx_state *state = fe->demodulator_priv; | ||
880 | |||
881 | dprintk("%s\n", __func__); | ||
882 | |||
883 | kfree(state); | ||
884 | } | ||
885 | |||
886 | static struct dvb_frontend_ops si21xx_ops = { | ||
887 | |||
888 | .info = { | ||
889 | .name = "SL SI21XX DVB-S", | ||
890 | .type = FE_QPSK, | ||
891 | .frequency_min = 950000, | ||
892 | .frequency_max = 2150000, | ||
893 | .frequency_stepsize = 125, /* kHz for QPSK frontends */ | ||
894 | .frequency_tolerance = 0, | ||
895 | .symbol_rate_min = 1000000, | ||
896 | .symbol_rate_max = 45000000, | ||
897 | .symbol_rate_tolerance = 500, /* ppm */ | ||
898 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
899 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
900 | FE_CAN_QPSK | | ||
901 | FE_CAN_FEC_AUTO | ||
902 | }, | ||
903 | |||
904 | .release = si21xx_release, | ||
905 | .init = si21xx_init, | ||
906 | .sleep = si21xx_sleep, | ||
907 | .write = si21_write, | ||
908 | .read_status = si21_read_status, | ||
909 | .read_ber = si21_read_ber, | ||
910 | .read_signal_strength = si21_read_signal_strength, | ||
911 | .read_snr = si21_read_snr, | ||
912 | .read_ucblocks = si21_read_ucblocks, | ||
913 | .diseqc_send_master_cmd = si21xx_send_diseqc_msg, | ||
914 | .diseqc_send_burst = si21xx_send_diseqc_burst, | ||
915 | .set_tone = si21xx_set_tone, | ||
916 | .set_voltage = si21xx_set_voltage, | ||
917 | |||
918 | .set_property = si21xx_set_property, | ||
919 | .get_property = si21xx_get_property, | ||
920 | .set_frontend = si21xx_set_frontend, | ||
921 | }; | ||
922 | |||
923 | struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, | ||
924 | struct i2c_adapter *i2c) | ||
925 | { | ||
926 | struct si21xx_state *state = NULL; | ||
927 | int id; | ||
928 | |||
929 | dprintk("%s\n", __func__); | ||
930 | |||
931 | /* allocate memory for the internal state */ | ||
932 | state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL); | ||
933 | if (state == NULL) | ||
934 | goto error; | ||
935 | |||
936 | /* setup the state */ | ||
937 | state->config = config; | ||
938 | state->i2c = i2c; | ||
939 | state->initialised = 0; | ||
940 | state->errmode = STATUS_BER; | ||
941 | |||
942 | /* check if the demod is there */ | ||
943 | id = si21_readreg(state, SYSTEM_MODE_REG); | ||
944 | si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ | ||
945 | msleep(200); | ||
946 | id = si21_readreg(state, 0x00); | ||
947 | |||
948 | /* register 0x00 contains: | ||
949 | 0x34 for SI2107 | ||
950 | 0x24 for SI2108 | ||
951 | 0x14 for SI2109 | ||
952 | 0x04 for SI2110 | ||
953 | */ | ||
954 | if (id != 0x04 && id != 0x14) | ||
955 | goto error; | ||
956 | |||
957 | /* create dvb_frontend */ | ||
958 | memcpy(&state->frontend.ops, &si21xx_ops, | ||
959 | sizeof(struct dvb_frontend_ops)); | ||
960 | state->frontend.demodulator_priv = state; | ||
961 | return &state->frontend; | ||
962 | |||
963 | error: | ||
964 | kfree(state); | ||
965 | return NULL; | ||
966 | } | ||
967 | EXPORT_SYMBOL(si21xx_attach); | ||
968 | |||
969 | module_param(debug, int, 0644); | ||
970 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
971 | |||
972 | MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); | ||
973 | MODULE_AUTHOR("Igor M. Liplianin"); | ||
974 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h new file mode 100644 index 000000000000..141b5b8a5f63 --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef SI21XX_H | ||
2 | #define SI21XX_H | ||
3 | |||
4 | #include <linux/dvb/frontend.h> | ||
5 | #include "dvb_frontend.h" | ||
6 | |||
7 | struct si21xx_config { | ||
8 | /* the demodulator's i2c address */ | ||
9 | u8 demod_address; | ||
10 | |||
11 | /* minimum delay before retuning */ | ||
12 | int min_delay_ms; | ||
13 | }; | ||
14 | |||
15 | #if defined(CONFIG_DVB_SI21XX) || \ | ||
16 | (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) | ||
17 | extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, | ||
18 | struct i2c_adapter *i2c); | ||
19 | #else | ||
20 | static inline struct dvb_frontend *si21xx_attach( | ||
21 | const struct si21xx_config *config, struct i2c_adapter *i2c) | ||
22 | { | ||
23 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
24 | return NULL; | ||
25 | } | ||
26 | #endif | ||
27 | |||
28 | static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val) | ||
29 | { | ||
30 | int r = 0; | ||
31 | u8 buf[] = {reg, val}; | ||
32 | if (fe->ops.write) | ||
33 | r = fe->ops.write(fe, buf, 2); | ||
34 | return r; | ||
35 | } | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 4543609e1816..559509ab4dab 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c | |||
@@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, | |||
337 | struct dvb_frontend_parameters *p) | 337 | struct dvb_frontend_parameters *p) |
338 | { | 338 | { |
339 | struct sp887x_state* state = fe->demodulator_priv; | 339 | struct sp887x_state* state = fe->demodulator_priv; |
340 | int actual_freq, err; | 340 | unsigned actual_freq; |
341 | int err; | ||
341 | u16 val, reg0xc05; | 342 | u16 val, reg0xc05; |
342 | 343 | ||
343 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && | 344 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && |
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c new file mode 100644 index 000000000000..0e2cb0df1441 --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | Driver for ST STB6000 DVBS Silicon tuner | ||
3 | |||
4 | Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
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 as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <asm/types.h> | ||
26 | |||
27 | #include "stb6000.h" | ||
28 | |||
29 | static int debug; | ||
30 | #define dprintk(args...) \ | ||
31 | do { \ | ||
32 | if (debug) \ | ||
33 | printk(KERN_DEBUG "stb6000: " args); \ | ||
34 | } while (0) | ||
35 | |||
36 | struct stb6000_priv { | ||
37 | /* i2c details */ | ||
38 | int i2c_address; | ||
39 | struct i2c_adapter *i2c; | ||
40 | u32 frequency; | ||
41 | }; | ||
42 | |||
43 | static int stb6000_release(struct dvb_frontend *fe) | ||
44 | { | ||
45 | kfree(fe->tuner_priv); | ||
46 | fe->tuner_priv = NULL; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int stb6000_sleep(struct dvb_frontend *fe) | ||
51 | { | ||
52 | struct stb6000_priv *priv = fe->tuner_priv; | ||
53 | int ret; | ||
54 | u8 buf[] = { 10, 0 }; | ||
55 | struct i2c_msg msg = { | ||
56 | .addr = priv->i2c_address, | ||
57 | .flags = 0, | ||
58 | .buf = buf, | ||
59 | .len = 2 | ||
60 | }; | ||
61 | |||
62 | dprintk("%s:\n", __func__); | ||
63 | |||
64 | if (fe->ops.i2c_gate_ctrl) | ||
65 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
66 | |||
67 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
68 | if (ret != 1) | ||
69 | dprintk("%s: i2c error\n", __func__); | ||
70 | |||
71 | if (fe->ops.i2c_gate_ctrl) | ||
72 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
73 | |||
74 | return (ret == 1) ? 0 : ret; | ||
75 | } | ||
76 | |||
77 | static int stb6000_set_params(struct dvb_frontend *fe, | ||
78 | struct dvb_frontend_parameters *params) | ||
79 | { | ||
80 | struct stb6000_priv *priv = fe->tuner_priv; | ||
81 | unsigned int n, m; | ||
82 | int ret; | ||
83 | u32 freq_mhz; | ||
84 | int bandwidth; | ||
85 | u8 buf[12]; | ||
86 | struct i2c_msg msg = { | ||
87 | .addr = priv->i2c_address, | ||
88 | .flags = 0, | ||
89 | .buf = buf, | ||
90 | .len = 12 | ||
91 | }; | ||
92 | |||
93 | dprintk("%s:\n", __func__); | ||
94 | |||
95 | freq_mhz = params->frequency / 1000; | ||
96 | bandwidth = params->u.qpsk.symbol_rate / 1000000; | ||
97 | |||
98 | if (bandwidth > 31) | ||
99 | bandwidth = 31; | ||
100 | |||
101 | if ((freq_mhz > 949) && (freq_mhz < 2151)) { | ||
102 | buf[0] = 0x01; | ||
103 | buf[1] = 0xac; | ||
104 | if (freq_mhz < 1950) | ||
105 | buf[1] = 0xaa; | ||
106 | if (freq_mhz < 1800) | ||
107 | buf[1] = 0xa8; | ||
108 | if (freq_mhz < 1650) | ||
109 | buf[1] = 0xa6; | ||
110 | if (freq_mhz < 1530) | ||
111 | buf[1] = 0xa5; | ||
112 | if (freq_mhz < 1470) | ||
113 | buf[1] = 0xa4; | ||
114 | if (freq_mhz < 1370) | ||
115 | buf[1] = 0xa2; | ||
116 | if (freq_mhz < 1300) | ||
117 | buf[1] = 0xa1; | ||
118 | if (freq_mhz < 1200) | ||
119 | buf[1] = 0xa0; | ||
120 | if (freq_mhz < 1075) | ||
121 | buf[1] = 0xbc; | ||
122 | if (freq_mhz < 1000) | ||
123 | buf[1] = 0xba; | ||
124 | if (freq_mhz < 1075) { | ||
125 | n = freq_mhz / 8; /* vco=lo*4 */ | ||
126 | m = 2; | ||
127 | } else { | ||
128 | n = freq_mhz / 16; /* vco=lo*2 */ | ||
129 | m = 1; | ||
130 | } | ||
131 | buf[2] = n >> 1; | ||
132 | buf[3] = (unsigned char)(((n & 1) << 7) | | ||
133 | (m * freq_mhz - n * 16) | 0x60); | ||
134 | buf[4] = 0x04; | ||
135 | buf[5] = 0x0e; | ||
136 | |||
137 | buf[6] = (unsigned char)(bandwidth); | ||
138 | |||
139 | buf[7] = 0xd8; | ||
140 | buf[8] = 0xd0; | ||
141 | buf[9] = 0x50; | ||
142 | buf[10] = 0xeb; | ||
143 | buf[11] = 0x4f; | ||
144 | |||
145 | if (fe->ops.i2c_gate_ctrl) | ||
146 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
147 | |||
148 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
149 | if (ret != 1) | ||
150 | dprintk("%s: i2c error\n", __func__); | ||
151 | |||
152 | udelay(10); | ||
153 | if (fe->ops.i2c_gate_ctrl) | ||
154 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
155 | |||
156 | buf[0] = 0x07; | ||
157 | buf[1] = 0xdf; | ||
158 | buf[2] = 0xd0; | ||
159 | buf[3] = 0x50; | ||
160 | buf[4] = 0xfb; | ||
161 | msg.len = 5; | ||
162 | |||
163 | if (fe->ops.i2c_gate_ctrl) | ||
164 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
165 | |||
166 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
167 | if (ret != 1) | ||
168 | dprintk("%s: i2c error\n", __func__); | ||
169 | |||
170 | udelay(10); | ||
171 | if (fe->ops.i2c_gate_ctrl) | ||
172 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
173 | |||
174 | priv->frequency = freq_mhz * 1000; | ||
175 | |||
176 | return (ret == 1) ? 0 : ret; | ||
177 | } | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
182 | { | ||
183 | struct stb6000_priv *priv = fe->tuner_priv; | ||
184 | *frequency = priv->frequency; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct dvb_tuner_ops stb6000_tuner_ops = { | ||
189 | .info = { | ||
190 | .name = "ST STB6000", | ||
191 | .frequency_min = 950000, | ||
192 | .frequency_max = 2150000 | ||
193 | }, | ||
194 | .release = stb6000_release, | ||
195 | .sleep = stb6000_sleep, | ||
196 | .set_params = stb6000_set_params, | ||
197 | .get_frequency = stb6000_get_frequency, | ||
198 | }; | ||
199 | |||
200 | struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, | ||
201 | struct i2c_adapter *i2c) | ||
202 | { | ||
203 | struct stb6000_priv *priv = NULL; | ||
204 | u8 b0[] = { 0 }; | ||
205 | u8 b1[] = { 0, 0 }; | ||
206 | struct i2c_msg msg[2] = { | ||
207 | { | ||
208 | .addr = addr, | ||
209 | .flags = 0, | ||
210 | .buf = b0, | ||
211 | .len = 0 | ||
212 | }, { | ||
213 | .addr = addr, | ||
214 | .flags = I2C_M_RD, | ||
215 | .buf = b1, | ||
216 | .len = 2 | ||
217 | } | ||
218 | }; | ||
219 | int ret; | ||
220 | |||
221 | dprintk("%s:\n", __func__); | ||
222 | |||
223 | if (fe->ops.i2c_gate_ctrl) | ||
224 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
225 | |||
226 | /* is some i2c device here ? */ | ||
227 | ret = i2c_transfer(i2c, msg, 2); | ||
228 | if (fe->ops.i2c_gate_ctrl) | ||
229 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
230 | |||
231 | if (ret != 2) | ||
232 | return NULL; | ||
233 | |||
234 | priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); | ||
235 | if (priv == NULL) | ||
236 | return NULL; | ||
237 | |||
238 | priv->i2c_address = addr; | ||
239 | priv->i2c = i2c; | ||
240 | |||
241 | memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, | ||
242 | sizeof(struct dvb_tuner_ops)); | ||
243 | |||
244 | fe->tuner_priv = priv; | ||
245 | |||
246 | return fe; | ||
247 | } | ||
248 | EXPORT_SYMBOL(stb6000_attach); | ||
249 | |||
250 | module_param(debug, int, 0644); | ||
251 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
252 | |||
253 | MODULE_DESCRIPTION("DVB STB6000 driver"); | ||
254 | MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>"); | ||
255 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h new file mode 100644 index 000000000000..7be479c22d5b --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | Driver for ST stb6000 DVBS Silicon tuner | ||
3 | |||
4 | Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
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 as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef __DVB_STB6000_H__ | ||
24 | #define __DVB_STB6000_H__ | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include "dvb_frontend.h" | ||
28 | |||
29 | /** | ||
30 | * Attach a stb6000 tuner to the supplied frontend structure. | ||
31 | * | ||
32 | * @param fe Frontend to attach to. | ||
33 | * @param addr i2c address of the tuner. | ||
34 | * @param i2c i2c adapter to use. | ||
35 | * @return FE pointer on success, NULL on failure. | ||
36 | */ | ||
37 | #if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ | ||
38 | && defined(MODULE)) | ||
39 | extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, | ||
40 | struct i2c_adapter *i2c); | ||
41 | #else | ||
42 | static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, | ||
43 | int addr, | ||
44 | struct i2c_adapter *i2c) | ||
45 | { | ||
46 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
47 | return NULL; | ||
48 | } | ||
49 | #endif /* CONFIG_DVB_STB6000 */ | ||
50 | |||
51 | #endif /* __DVB_STB6000_H__ */ | ||
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c new file mode 100644 index 000000000000..ff1194de34c0 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /* | ||
2 | Driver for ST STV0288 demodulator | ||
3 | Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de | ||
4 | for Reel Multimedia | ||
5 | Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com> | ||
6 | Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> | ||
7 | Removed stb6000 specific tuner code and revised some | ||
8 | procedures. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/jiffies.h> | ||
32 | #include <asm/div64.h> | ||
33 | |||
34 | #include "dvb_frontend.h" | ||
35 | #include "stv0288.h" | ||
36 | |||
37 | struct stv0288_state { | ||
38 | struct i2c_adapter *i2c; | ||
39 | const struct stv0288_config *config; | ||
40 | struct dvb_frontend frontend; | ||
41 | |||
42 | u8 initialised:1; | ||
43 | u32 tuner_frequency; | ||
44 | u32 symbol_rate; | ||
45 | fe_code_rate_t fec_inner; | ||
46 | int errmode; | ||
47 | }; | ||
48 | |||
49 | #define STATUS_BER 0 | ||
50 | #define STATUS_UCBLOCKS 1 | ||
51 | |||
52 | static int debug; | ||
53 | static int debug_legacy_dish_switch; | ||
54 | #define dprintk(args...) \ | ||
55 | do { \ | ||
56 | if (debug) \ | ||
57 | printk(KERN_DEBUG "stv0288: " args); \ | ||
58 | } while (0) | ||
59 | |||
60 | |||
61 | static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) | ||
62 | { | ||
63 | int ret; | ||
64 | u8 buf[] = { reg, data }; | ||
65 | struct i2c_msg msg = { | ||
66 | .addr = state->config->demod_address, | ||
67 | .flags = 0, | ||
68 | .buf = buf, | ||
69 | .len = 2 | ||
70 | }; | ||
71 | |||
72 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
73 | |||
74 | if (ret != 1) | ||
75 | dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " | ||
76 | "ret == %i)\n", __func__, reg, data, ret); | ||
77 | |||
78 | return (ret != 1) ? -EREMOTEIO : 0; | ||
79 | } | ||
80 | |||
81 | static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len) | ||
82 | { | ||
83 | struct stv0288_state *state = fe->demodulator_priv; | ||
84 | |||
85 | if (len != 2) | ||
86 | return -EINVAL; | ||
87 | |||
88 | return stv0288_writeregI(state, buf[0], buf[1]); | ||
89 | } | ||
90 | |||
91 | static u8 stv0288_readreg(struct stv0288_state *state, u8 reg) | ||
92 | { | ||
93 | int ret; | ||
94 | u8 b0[] = { reg }; | ||
95 | u8 b1[] = { 0 }; | ||
96 | struct i2c_msg msg[] = { | ||
97 | { | ||
98 | .addr = state->config->demod_address, | ||
99 | .flags = 0, | ||
100 | .buf = b0, | ||
101 | .len = 1 | ||
102 | }, { | ||
103 | .addr = state->config->demod_address, | ||
104 | .flags = I2C_M_RD, | ||
105 | .buf = b1, | ||
106 | .len = 1 | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | ret = i2c_transfer(state->i2c, msg, 2); | ||
111 | |||
112 | if (ret != 2) | ||
113 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
114 | __func__, reg, ret); | ||
115 | |||
116 | return b1[0]; | ||
117 | } | ||
118 | |||
119 | static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) | ||
120 | { | ||
121 | struct stv0288_state *state = fe->demodulator_priv; | ||
122 | unsigned int temp; | ||
123 | unsigned char b[3]; | ||
124 | |||
125 | if ((srate < 1000000) || (srate > 45000000)) | ||
126 | return -EINVAL; | ||
127 | |||
128 | temp = (unsigned int)srate / 1000; | ||
129 | |||
130 | temp = temp * 32768; | ||
131 | temp = temp / 25; | ||
132 | temp = temp / 125; | ||
133 | b[0] = (unsigned char)((temp >> 12) & 0xff); | ||
134 | b[1] = (unsigned char)((temp >> 4) & 0xff); | ||
135 | b[2] = (unsigned char)((temp << 4) & 0xf0); | ||
136 | stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ | ||
137 | stv0288_writeregI(state, 0x29, 0); /* SFRM */ | ||
138 | stv0288_writeregI(state, 0x2a, 0); /* SFRL */ | ||
139 | |||
140 | stv0288_writeregI(state, 0x28, b[0]); | ||
141 | stv0288_writeregI(state, 0x29, b[1]); | ||
142 | stv0288_writeregI(state, 0x2a, b[2]); | ||
143 | dprintk("stv0288: stv0288_set_symbolrate\n"); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, | ||
149 | struct dvb_diseqc_master_cmd *m) | ||
150 | { | ||
151 | struct stv0288_state *state = fe->demodulator_priv; | ||
152 | |||
153 | int i; | ||
154 | |||
155 | dprintk("%s\n", __func__); | ||
156 | |||
157 | stv0288_writeregI(state, 0x09, 0); | ||
158 | msleep(30); | ||
159 | stv0288_writeregI(state, 0x05, 0x16); | ||
160 | |||
161 | for (i = 0; i < m->msg_len; i++) { | ||
162 | if (stv0288_writeregI(state, 0x06, m->msg[i])) | ||
163 | return -EREMOTEIO; | ||
164 | msleep(12); | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, | ||
171 | fe_sec_mini_cmd_t burst) | ||
172 | { | ||
173 | struct stv0288_state *state = fe->demodulator_priv; | ||
174 | |||
175 | dprintk("%s\n", __func__); | ||
176 | |||
177 | if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */ | ||
178 | return -EREMOTEIO; | ||
179 | |||
180 | if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) | ||
181 | return -EREMOTEIO; | ||
182 | |||
183 | if (stv0288_writeregI(state, 0x06, 0x12)) | ||
184 | return -EREMOTEIO; | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
190 | { | ||
191 | struct stv0288_state *state = fe->demodulator_priv; | ||
192 | |||
193 | switch (tone) { | ||
194 | case SEC_TONE_ON: | ||
195 | if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */ | ||
196 | return -EREMOTEIO; | ||
197 | return stv0288_writeregI(state, 0x06, 0xff); | ||
198 | |||
199 | case SEC_TONE_OFF: | ||
200 | if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */ | ||
201 | return -EREMOTEIO; | ||
202 | return stv0288_writeregI(state, 0x06, 0x00); | ||
203 | |||
204 | default: | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | static u8 stv0288_inittab[] = { | ||
210 | 0x01, 0x15, | ||
211 | 0x02, 0x20, | ||
212 | 0x09, 0x0, | ||
213 | 0x0a, 0x4, | ||
214 | 0x0b, 0x0, | ||
215 | 0x0c, 0x0, | ||
216 | 0x0d, 0x0, | ||
217 | 0x0e, 0xd4, | ||
218 | 0x0f, 0x30, | ||
219 | 0x11, 0x80, | ||
220 | 0x12, 0x03, | ||
221 | 0x13, 0x48, | ||
222 | 0x14, 0x84, | ||
223 | 0x15, 0x45, | ||
224 | 0x16, 0xb7, | ||
225 | 0x17, 0x9c, | ||
226 | 0x18, 0x0, | ||
227 | 0x19, 0xa6, | ||
228 | 0x1a, 0x88, | ||
229 | 0x1b, 0x8f, | ||
230 | 0x1c, 0xf0, | ||
231 | 0x20, 0x0b, | ||
232 | 0x21, 0x54, | ||
233 | 0x22, 0x0, | ||
234 | 0x23, 0x0, | ||
235 | 0x2b, 0xff, | ||
236 | 0x2c, 0xf7, | ||
237 | 0x30, 0x0, | ||
238 | 0x31, 0x1e, | ||
239 | 0x32, 0x14, | ||
240 | 0x33, 0x0f, | ||
241 | 0x34, 0x09, | ||
242 | 0x35, 0x0c, | ||
243 | 0x36, 0x05, | ||
244 | 0x37, 0x2f, | ||
245 | 0x38, 0x16, | ||
246 | 0x39, 0xbe, | ||
247 | 0x3a, 0x0, | ||
248 | 0x3b, 0x13, | ||
249 | 0x3c, 0x11, | ||
250 | 0x3d, 0x30, | ||
251 | 0x40, 0x63, | ||
252 | 0x41, 0x04, | ||
253 | 0x42, 0x60, | ||
254 | 0x43, 0x00, | ||
255 | 0x44, 0x00, | ||
256 | 0x45, 0x00, | ||
257 | 0x46, 0x00, | ||
258 | 0x47, 0x00, | ||
259 | 0x4a, 0x00, | ||
260 | 0x50, 0x10, | ||
261 | 0x51, 0x38, | ||
262 | 0x52, 0x21, | ||
263 | 0x58, 0x54, | ||
264 | 0x59, 0x86, | ||
265 | 0x5a, 0x0, | ||
266 | 0x5b, 0x9b, | ||
267 | 0x5c, 0x08, | ||
268 | 0x5d, 0x7f, | ||
269 | 0x5e, 0x0, | ||
270 | 0x5f, 0xff, | ||
271 | 0x70, 0x0, | ||
272 | 0x71, 0x0, | ||
273 | 0x72, 0x0, | ||
274 | 0x74, 0x0, | ||
275 | 0x75, 0x0, | ||
276 | 0x76, 0x0, | ||
277 | 0x81, 0x0, | ||
278 | 0x82, 0x3f, | ||
279 | 0x83, 0x3f, | ||
280 | 0x84, 0x0, | ||
281 | 0x85, 0x0, | ||
282 | 0x88, 0x0, | ||
283 | 0x89, 0x0, | ||
284 | 0x8a, 0x0, | ||
285 | 0x8b, 0x0, | ||
286 | 0x8c, 0x0, | ||
287 | 0x90, 0x0, | ||
288 | 0x91, 0x0, | ||
289 | 0x92, 0x0, | ||
290 | 0x93, 0x0, | ||
291 | 0x94, 0x1c, | ||
292 | 0x97, 0x0, | ||
293 | 0xa0, 0x48, | ||
294 | 0xa1, 0x0, | ||
295 | 0xb0, 0xb8, | ||
296 | 0xb1, 0x3a, | ||
297 | 0xb2, 0x10, | ||
298 | 0xb3, 0x82, | ||
299 | 0xb4, 0x80, | ||
300 | 0xb5, 0x82, | ||
301 | 0xb6, 0x82, | ||
302 | 0xb7, 0x82, | ||
303 | 0xb8, 0x20, | ||
304 | 0xb9, 0x0, | ||
305 | 0xf0, 0x0, | ||
306 | 0xf1, 0x0, | ||
307 | 0xf2, 0xc0, | ||
308 | 0x51, 0x36, | ||
309 | 0x52, 0x09, | ||
310 | 0x53, 0x94, | ||
311 | 0x54, 0x62, | ||
312 | 0x55, 0x29, | ||
313 | 0x56, 0x64, | ||
314 | 0x57, 0x2b, | ||
315 | 0xff, 0xff, | ||
316 | }; | ||
317 | |||
318 | static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) | ||
319 | { | ||
320 | dprintk("%s: %s\n", __func__, | ||
321 | volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
322 | volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int stv0288_init(struct dvb_frontend *fe) | ||
328 | { | ||
329 | struct stv0288_state *state = fe->demodulator_priv; | ||
330 | int i; | ||
331 | u8 reg; | ||
332 | u8 val; | ||
333 | |||
334 | dprintk("stv0288: init chip\n"); | ||
335 | stv0288_writeregI(state, 0x41, 0x04); | ||
336 | msleep(50); | ||
337 | |||
338 | /* we have default inittab */ | ||
339 | if (state->config->inittab == NULL) { | ||
340 | for (i = 0; !(stv0288_inittab[i] == 0xff && | ||
341 | stv0288_inittab[i + 1] == 0xff); i += 2) | ||
342 | stv0288_writeregI(state, stv0288_inittab[i], | ||
343 | stv0288_inittab[i + 1]); | ||
344 | } else { | ||
345 | for (i = 0; ; i += 2) { | ||
346 | reg = state->config->inittab[i]; | ||
347 | val = state->config->inittab[i+1]; | ||
348 | if (reg == 0xff && val == 0xff) | ||
349 | break; | ||
350 | stv0288_writeregI(state, reg, val); | ||
351 | } | ||
352 | } | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
357 | { | ||
358 | struct stv0288_state *state = fe->demodulator_priv; | ||
359 | |||
360 | u8 sync = stv0288_readreg(state, 0x24); | ||
361 | if (sync == 255) | ||
362 | sync = 0; | ||
363 | |||
364 | dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); | ||
365 | |||
366 | *status = 0; | ||
367 | |||
368 | if ((sync & 0x08) == 0x08) { | ||
369 | *status |= FE_HAS_LOCK; | ||
370 | dprintk("stv0288 has locked\n"); | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
377 | { | ||
378 | struct stv0288_state *state = fe->demodulator_priv; | ||
379 | |||
380 | if (state->errmode != STATUS_BER) | ||
381 | return 0; | ||
382 | *ber = (stv0288_readreg(state, 0x26) << 8) | | ||
383 | stv0288_readreg(state, 0x27); | ||
384 | dprintk("stv0288_read_ber %d\n", *ber); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | |||
390 | static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
391 | { | ||
392 | struct stv0288_state *state = fe->demodulator_priv; | ||
393 | |||
394 | s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); | ||
395 | |||
396 | |||
397 | signal = signal * 5 / 4; | ||
398 | *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; | ||
399 | dprintk("stv0288_read_signal_strength %d\n", *strength); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | static int stv0288_sleep(struct dvb_frontend *fe) | ||
404 | { | ||
405 | struct stv0288_state *state = fe->demodulator_priv; | ||
406 | |||
407 | stv0288_writeregI(state, 0x41, 0x84); | ||
408 | state->initialised = 0; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
413 | { | ||
414 | struct stv0288_state *state = fe->demodulator_priv; | ||
415 | |||
416 | s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) | ||
417 | | stv0288_readreg(state, 0x2e)); | ||
418 | xsnr = 3 * (xsnr - 0xa100); | ||
419 | *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; | ||
420 | dprintk("stv0288_read_snr %d\n", *snr); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
426 | { | ||
427 | struct stv0288_state *state = fe->demodulator_priv; | ||
428 | |||
429 | if (state->errmode != STATUS_BER) | ||
430 | return 0; | ||
431 | *ucblocks = (stv0288_readreg(state, 0x26) << 8) | | ||
432 | stv0288_readreg(state, 0x27); | ||
433 | dprintk("stv0288_read_ber %d\n", *ucblocks); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
439 | { | ||
440 | dprintk("%s(..)\n", __func__); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
445 | { | ||
446 | dprintk("%s(..)\n", __func__); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int stv0288_set_frontend(struct dvb_frontend *fe, | ||
451 | struct dvb_frontend_parameters *dfp) | ||
452 | { | ||
453 | struct stv0288_state *state = fe->demodulator_priv; | ||
454 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
455 | |||
456 | char tm; | ||
457 | unsigned char tda[3]; | ||
458 | |||
459 | dprintk("%s : FE_SET_FRONTEND\n", __func__); | ||
460 | |||
461 | if (c->delivery_system != SYS_DVBS) { | ||
462 | dprintk("%s: unsupported delivery " | ||
463 | "system selected (%d)\n", | ||
464 | __func__, c->delivery_system); | ||
465 | return -EOPNOTSUPP; | ||
466 | } | ||
467 | |||
468 | if (state->config->set_ts_params) | ||
469 | state->config->set_ts_params(fe, 0); | ||
470 | |||
471 | /* only frequency & symbol_rate are used for tuner*/ | ||
472 | dfp->frequency = c->frequency; | ||
473 | dfp->u.qpsk.symbol_rate = c->symbol_rate; | ||
474 | if (fe->ops.tuner_ops.set_params) { | ||
475 | fe->ops.tuner_ops.set_params(fe, dfp); | ||
476 | if (fe->ops.i2c_gate_ctrl) | ||
477 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
478 | } | ||
479 | |||
480 | udelay(10); | ||
481 | stv0288_set_symbolrate(fe, c->symbol_rate); | ||
482 | /* Carrier lock control register */ | ||
483 | stv0288_writeregI(state, 0x15, 0xc5); | ||
484 | |||
485 | tda[0] = 0x2b; /* CFRM */ | ||
486 | tda[2] = 0x0; /* CFRL */ | ||
487 | for (tm = -6; tm < 7;) { | ||
488 | /* Viterbi status */ | ||
489 | if (stv0288_readreg(state, 0x24) & 0x80) | ||
490 | break; | ||
491 | |||
492 | tda[2] += 40; | ||
493 | if (tda[2] < 40) | ||
494 | tm++; | ||
495 | tda[1] = (unsigned char)tm; | ||
496 | stv0288_writeregI(state, 0x2b, tda[1]); | ||
497 | stv0288_writeregI(state, 0x2c, tda[2]); | ||
498 | udelay(30); | ||
499 | } | ||
500 | |||
501 | state->tuner_frequency = c->frequency; | ||
502 | state->fec_inner = FEC_AUTO; | ||
503 | state->symbol_rate = c->symbol_rate; | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
509 | { | ||
510 | struct stv0288_state *state = fe->demodulator_priv; | ||
511 | |||
512 | if (enable) | ||
513 | stv0288_writeregI(state, 0x01, 0xb5); | ||
514 | else | ||
515 | stv0288_writeregI(state, 0x01, 0x35); | ||
516 | |||
517 | udelay(1); | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static void stv0288_release(struct dvb_frontend *fe) | ||
523 | { | ||
524 | struct stv0288_state *state = fe->demodulator_priv; | ||
525 | kfree(state); | ||
526 | } | ||
527 | |||
528 | static struct dvb_frontend_ops stv0288_ops = { | ||
529 | |||
530 | .info = { | ||
531 | .name = "ST STV0288 DVB-S", | ||
532 | .type = FE_QPSK, | ||
533 | .frequency_min = 950000, | ||
534 | .frequency_max = 2150000, | ||
535 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | ||
536 | .frequency_tolerance = 0, | ||
537 | .symbol_rate_min = 1000000, | ||
538 | .symbol_rate_max = 45000000, | ||
539 | .symbol_rate_tolerance = 500, /* ppm */ | ||
540 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
541 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
542 | FE_CAN_QPSK | | ||
543 | FE_CAN_FEC_AUTO | ||
544 | }, | ||
545 | |||
546 | .release = stv0288_release, | ||
547 | .init = stv0288_init, | ||
548 | .sleep = stv0288_sleep, | ||
549 | .write = stv0288_write, | ||
550 | .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, | ||
551 | .read_status = stv0288_read_status, | ||
552 | .read_ber = stv0288_read_ber, | ||
553 | .read_signal_strength = stv0288_read_signal_strength, | ||
554 | .read_snr = stv0288_read_snr, | ||
555 | .read_ucblocks = stv0288_read_ucblocks, | ||
556 | .diseqc_send_master_cmd = stv0288_send_diseqc_msg, | ||
557 | .diseqc_send_burst = stv0288_send_diseqc_burst, | ||
558 | .set_tone = stv0288_set_tone, | ||
559 | .set_voltage = stv0288_set_voltage, | ||
560 | |||
561 | .set_property = stv0288_set_property, | ||
562 | .get_property = stv0288_get_property, | ||
563 | .set_frontend = stv0288_set_frontend, | ||
564 | }; | ||
565 | |||
566 | struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
567 | struct i2c_adapter *i2c) | ||
568 | { | ||
569 | struct stv0288_state *state = NULL; | ||
570 | int id; | ||
571 | |||
572 | /* allocate memory for the internal state */ | ||
573 | state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL); | ||
574 | if (state == NULL) | ||
575 | goto error; | ||
576 | |||
577 | /* setup the state */ | ||
578 | state->config = config; | ||
579 | state->i2c = i2c; | ||
580 | state->initialised = 0; | ||
581 | state->tuner_frequency = 0; | ||
582 | state->symbol_rate = 0; | ||
583 | state->fec_inner = 0; | ||
584 | state->errmode = STATUS_BER; | ||
585 | |||
586 | stv0288_writeregI(state, 0x41, 0x04); | ||
587 | msleep(200); | ||
588 | id = stv0288_readreg(state, 0x00); | ||
589 | dprintk("stv0288 id %x\n", id); | ||
590 | |||
591 | /* register 0x00 contains 0x11 for STV0288 */ | ||
592 | if (id != 0x11) | ||
593 | goto error; | ||
594 | |||
595 | /* create dvb_frontend */ | ||
596 | memcpy(&state->frontend.ops, &stv0288_ops, | ||
597 | sizeof(struct dvb_frontend_ops)); | ||
598 | state->frontend.demodulator_priv = state; | ||
599 | return &state->frontend; | ||
600 | |||
601 | error: | ||
602 | kfree(state); | ||
603 | |||
604 | return NULL; | ||
605 | } | ||
606 | EXPORT_SYMBOL(stv0288_attach); | ||
607 | |||
608 | module_param(debug_legacy_dish_switch, int, 0444); | ||
609 | MODULE_PARM_DESC(debug_legacy_dish_switch, | ||
610 | "Enable timing analysis for Dish Network legacy switches"); | ||
611 | |||
612 | module_param(debug, int, 0644); | ||
613 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
614 | |||
615 | MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); | ||
616 | MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); | ||
617 | MODULE_LICENSE("GPL"); | ||
618 | |||
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h new file mode 100644 index 000000000000..f2b53db0606d --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | Driver for ST STV0288 demodulator | ||
3 | |||
4 | Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de | ||
5 | for Reel Multimedia | ||
6 | Copyright (C) 2008 TurboSight.com, <bob@turbosight.com> | ||
7 | Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> | ||
8 | Removed stb6000 specific tuner code and revised some | ||
9 | procedures. | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | |||
25 | */ | ||
26 | |||
27 | #ifndef STV0288_H | ||
28 | #define STV0288_H | ||
29 | |||
30 | #include <linux/dvb/frontend.h> | ||
31 | #include "dvb_frontend.h" | ||
32 | |||
33 | struct stv0288_config { | ||
34 | /* the demodulator's i2c address */ | ||
35 | u8 demod_address; | ||
36 | |||
37 | u8* inittab; | ||
38 | |||
39 | /* minimum delay before retuning */ | ||
40 | int min_delay_ms; | ||
41 | |||
42 | int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); | ||
43 | }; | ||
44 | |||
45 | #if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ | ||
46 | defined(MODULE)) | ||
47 | extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
48 | struct i2c_adapter *i2c); | ||
49 | #else | ||
50 | static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
51 | struct i2c_adapter *i2c) | ||
52 | { | ||
53 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
54 | return NULL; | ||
55 | } | ||
56 | #endif /* CONFIG_DVB_STV0288 */ | ||
57 | |||
58 | static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val) | ||
59 | { | ||
60 | int r = 0; | ||
61 | u8 buf[] = { reg, val }; | ||
62 | if (fe->ops.write) | ||
63 | r = fe->ops.write(fe, buf, 2); | ||
64 | return r; | ||
65 | } | ||
66 | |||
67 | #endif /* STV0288_H */ | ||
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 35435bef8e79..6c1cb1973c6e 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c | |||
@@ -559,6 +559,8 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par | |||
559 | int invval = 0; | 559 | int invval = 0; |
560 | 560 | ||
561 | dprintk ("%s : FE_SET_FRONTEND\n", __func__); | 561 | dprintk ("%s : FE_SET_FRONTEND\n", __func__); |
562 | if (state->config->set_ts_params) | ||
563 | state->config->set_ts_params(fe, 0); | ||
562 | 564 | ||
563 | // set the inversion | 565 | // set the inversion |
564 | if (p->inversion == INVERSION_OFF) invval = 0; | 566 | if (p->inversion == INVERSION_OFF) invval = 0; |
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 3282f43022f5..0fd96e22b650 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h | |||
@@ -89,15 +89,18 @@ struct stv0299_config | |||
89 | int min_delay_ms; | 89 | int min_delay_ms; |
90 | 90 | ||
91 | /* Set the symbol rate */ | 91 | /* Set the symbol rate */ |
92 | int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); | 92 | int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio); |
93 | |||
94 | /* Set device param to start dma */ | ||
95 | int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); | ||
93 | }; | 96 | }; |
94 | 97 | ||
95 | #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) | 98 | #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) |
96 | extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | 99 | extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, |
97 | struct i2c_adapter* i2c); | 100 | struct i2c_adapter *i2c); |
98 | #else | 101 | #else |
99 | static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | 102 | static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, |
100 | struct i2c_adapter* i2c) | 103 | struct i2c_adapter *i2c) |
101 | { | 104 | { |
102 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 105 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
103 | return NULL; | 106 | return NULL; |
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h new file mode 100644 index 000000000000..51f170678650 --- /dev/null +++ b/drivers/media/dvb/frontends/tdhd1.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * tdhd1.h - ALPS TDHD1-204A tuner support | ||
3 | * | ||
4 | * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2 | ||
10 | * of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
21 | * | ||
22 | * | ||
23 | * The project's page is at http://www.linuxtv.org | ||
24 | */ | ||
25 | |||
26 | #ifndef TDHD1_H | ||
27 | #define TDHD1_H | ||
28 | |||
29 | #include "tda1004x.h" | ||
30 | |||
31 | static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); | ||
32 | |||
33 | static struct tda1004x_config alps_tdhd1_204a_config = { | ||
34 | .demod_address = 0x8, | ||
35 | .invert = 1, | ||
36 | .invert_oclk = 0, | ||
37 | .xtal_freq = TDA10046_XTAL_4M, | ||
38 | .agc_config = TDA10046_AGC_DEFAULT, | ||
39 | .if_freq = TDA10046_FREQ_3617, | ||
40 | .request_firmware = alps_tdhd1_204_request_firmware | ||
41 | }; | ||
42 | |||
43 | static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
44 | { | ||
45 | struct i2c_adapter *i2c = fe->tuner_priv; | ||
46 | u8 data[4]; | ||
47 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
48 | u32 div; | ||
49 | |||
50 | div = (params->frequency + 36166666) / 166666; | ||
51 | |||
52 | data[0] = (div >> 8) & 0x7f; | ||
53 | data[1] = div & 0xff; | ||
54 | data[2] = 0x85; | ||
55 | |||
56 | if (params->frequency >= 174000000 && params->frequency <= 230000000) | ||
57 | data[3] = 0x02; | ||
58 | else if (params->frequency >= 470000000 && params->frequency <= 823000000) | ||
59 | data[3] = 0x0C; | ||
60 | else if (params->frequency > 823000000 && params->frequency <= 862000000) | ||
61 | data[3] = 0x8C; | ||
62 | else | ||
63 | return -EINVAL; | ||
64 | |||
65 | if (fe->ops.i2c_gate_ctrl) | ||
66 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
67 | if (i2c_transfer(i2c, &msg, 1) != 1) | ||
68 | return -EIO; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | #endif /* TDHD1_H */ | ||