Merge remote-tracking branch 'asoc/fix/intel' into asoc-linus
[deliverable/linux.git] / drivers / media / dvb-frontends / ves1820.c
CommitLineData
1da177e4
LT
1/*
2 VES1820 - Single Chip Cable Channel Receiver driver module
3
4 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
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
1da177e4
LT
21#include <linux/delay.h>
22#include <linux/errno.h>
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/string.h>
27#include <linux/slab.h>
28#include <asm/div64.h>
29
30#include "dvb_frontend.h"
31#include "ves1820.h"
32
33
34
35struct ves1820_state {
36 struct i2c_adapter* i2c;
1da177e4
LT
37 /* configuration settings */
38 const struct ves1820_config* config;
39 struct dvb_frontend frontend;
40
41 /* private demodulator data */
42 u8 reg0;
43 u8 pwm;
44};
45
46
47static int verbose;
48
49static u8 ves1820_inittab[] = {
4a3625b2 50 0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
1da177e4
LT
51 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
52 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
54 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x40
57};
58
59static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
60{
61 u8 buf[] = { 0x00, reg, data };
62 struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
63 int ret;
64
65 ret = i2c_transfer(state->i2c, &msg, 1);
66
67 if (ret != 1)
11645cc3 68 printk("ves1820: %s(): writereg error (reg == 0x%02x, "
271ddbf7 69 "val == 0x%02x, ret == %i)\n", __func__, reg, data, ret);
1da177e4 70
1da177e4
LT
71 return (ret != 1) ? -EREMOTEIO : 0;
72}
73
74static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
75{
76 u8 b0[] = { 0x00, reg };
77 u8 b1[] = { 0 };
78 struct i2c_msg msg[] = {
79 {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
80 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
81 };
82 int ret;
83
84 ret = i2c_transfer(state->i2c, msg, 2);
85
86 if (ret != 2)
11645cc3 87 printk("ves1820: %s(): readreg error (reg == 0x%02x, "
271ddbf7 88 "ret == %i)\n", __func__, reg, ret);
1da177e4
LT
89
90 return b1[0];
91}
92
93static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
94{
95 reg0 |= state->reg0 & 0x62;
96
97 if (INVERSION_ON == inversion) {
98 if (!state->config->invert) reg0 |= 0x20;
99 else reg0 &= ~0x20;
100 } else if (INVERSION_OFF == inversion) {
101 if (!state->config->invert) reg0 &= ~0x20;
102 else reg0 |= 0x20;
103 }
104
105 ves1820_writereg(state, 0x00, reg0 & 0xfe);
106 ves1820_writereg(state, 0x00, reg0 | 0x01);
107
108 state->reg0 = reg0;
109
110 return 0;
111}
112
113static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
114{
115 s32 BDR;
116 s32 BDRI;
117 s16 SFIL = 0;
118 u16 NDEC = 0;
119 u32 ratio;
120 u32 fin;
121 u32 tmp;
122 u64 fptmp;
123 u64 fpxin;
124
125 if (symbolrate > state->config->xin / 2)
126 symbolrate = state->config->xin / 2;
127
128 if (symbolrate < 500000)
129 symbolrate = 500000;
130
131 if (symbolrate < state->config->xin / 16)
132 NDEC = 1;
133 if (symbolrate < state->config->xin / 32)
134 NDEC = 2;
135 if (symbolrate < state->config->xin / 64)
136 NDEC = 3;
137
138 /* yeuch! */
139 fpxin = state->config->xin * 10;
140 fptmp = fpxin; do_div(fptmp, 123);
48063a75 141 if (symbolrate < fptmp)
1da177e4
LT
142 SFIL = 1;
143 fptmp = fpxin; do_div(fptmp, 160);
48063a75 144 if (symbolrate < fptmp)
1da177e4
LT
145 SFIL = 0;
146 fptmp = fpxin; do_div(fptmp, 246);
48063a75 147 if (symbolrate < fptmp)
1da177e4
LT
148 SFIL = 1;
149 fptmp = fpxin; do_div(fptmp, 320);
48063a75 150 if (symbolrate < fptmp)
1da177e4
LT
151 SFIL = 0;
152 fptmp = fpxin; do_div(fptmp, 492);
48063a75 153 if (symbolrate < fptmp)
1da177e4
LT
154 SFIL = 1;
155 fptmp = fpxin; do_div(fptmp, 640);
48063a75 156 if (symbolrate < fptmp)
1da177e4
LT
157 SFIL = 0;
158 fptmp = fpxin; do_div(fptmp, 984);
48063a75 159 if (symbolrate < fptmp)
1da177e4
LT
160 SFIL = 1;
161
162 fin = state->config->xin >> 4;
163 symbolrate <<= NDEC;
164 ratio = (symbolrate << 4) / fin;
165 tmp = ((symbolrate << 4) % fin) << 8;
166 ratio = (ratio << 8) + tmp / fin;
167 tmp = (tmp % fin) << 8;
75b697f7 168 ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
1da177e4
LT
169
170 BDR = ratio;
171 BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
172
173 if (BDRI > 0xFF)
174 BDRI = 0xFF;
175
176 SFIL = (SFIL << 4) | ves1820_inittab[0x0E];
177
178 NDEC = (NDEC << 6) | ves1820_inittab[0x03];
179
180 ves1820_writereg(state, 0x03, NDEC);
181 ves1820_writereg(state, 0x0a, BDR & 0xff);
182 ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
183 ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
184
185 ves1820_writereg(state, 0x0d, BDRI);
186 ves1820_writereg(state, 0x0e, SFIL);
187
188 return 0;
189}
190
191static int ves1820_init(struct dvb_frontend* fe)
192{
b8742700 193 struct ves1820_state* state = fe->demodulator_priv;
1da177e4 194 int i;
1da177e4
LT
195
196 ves1820_writereg(state, 0, 0);
197
6816a4c1
JS
198 for (i = 0; i < sizeof(ves1820_inittab); i++)
199 ves1820_writereg(state, i, ves1820_inittab[i]);
200 if (state->config->selagc)
201 ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08);
1da177e4
LT
202
203 ves1820_writereg(state, 0x34, state->pwm);
204
1da177e4
LT
205 return 0;
206}
207
f6c69968 208static int ves1820_set_parameters(struct dvb_frontend *fe)
1da177e4 209{
f6c69968 210 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
b8742700 211 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
212 static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
213 static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
214 static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
215 static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
216 static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
f6c69968 217 int real_qam = p->modulation - QAM_16;
1da177e4
LT
218
219 if (real_qam < 0 || real_qam > 4)
220 return -EINVAL;
221
dea74869 222 if (fe->ops.tuner_ops.set_params) {
14d24d14 223 fe->ops.tuner_ops.set_params(fe);
dea74869 224 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
58b119e8
AQ
225 }
226
f6c69968 227 ves1820_set_symbolrate(state, p->symbol_rate);
1da177e4
LT
228 ves1820_writereg(state, 0x34, state->pwm);
229
230 ves1820_writereg(state, 0x01, reg0x01[real_qam]);
231 ves1820_writereg(state, 0x05, reg0x05[real_qam]);
232 ves1820_writereg(state, 0x08, reg0x08[real_qam]);
233 ves1820_writereg(state, 0x09, reg0x09[real_qam]);
234
235 ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
6816a4c1 236 ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
1da177e4
LT
237 return 0;
238}
239
240static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
241{
b8742700 242 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
243 int sync;
244
245 *status = 0;
246 sync = ves1820_readreg(state, 0x11);
247
248 if (sync & 1)
249 *status |= FE_HAS_SIGNAL;
250
251 if (sync & 2)
252 *status |= FE_HAS_CARRIER;
253
254 if (sync & 2) /* XXX FIXME! */
255 *status |= FE_HAS_VITERBI;
256
257 if (sync & 4)
258 *status |= FE_HAS_SYNC;
259
260 if (sync & 8)
261 *status |= FE_HAS_LOCK;
262
263 return 0;
264}
265
266static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
267{
b8742700 268 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
269
270 u32 _ber = ves1820_readreg(state, 0x14) |
271 (ves1820_readreg(state, 0x15) << 8) |
272 ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
273 *ber = 10 * _ber;
274
275 return 0;
276}
277
278static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
279{
b8742700 280 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
281
282 u8 gain = ves1820_readreg(state, 0x17);
283 *strength = (gain << 8) | gain;
284
285 return 0;
286}
287
288static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
289{
b8742700 290 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
291
292 u8 quality = ~ves1820_readreg(state, 0x18);
293 *snr = (quality << 8) | quality;
294
295 return 0;
296}
297
298static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
299{
b8742700 300 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
301
302 *ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
303 if (*ucblocks == 0x7f)
304 *ucblocks = 0xffffffff;
305
306 /* reset uncorrected block counter */
307 ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
308 ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
309
310 return 0;
311}
312
7c61d80a 313static int ves1820_get_frontend(struct dvb_frontend *fe)
1da177e4 314{
7c61d80a 315 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
b8742700 316 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
317 int sync;
318 s8 afc = 0;
319
320 sync = ves1820_readreg(state, 0x11);
321 afc = ves1820_readreg(state, 0x19);
322 if (verbose) {
323 /* AFC only valid when carrier has been recovered */
324 printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
f6c69968 325 "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
1da177e4
LT
326 }
327
328 if (!state->config->invert) {
329 p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
330 } else {
331 p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
332 }
333
f6c69968 334 p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
1da177e4 335
f6c69968 336 p->fec_inner = FEC_NONE;
1da177e4
LT
337
338 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
339 if (sync & 2)
f6c69968 340 p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
1da177e4
LT
341
342 return 0;
343}
344
345static int ves1820_sleep(struct dvb_frontend* fe)
346{
b8742700 347 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
348
349 ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */
350 ves1820_writereg(state, 0x00, 0x80); /* standby */
351
352 return 0;
353}
354
355static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
356{
357
358 fesettings->min_delay_ms = 200;
359 fesettings->step_size = 0;
360 fesettings->max_drift = 0;
361 return 0;
362}
363
364static void ves1820_release(struct dvb_frontend* fe)
365{
b8742700 366 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
367 kfree(state);
368}
369
370static struct dvb_frontend_ops ves1820_ops;
371
372struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
373 struct i2c_adapter* i2c,
374 u8 pwm)
375{
376 struct ves1820_state* state = NULL;
377
378 /* allocate memory for the internal state */
084e24ac 379 state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
1da177e4
LT
380 if (state == NULL)
381 goto error;
382
383 /* setup the state */
1da177e4
LT
384 state->reg0 = ves1820_inittab[0];
385 state->config = config;
386 state->i2c = i2c;
387 state->pwm = pwm;
388
389 /* check if the demod is there */
390 if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
391 goto error;
392
393 if (verbose)
394 printk("ves1820: pwm=0x%02x\n", state->pwm);
395
1da177e4 396 /* create dvb_frontend */
dea74869
PB
397 memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
398 state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
399 state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
1da177e4 400 state->frontend.demodulator_priv = state;
dea74869 401
1da177e4
LT
402 return &state->frontend;
403
404error:
405 kfree(state);
406 return NULL;
407}
408
409static struct dvb_frontend_ops ves1820_ops = {
f6c69968 410 .delsys = { SYS_DVBC_ANNEX_A },
1da177e4
LT
411 .info = {
412 .name = "VLSI VES1820 DVB-C",
1da177e4 413 .frequency_stepsize = 62500,
a18255be
HB
414 .frequency_min = 47000000,
415 .frequency_max = 862000000,
1da177e4
LT
416 .caps = FE_CAN_QAM_16 |
417 FE_CAN_QAM_32 |
418 FE_CAN_QAM_64 |
419 FE_CAN_QAM_128 |
420 FE_CAN_QAM_256 |
421 FE_CAN_FEC_AUTO
422 },
423
424 .release = ves1820_release,
425
426 .init = ves1820_init,
427 .sleep = ves1820_sleep,
428
f6c69968
MCC
429 .set_frontend = ves1820_set_parameters,
430 .get_frontend = ves1820_get_frontend,
1da177e4
LT
431 .get_tune_settings = ves1820_get_tune_settings,
432
433 .read_status = ves1820_read_status,
434 .read_ber = ves1820_read_ber,
435 .read_signal_strength = ves1820_read_signal_strength,
436 .read_snr = ves1820_read_snr,
437 .read_ucblocks = ves1820_read_ucblocks,
438};
439
440module_param(verbose, int, 0644);
441MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
442
443MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
444MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
445MODULE_LICENSE("GPL");
446
447EXPORT_SYMBOL(ves1820_attach);
This page took 1.163143 seconds and 5 git commands to generate.