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