2 * Sharp VA3A5JZ921 One Seg Broadcast Module driver
3 * This device is labeled as just S. 921 at the top of the frontend can
5 * Copyright (C) 2009-2010 Mauro Carvalho Chehab
8 * Developed for Leadership SBTVD 1seg device sold in Brazil
10 * Frontend module based on cx24123 driver, getting some info from
11 * the old s921 driver.
13 * FIXME: Need to port to DVB v5.2 API
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation version 2.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
25 #include <linux/kernel.h>
26 #include <asm/div64.h>
28 #include "dvb_frontend.h"
32 module_param(debug, int, 0644);
33 MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
35 #define rc(args...) do { \
36 printk(KERN_ERR "s921: " args); \
39 #define dprintk(args...) \
42 printk(KERN_DEBUG "s921: %s: ", __func__); \
48 struct i2c_adapter *i2c;
49 const struct s921_config *config;
51 struct dvb_frontend frontend;
53 /* The Demod can't easily provide these, we cache them */
58 * Various tuner defaults need to be established for a given frequency kHz.
59 * fixme: The bounds on the bands do not match the doc in real life.
60 * fixme: Some of them have been moved, other might need adjustment.
62 static struct s921_bandselect_val {
65 } s921_bandselect[] = {
81 static struct regdata s921_init[] = {
82 { 0x01, 0x80 }, /* Probably, a reset sequence */
189 static struct regdata s921_prefreq[] = {
197 static struct regdata s921_postfreq[] = {
206 static int s921_i2c_writereg(struct s921_state *state,
207 u8 i2c_addr, int reg, int data)
209 u8 buf[] = { reg, data };
210 struct i2c_msg msg = {
211 .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
215 rc = i2c_transfer(state->i2c, &msg, 1);
217 printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
218 " data == 0x%02x)\n", __func__, rc, reg, data);
225 static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
226 struct regdata *rd, int size)
230 for (i = 0; i < size; i++) {
231 rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
238 static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
242 struct i2c_msg msg[] = {
243 { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 },
244 { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
247 rc = i2c_transfer(state->i2c, msg, 2);
250 rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
257 #define s921_readreg(state, reg) \
258 s921_i2c_readreg(state, state->config->demod_address, reg)
259 #define s921_writereg(state, reg, val) \
260 s921_i2c_writereg(state, state->config->demod_address, reg, val)
261 #define s921_writeregdata(state, regdata) \
262 s921_i2c_writeregdata(state, state->config->demod_address, \
263 regdata, ARRAY_SIZE(regdata))
265 static int s921_pll_tune(struct dvb_frontend *fe)
267 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
268 struct s921_state *state = fe->demodulator_priv;
270 unsigned long f_offset;
274 dprintk("frequency=%i\n", p->frequency);
276 for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
277 if (p->frequency < s921_bandselect[band].freq_low)
282 rc("%s: frequency out of range\n", __func__);
286 f_switch = s921_bandselect[band].band_reg;
288 offset = ((u64)p->frequency) * 258;
289 do_div(offset, 6000000);
290 f_offset = ((unsigned long)offset) + 2321;
292 rc = s921_writeregdata(state, s921_prefreq);
296 rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
300 rc = s921_writereg(state, 0xf3, f_offset & 0xff);
304 rc = s921_writereg(state, 0xf4, f_switch);
308 rc = s921_writeregdata(state, s921_postfreq);
312 for (i = 0 ; i < 6; i++) {
313 rc = s921_readreg(state, 0x80);
314 dprintk("status 0x80: %02x\n", rc);
316 rc = s921_writereg(state, 0x01, 0x40);
320 rc = s921_readreg(state, 0x01);
321 dprintk("status 0x01: %02x\n", rc);
323 rc = s921_readreg(state, 0x80);
324 dprintk("status 0x80: %02x\n", rc);
326 rc = s921_readreg(state, 0x80);
327 dprintk("status 0x80: %02x\n", rc);
329 rc = s921_readreg(state, 0x32);
330 dprintk("status 0x32: %02x\n", rc);
332 dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
337 static int s921_initfe(struct dvb_frontend *fe)
339 struct s921_state *state = fe->demodulator_priv;
344 rc = s921_writeregdata(state, s921_init);
351 static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
353 struct s921_state *state = fe->demodulator_priv;
358 rc = s921_readreg(state, 0x81);
364 rc = s921_readreg(state, 0x82);
370 dprintk("status = %04x\n", regstatus);
372 /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
373 if ((regstatus & 0xff) == 0x40) {
374 *status = FE_HAS_SIGNAL |
379 } else if (regstatus & 0x40) {
380 /* This is close to Full Sync, but not enough to get useful info */
381 *status = FE_HAS_SIGNAL |
390 static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
393 struct s921_state *state = fe->demodulator_priv;
396 /* FIXME: Use the proper register for it... 0x80? */
397 rc = s921_read_status(fe, &status);
401 *strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
403 dprintk("strength = 0x%04x\n", *strength);
405 rc = s921_readreg(state, 0x01);
406 dprintk("status 0x01: %02x\n", rc);
408 rc = s921_readreg(state, 0x80);
409 dprintk("status 0x80: %02x\n", rc);
411 rc = s921_readreg(state, 0x32);
412 dprintk("status 0x32: %02x\n", rc);
417 static int s921_set_frontend(struct dvb_frontend *fe)
419 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
420 struct s921_state *state = fe->demodulator_priv;
425 /* FIXME: We don't know how to use non-auto mode */
427 rc = s921_pll_tune(fe);
431 state->currentfreq = p->frequency;
436 static int s921_get_frontend(struct dvb_frontend *fe)
438 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
439 struct s921_state *state = fe->demodulator_priv;
441 /* FIXME: Probably it is possible to get it from regs f1 and f2 */
442 p->frequency = state->currentfreq;
443 p->delivery_system = SYS_ISDBT;
448 static int s921_tune(struct dvb_frontend *fe,
450 unsigned int mode_flags,
459 rc = s921_set_frontend(fe);
461 if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
462 s921_read_status(fe, status);
467 static int s921_get_algo(struct dvb_frontend *fe)
469 return 1; /* FE_ALGO_HW */
472 static void s921_release(struct dvb_frontend *fe)
474 struct s921_state *state = fe->demodulator_priv;
480 static struct dvb_frontend_ops s921_ops;
482 struct dvb_frontend *s921_attach(const struct s921_config *config,
483 struct i2c_adapter *i2c)
485 /* allocate memory for the internal state */
486 struct s921_state *state =
487 kzalloc(sizeof(struct s921_state), GFP_KERNEL);
491 rc("Unable to kzalloc\n");
495 /* setup the state */
496 state->config = config;
499 /* create dvb_frontend */
500 memcpy(&state->frontend.ops, &s921_ops,
501 sizeof(struct dvb_frontend_ops));
502 state->frontend.demodulator_priv = state;
504 return &state->frontend;
506 EXPORT_SYMBOL(s921_attach);
508 static struct dvb_frontend_ops s921_ops = {
509 .delsys = { SYS_ISDBT },
510 /* Use dib8000 values per default */
512 .name = "Sharp S921",
513 .frequency_min = 470000000,
515 * Max should be 770MHz instead, according with Sharp docs,
516 * but Leadership doc says it works up to 806 MHz. This is
517 * required to get channel 69, used in Brazil
519 .frequency_max = 806000000,
520 .frequency_tolerance = 0,
521 .caps = FE_CAN_INVERSION_AUTO |
522 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
523 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
524 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
525 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
526 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
527 FE_CAN_HIERARCHY_AUTO,
530 .release = s921_release,
533 .set_frontend = s921_set_frontend,
534 .get_frontend = s921_get_frontend,
535 .read_status = s921_read_status,
536 .read_signal_strength = s921_read_signal_strength,
538 .get_frontend_algo = s921_get_algo,
541 MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
542 MODULE_AUTHOR("Mauro Carvalho Chehab");
544 MODULE_LICENSE("GPL");