]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/dvb/frontends/ves1820.c
V4L/DVB (12440): Use kzalloc for frontend states to have struct dvb_frontend properly
[mirror_ubuntu-artful-kernel.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;
168 ratio = (ratio << 8) + (tmp + fin / 2) / fin;
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
208static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
209{
b8742700 210 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
211 static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
212 static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
213 static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
214 static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
215 static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
216 int real_qam = p->u.qam.modulation - QAM_16;
217
218 if (real_qam < 0 || real_qam > 4)
219 return -EINVAL;
220
dea74869
PB
221 if (fe->ops.tuner_ops.set_params) {
222 fe->ops.tuner_ops.set_params(fe, p);
223 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
58b119e8
AQ
224 }
225
1da177e4
LT
226 ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
227 ves1820_writereg(state, 0x34, state->pwm);
228
229 ves1820_writereg(state, 0x01, reg0x01[real_qam]);
230 ves1820_writereg(state, 0x05, reg0x05[real_qam]);
231 ves1820_writereg(state, 0x08, reg0x08[real_qam]);
232 ves1820_writereg(state, 0x09, reg0x09[real_qam]);
233
234 ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
6816a4c1 235 ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0));
1da177e4
LT
236 return 0;
237}
238
239static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
240{
b8742700 241 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
242 int sync;
243
244 *status = 0;
245 sync = ves1820_readreg(state, 0x11);
246
247 if (sync & 1)
248 *status |= FE_HAS_SIGNAL;
249
250 if (sync & 2)
251 *status |= FE_HAS_CARRIER;
252
253 if (sync & 2) /* XXX FIXME! */
254 *status |= FE_HAS_VITERBI;
255
256 if (sync & 4)
257 *status |= FE_HAS_SYNC;
258
259 if (sync & 8)
260 *status |= FE_HAS_LOCK;
261
262 return 0;
263}
264
265static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
266{
b8742700 267 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
268
269 u32 _ber = ves1820_readreg(state, 0x14) |
270 (ves1820_readreg(state, 0x15) << 8) |
271 ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
272 *ber = 10 * _ber;
273
274 return 0;
275}
276
277static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
278{
b8742700 279 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
280
281 u8 gain = ves1820_readreg(state, 0x17);
282 *strength = (gain << 8) | gain;
283
284 return 0;
285}
286
287static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
288{
b8742700 289 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
290
291 u8 quality = ~ves1820_readreg(state, 0x18);
292 *snr = (quality << 8) | quality;
293
294 return 0;
295}
296
297static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
298{
b8742700 299 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
300
301 *ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
302 if (*ucblocks == 0x7f)
303 *ucblocks = 0xffffffff;
304
305 /* reset uncorrected block counter */
306 ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
307 ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
308
309 return 0;
310}
311
312static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
313{
b8742700 314 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
315 int sync;
316 s8 afc = 0;
317
318 sync = ves1820_readreg(state, 0x11);
319 afc = ves1820_readreg(state, 0x19);
320 if (verbose) {
321 /* AFC only valid when carrier has been recovered */
322 printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
323 "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
324 }
325
326 if (!state->config->invert) {
327 p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
328 } else {
329 p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
330 }
331
332 p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
333
334 p->u.qam.fec_inner = FEC_NONE;
335
336 p->frequency = ((p->frequency + 31250) / 62500) * 62500;
337 if (sync & 2)
338 p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
339
340 return 0;
341}
342
343static int ves1820_sleep(struct dvb_frontend* fe)
344{
b8742700 345 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
346
347 ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */
348 ves1820_writereg(state, 0x00, 0x80); /* standby */
349
350 return 0;
351}
352
353static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
354{
355
356 fesettings->min_delay_ms = 200;
357 fesettings->step_size = 0;
358 fesettings->max_drift = 0;
359 return 0;
360}
361
362static void ves1820_release(struct dvb_frontend* fe)
363{
b8742700 364 struct ves1820_state* state = fe->demodulator_priv;
1da177e4
LT
365 kfree(state);
366}
367
368static struct dvb_frontend_ops ves1820_ops;
369
370struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
371 struct i2c_adapter* i2c,
372 u8 pwm)
373{
374 struct ves1820_state* state = NULL;
375
376 /* allocate memory for the internal state */
084e24ac 377 state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL);
1da177e4
LT
378 if (state == NULL)
379 goto error;
380
381 /* setup the state */
1da177e4
LT
382 state->reg0 = ves1820_inittab[0];
383 state->config = config;
384 state->i2c = i2c;
385 state->pwm = pwm;
386
387 /* check if the demod is there */
388 if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
389 goto error;
390
391 if (verbose)
392 printk("ves1820: pwm=0x%02x\n", state->pwm);
393
1da177e4 394 /* create dvb_frontend */
dea74869
PB
395 memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
396 state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
397 state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
1da177e4 398 state->frontend.demodulator_priv = state;
dea74869 399
1da177e4
LT
400 return &state->frontend;
401
402error:
403 kfree(state);
404 return NULL;
405}
406
407static struct dvb_frontend_ops ves1820_ops = {
408
409 .info = {
410 .name = "VLSI VES1820 DVB-C",
411 .type = FE_QAM,
412 .frequency_stepsize = 62500,
a18255be
HB
413 .frequency_min = 47000000,
414 .frequency_max = 862000000,
1da177e4
LT
415 .caps = FE_CAN_QAM_16 |
416 FE_CAN_QAM_32 |
417 FE_CAN_QAM_64 |
418 FE_CAN_QAM_128 |
419 FE_CAN_QAM_256 |
420 FE_CAN_FEC_AUTO
421 },
422
423 .release = ves1820_release,
424
425 .init = ves1820_init,
426 .sleep = ves1820_sleep,
427
428 .set_frontend = ves1820_set_parameters,
429 .get_frontend = ves1820_get_frontend,
430 .get_tune_settings = ves1820_get_tune_settings,
431
432 .read_status = ves1820_read_status,
433 .read_ber = ves1820_read_ber,
434 .read_signal_strength = ves1820_read_signal_strength,
435 .read_snr = ves1820_read_snr,
436 .read_ucblocks = ves1820_read_ucblocks,
437};
438
439module_param(verbose, int, 0644);
440MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
441
442MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
443MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
444MODULE_LICENSE("GPL");
445
446EXPORT_SYMBOL(ves1820_attach);