Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.13 450 lines 10 kB view raw
1/* 2 * at76c651.c 3 * 4 * Atmel DVB-C Frontend Driver (at76c651/tua6010xs) 5 * 6 * Copyright (C) 2001 fnbrd <fnbrd@gmx.de> 7 * & 2002-2004 Andreas Oberritter <obi@linuxtv.org> 8 * & 2003 Wolfram Joost <dbox2@frokaschwei.de> 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 * AT76C651 25 * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf 26 * http://www.atmel.com/atmel/acrobat/doc1320.pdf 27 */ 28 29#include <linux/init.h> 30#include <linux/module.h> 31#include <linux/moduleparam.h> 32#include <linux/kernel.h> 33#include <linux/string.h> 34#include <linux/slab.h> 35#include <linux/bitops.h> 36#include "dvb_frontend.h" 37#include "at76c651.h" 38 39 40struct at76c651_state { 41 42 struct i2c_adapter* i2c; 43 44 struct dvb_frontend_ops ops; 45 46 const struct at76c651_config* config; 47 48 struct dvb_frontend frontend; 49 50 /* revision of the chip */ 51 u8 revision; 52 53 /* last QAM value set */ 54 u8 qam; 55}; 56 57static int debug; 58#define dprintk(args...) \ 59 do { \ 60 if (debug) printk(KERN_DEBUG "at76c651: " args); \ 61 } while (0) 62 63 64#if ! defined(__powerpc__) 65static __inline__ int __ilog2(unsigned long x) 66{ 67 int i; 68 69 if (x == 0) 70 return -1; 71 72 for (i = 0; x != 0; i++) 73 x >>= 1; 74 75 return i - 1; 76} 77#endif 78 79static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data) 80{ 81 int ret; 82 u8 buf[] = { reg, data }; 83 struct i2c_msg msg = 84 { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 85 86 ret = i2c_transfer(state->i2c, &msg, 1); 87 88 if (ret != 1) 89 dprintk("%s: writereg error " 90 "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", 91 __FUNCTION__, reg, data, ret); 92 93 msleep(10); 94 95 return (ret != 1) ? -EREMOTEIO : 0; 96} 97 98static u8 at76c651_readreg(struct at76c651_state* state, u8 reg) 99{ 100 int ret; 101 u8 val; 102 struct i2c_msg msg[] = { 103 { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 }, 104 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = &val, .len = 1 } 105 }; 106 107 ret = i2c_transfer(state->i2c, msg, 2); 108 109 if (ret != 2) 110 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); 111 112 return val; 113} 114 115static int at76c651_reset(struct at76c651_state* state) 116{ 117 return at76c651_writereg(state, 0x07, 0x01); 118} 119 120static void at76c651_disable_interrupts(struct at76c651_state* state) 121{ 122 at76c651_writereg(state, 0x0b, 0x00); 123} 124 125static int at76c651_set_auto_config(struct at76c651_state *state) 126{ 127 /* 128 * Autoconfig 129 */ 130 131 at76c651_writereg(state, 0x06, 0x01); 132 133 /* 134 * Performance optimizations, should be done after autoconfig 135 */ 136 137 at76c651_writereg(state, 0x10, 0x06); 138 at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10); 139 at76c651_writereg(state, 0x15, 0x28); 140 at76c651_writereg(state, 0x20, 0x09); 141 at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90); 142 at76c651_writereg(state, 0x30, 0x90); 143 if (state->qam == 5) 144 at76c651_writereg(state, 0x35, 0x2A); 145 146 /* 147 * Initialize A/D-converter 148 */ 149 150 if (state->revision == 0x11) { 151 at76c651_writereg(state, 0x2E, 0x38); 152 at76c651_writereg(state, 0x2F, 0x13); 153 } 154 155 at76c651_disable_interrupts(state); 156 157 /* 158 * Restart operation 159 */ 160 161 at76c651_reset(state); 162 163 return 0; 164} 165 166static void at76c651_set_bbfreq(struct at76c651_state* state) 167{ 168 at76c651_writereg(state, 0x04, 0x3f); 169 at76c651_writereg(state, 0x05, 0xee); 170} 171 172static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate) 173{ 174 u8 exponent; 175 u32 mantissa; 176 177 if (symbol_rate > 9360000) 178 return -EINVAL; 179 180 /* 181 * FREF = 57800 kHz 182 * exponent = 10 + floor (log2(symbol_rate / FREF)) 183 * mantissa = (symbol_rate / FREF) * (1 << (30 - exponent)) 184 */ 185 186 exponent = __ilog2((symbol_rate << 4) / 903125); 187 mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289; 188 189 at76c651_writereg(state, 0x00, mantissa >> 13); 190 at76c651_writereg(state, 0x01, mantissa >> 5); 191 at76c651_writereg(state, 0x02, (mantissa << 3) | exponent); 192 193 return 0; 194} 195 196static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam) 197{ 198 switch (qam) { 199 case QPSK: 200 state->qam = 0x02; 201 break; 202 case QAM_16: 203 state->qam = 0x04; 204 break; 205 case QAM_32: 206 state->qam = 0x05; 207 break; 208 case QAM_64: 209 state->qam = 0x06; 210 break; 211 case QAM_128: 212 state->qam = 0x07; 213 break; 214 case QAM_256: 215 state->qam = 0x08; 216 break; 217#if 0 218 case QAM_512: 219 state->qam = 0x09; 220 break; 221 case QAM_1024: 222 state->qam = 0x0A; 223 break; 224#endif 225 default: 226 return -EINVAL; 227 228 } 229 230 return at76c651_writereg(state, 0x03, state->qam); 231} 232 233static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion) 234{ 235 u8 feciqinv = at76c651_readreg(state, 0x60); 236 237 switch (inversion) { 238 case INVERSION_OFF: 239 feciqinv |= 0x02; 240 feciqinv &= 0xFE; 241 break; 242 243 case INVERSION_ON: 244 feciqinv |= 0x03; 245 break; 246 247 case INVERSION_AUTO: 248 feciqinv &= 0xFC; 249 break; 250 251 default: 252 return -EINVAL; 253 } 254 255 return at76c651_writereg(state, 0x60, feciqinv); 256} 257 258static int at76c651_set_parameters(struct dvb_frontend* fe, 259 struct dvb_frontend_parameters *p) 260{ 261 int ret; 262 struct at76c651_state* state = fe->demodulator_priv; 263 264 at76c651_writereg(state, 0x0c, 0xc3); 265 state->config->pll_set(fe, p); 266 at76c651_writereg(state, 0x0c, 0xc2); 267 268 if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate))) 269 return ret; 270 271 if ((ret = at76c651_set_inversion(state, p->inversion))) 272 return ret; 273 274 return at76c651_set_auto_config(state); 275} 276 277static int at76c651_set_defaults(struct dvb_frontend* fe) 278{ 279 struct at76c651_state* state = fe->demodulator_priv; 280 281 at76c651_set_symbol_rate(state, 6900000); 282 at76c651_set_qam(state, QAM_64); 283 at76c651_set_bbfreq(state); 284 at76c651_set_auto_config(state); 285 286 if (state->config->pll_init) { 287 at76c651_writereg(state, 0x0c, 0xc3); 288 state->config->pll_init(fe); 289 at76c651_writereg(state, 0x0c, 0xc2); 290 } 291 292 return 0; 293} 294 295static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) 296{ 297 struct at76c651_state* state = fe->demodulator_priv; 298 u8 sync; 299 300 /* 301 * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) 302 */ 303 sync = at76c651_readreg(state, 0x80); 304 *status = 0; 305 306 if (sync & (0x04 | 0x10)) /* AGC1 || TIM */ 307 *status |= FE_HAS_SIGNAL; 308 if (sync & 0x10) /* TIM */ 309 *status |= FE_HAS_CARRIER; 310 if (sync & 0x80) /* FEC */ 311 *status |= FE_HAS_VITERBI; 312 if (sync & 0x40) /* CAR */ 313 *status |= FE_HAS_SYNC; 314 if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */ 315 *status |= FE_HAS_LOCK; 316 317 return 0; 318} 319 320static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) 321{ 322 struct at76c651_state* state = fe->demodulator_priv; 323 324 *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16; 325 *ber |= at76c651_readreg(state, 0x82) << 8; 326 *ber |= at76c651_readreg(state, 0x83); 327 *ber *= 10; 328 329 return 0; 330} 331 332static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) 333{ 334 struct at76c651_state* state = fe->demodulator_priv; 335 336 u8 gain = ~at76c651_readreg(state, 0x91); 337 *strength = (gain << 8) | gain; 338 339 return 0; 340} 341 342static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) 343{ 344 struct at76c651_state* state = fe->demodulator_priv; 345 346 *snr = 0xFFFF - 347 ((at76c651_readreg(state, 0x8F) << 8) | 348 at76c651_readreg(state, 0x90)); 349 350 return 0; 351} 352 353static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 354{ 355 struct at76c651_state* state = fe->demodulator_priv; 356 357 *ucblocks = at76c651_readreg(state, 0x82); 358 359 return 0; 360} 361 362static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings) 363{ 364 fesettings->min_delay_ms = 50; 365 fesettings->step_size = 0; 366 fesettings->max_drift = 0; 367 return 0; 368} 369 370static void at76c651_release(struct dvb_frontend* fe) 371{ 372 struct at76c651_state* state = fe->demodulator_priv; 373 kfree(state); 374} 375 376static struct dvb_frontend_ops at76c651_ops; 377 378struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, 379 struct i2c_adapter* i2c) 380{ 381 struct at76c651_state* state = NULL; 382 383 /* allocate memory for the internal state */ 384 state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); 385 if (state == NULL) goto error; 386 387 /* setup the state */ 388 state->config = config; 389 state->qam = 0; 390 391 /* check if the demod is there */ 392 if (at76c651_readreg(state, 0x0e) != 0x65) goto error; 393 394 /* finalise state setup */ 395 state->i2c = i2c; 396 state->revision = at76c651_readreg(state, 0x0f) & 0xfe; 397 memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops)); 398 399 /* create dvb_frontend */ 400 state->frontend.ops = &state->ops; 401 state->frontend.demodulator_priv = state; 402 return &state->frontend; 403 404error: 405 kfree(state); 406 return NULL; 407} 408 409static struct dvb_frontend_ops at76c651_ops = { 410 411 .info = { 412 .name = "Atmel AT76C651B DVB-C", 413 .type = FE_QAM, 414 .frequency_min = 48250000, 415 .frequency_max = 863250000, 416 .frequency_stepsize = 62500, 417 /*.frequency_tolerance = */ /* FIXME: 12% of SR */ 418 .symbol_rate_min = 0, /* FIXME */ 419 .symbol_rate_max = 9360000, /* FIXME */ 420 .symbol_rate_tolerance = 4000, 421 .caps = FE_CAN_INVERSION_AUTO | 422 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 423 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | 424 FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | 425 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | 426 FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER 427 }, 428 429 .release = at76c651_release, 430 431 .init = at76c651_set_defaults, 432 433 .set_frontend = at76c651_set_parameters, 434 .get_tune_settings = at76c651_get_tune_settings, 435 436 .read_status = at76c651_read_status, 437 .read_ber = at76c651_read_ber, 438 .read_signal_strength = at76c651_read_signal_strength, 439 .read_snr = at76c651_read_snr, 440 .read_ucblocks = at76c651_read_ucblocks, 441}; 442 443module_param(debug, int, 0644); 444MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 445 446MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver"); 447MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); 448MODULE_LICENSE("GPL"); 449 450EXPORT_SYMBOL(at76c651_attach);