Linux 3.12.39
[linux/fpc-iii.git] / drivers / media / dvb-frontends / s921.c
bloba271ac3eaec04dc4e85c62a616837bfb4f27ff4f
1 /*
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 <mchehab@redhat.com>
6 * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
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"
29 #include "s921.h"
31 static int debug = 1;
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); \
37 } while (0)
39 #define dprintk(args...) \
40 do { \
41 if (debug) { \
42 printk(KERN_DEBUG "s921: %s: ", __func__); \
43 printk(args); \
44 } \
45 } while (0)
47 struct s921_state {
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 */
54 u32 currentfreq;
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 {
63 u32 freq_low;
64 u8 band_reg;
65 } s921_bandselect[] = {
66 { 0, 0x7b },
67 { 485140000, 0x5b },
68 { 515140000, 0x3b },
69 { 545140000, 0x1b },
70 { 599140000, 0xfb },
71 { 623140000, 0xdb },
72 { 659140000, 0xbb },
73 { 713140000, 0x9b },
76 struct regdata {
77 u8 reg;
78 u8 data;
81 static struct regdata s921_init[] = {
82 { 0x01, 0x80 }, /* Probably, a reset sequence */
83 { 0x01, 0x40 },
84 { 0x01, 0x80 },
85 { 0x01, 0x40 },
87 { 0x02, 0x00 },
88 { 0x03, 0x40 },
89 { 0x04, 0x01 },
90 { 0x05, 0x00 },
91 { 0x06, 0x00 },
92 { 0x07, 0x00 },
93 { 0x08, 0x00 },
94 { 0x09, 0x00 },
95 { 0x0a, 0x00 },
96 { 0x0b, 0x5a },
97 { 0x0c, 0x00 },
98 { 0x0d, 0x00 },
99 { 0x0f, 0x00 },
100 { 0x13, 0x1b },
101 { 0x14, 0x80 },
102 { 0x15, 0x40 },
103 { 0x17, 0x70 },
104 { 0x18, 0x01 },
105 { 0x19, 0x12 },
106 { 0x1a, 0x01 },
107 { 0x1b, 0x12 },
108 { 0x1c, 0xa0 },
109 { 0x1d, 0x00 },
110 { 0x1e, 0x0a },
111 { 0x1f, 0x08 },
112 { 0x20, 0x40 },
113 { 0x21, 0xff },
114 { 0x22, 0x4c },
115 { 0x23, 0x4e },
116 { 0x24, 0x4c },
117 { 0x25, 0x00 },
118 { 0x26, 0x00 },
119 { 0x27, 0xf4 },
120 { 0x28, 0x60 },
121 { 0x29, 0x88 },
122 { 0x2a, 0x40 },
123 { 0x2b, 0x40 },
124 { 0x2c, 0xff },
125 { 0x2d, 0x00 },
126 { 0x2e, 0xff },
127 { 0x2f, 0x00 },
128 { 0x30, 0x20 },
129 { 0x31, 0x06 },
130 { 0x32, 0x0c },
131 { 0x34, 0x0f },
132 { 0x37, 0xfe },
133 { 0x38, 0x00 },
134 { 0x39, 0x63 },
135 { 0x3a, 0x10 },
136 { 0x3b, 0x10 },
137 { 0x47, 0x00 },
138 { 0x49, 0xe5 },
139 { 0x4b, 0x00 },
140 { 0x50, 0xc0 },
141 { 0x52, 0x20 },
142 { 0x54, 0x5a },
143 { 0x55, 0x5b },
144 { 0x56, 0x40 },
145 { 0x57, 0x70 },
146 { 0x5c, 0x50 },
147 { 0x5d, 0x00 },
148 { 0x62, 0x17 },
149 { 0x63, 0x2f },
150 { 0x64, 0x6f },
151 { 0x68, 0x00 },
152 { 0x69, 0x89 },
153 { 0x6a, 0x00 },
154 { 0x6b, 0x00 },
155 { 0x6c, 0x00 },
156 { 0x6d, 0x00 },
157 { 0x6e, 0x00 },
158 { 0x70, 0x10 },
159 { 0x71, 0x00 },
160 { 0x75, 0x00 },
161 { 0x76, 0x30 },
162 { 0x77, 0x01 },
163 { 0xaf, 0x00 },
164 { 0xb0, 0xa0 },
165 { 0xb2, 0x3d },
166 { 0xb3, 0x25 },
167 { 0xb4, 0x8b },
168 { 0xb5, 0x4b },
169 { 0xb6, 0x3f },
170 { 0xb7, 0xff },
171 { 0xb8, 0xff },
172 { 0xb9, 0xfc },
173 { 0xba, 0x00 },
174 { 0xbb, 0x00 },
175 { 0xbc, 0x00 },
176 { 0xd0, 0x30 },
177 { 0xe4, 0x84 },
178 { 0xf0, 0x48 },
179 { 0xf1, 0x19 },
180 { 0xf2, 0x5a },
181 { 0xf3, 0x8e },
182 { 0xf4, 0x2d },
183 { 0xf5, 0x07 },
184 { 0xf6, 0x5a },
185 { 0xf7, 0xba },
186 { 0xf8, 0xd7 },
189 static struct regdata s921_prefreq[] = {
190 { 0x47, 0x60 },
191 { 0x68, 0x00 },
192 { 0x69, 0x89 },
193 { 0xf0, 0x48 },
194 { 0xf1, 0x19 },
197 static struct regdata s921_postfreq[] = {
198 { 0xf5, 0xae },
199 { 0xf6, 0xb7 },
200 { 0xf7, 0xba },
201 { 0xf8, 0xd7 },
202 { 0x68, 0x0a },
203 { 0x69, 0x09 },
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
213 int rc;
215 rc = i2c_transfer(state->i2c, &msg, 1);
216 if (rc != 1) {
217 printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
218 " data == 0x%02x)\n", __func__, rc, reg, data);
219 return rc;
222 return 0;
225 static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
226 struct regdata *rd, int size)
228 int i, rc;
230 for (i = 0; i < size; i++) {
231 rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
232 if (rc < 0)
233 return rc;
235 return 0;
238 static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
240 u8 val;
241 int rc;
242 struct i2c_msg msg[] = {
243 { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
244 { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
247 rc = i2c_transfer(state->i2c, msg, 2);
249 if (rc != 2) {
250 rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
251 return rc;
254 return val;
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;
269 int band, rc, i;
270 unsigned long f_offset;
271 u8 f_switch;
272 u64 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)
278 break;
279 band--;
281 if (band < 0) {
282 rc("%s: frequency out of range\n", __func__);
283 return -EINVAL;
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);
293 if (rc < 0)
294 return rc;
296 rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
297 if (rc < 0)
298 return rc;
300 rc = s921_writereg(state, 0xf3, f_offset & 0xff);
301 if (rc < 0)
302 return rc;
304 rc = s921_writereg(state, 0xf4, f_switch);
305 if (rc < 0)
306 return rc;
308 rc = s921_writeregdata(state, s921_postfreq);
309 if (rc < 0)
310 return rc;
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);
317 if (rc < 0)
318 return rc;
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);
334 return 0;
337 static int s921_initfe(struct dvb_frontend *fe)
339 struct s921_state *state = fe->demodulator_priv;
340 int rc;
342 dprintk("\n");
344 rc = s921_writeregdata(state, s921_init);
345 if (rc < 0)
346 return rc;
348 return 0;
351 static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
353 struct s921_state *state = fe->demodulator_priv;
354 int regstatus, rc;
356 *status = 0;
358 rc = s921_readreg(state, 0x81);
359 if (rc < 0)
360 return rc;
362 regstatus = rc << 8;
364 rc = s921_readreg(state, 0x82);
365 if (rc < 0)
366 return rc;
368 regstatus |= rc;
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 |
375 FE_HAS_CARRIER |
376 FE_HAS_VITERBI |
377 FE_HAS_SYNC |
378 FE_HAS_LOCK;
379 } else if (regstatus & 0x40) {
380 /* This is close to Full Sync, but not enough to get useful info */
381 *status = FE_HAS_SIGNAL |
382 FE_HAS_CARRIER |
383 FE_HAS_VITERBI |
384 FE_HAS_SYNC;
387 return 0;
390 static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
392 fe_status_t status;
393 struct s921_state *state = fe->demodulator_priv;
394 int rc;
396 /* FIXME: Use the proper register for it... 0x80? */
397 rc = s921_read_status(fe, &status);
398 if (rc < 0)
399 return rc;
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);
414 return 0;
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;
421 int rc;
423 dprintk("\n");
425 /* FIXME: We don't know how to use non-auto mode */
427 rc = s921_pll_tune(fe);
428 if (rc < 0)
429 return rc;
431 state->currentfreq = p->frequency;
433 return 0;
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;
445 return 0;
448 static int s921_tune(struct dvb_frontend *fe,
449 bool re_tune,
450 unsigned int mode_flags,
451 unsigned int *delay,
452 fe_status_t *status)
454 int rc = 0;
456 dprintk("\n");
458 if (re_tune)
459 rc = s921_set_frontend(fe);
461 if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
462 s921_read_status(fe, status);
464 return rc;
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;
476 dprintk("\n");
477 kfree(state);
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);
489 dprintk("\n");
490 if (!state) {
491 rc("Unable to kzalloc\n");
492 return NULL;
495 /* setup the state */
496 state->config = config;
497 state->i2c = i2c;
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 */
511 .info = {
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,
532 .init = s921_initfe,
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,
537 .tune = s921_tune,
538 .get_frontend_algo = s921_get_algo,
541 MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
542 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
543 MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
544 MODULE_LICENSE("GPL");