blob: 2bb695490ab2bbfea4a3c3b559a2a90f38bc0465 [file] [log] [blame]
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -03001/* tuner-xc2028
2 *
3 * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
Michel Ludwig701672e2007-07-18 10:29:10 -03004 * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
5 * - frontend interface
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -03006 * This code is placed under the terms of the GNU General Public License v2
7 */
8
9#include <linux/i2c.h>
10#include <asm/div64.h>
11#include <linux/firmware.h>
12#include <linux/videodev.h>
13#include <linux/delay.h>
Michel Ludwig701672e2007-07-18 10:29:10 -030014#include <media/tuner.h>
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -030015#include "tuner-driver.h"
16#include "tuner-xc2028.h"
17
Michel Ludwig701672e2007-07-18 10:29:10 -030018#include <linux/dvb/frontend.h>
19#include "dvb_frontend.h"
20
21/* digital TV standards */
22#define V4L2_STD_DTV_6MHZ ((v4l2_std_id)0x04000000)
23#define V4L2_STD_DTV_7MHZ ((v4l2_std_id)0x08000000)
24#define V4L2_STD_DTV_8MHZ ((v4l2_std_id)0x10000000)
25
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -030026/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */
27static const char *firmware_6M = "tm6000_xc3028_DTV_6M.fw";
Michel Ludwig701672e2007-07-18 10:29:10 -030028// static const char *firmware_78M = "tm6000_xc3028_78M.fw";
29static const char *firmware_7M = "tm6000_xc3028_7M.fw";
30static const char *firmware_8M = "tm6000_xc3028_8M.fw";
31static const char *firmware_B = "tm6000_xc3028_B_PAL.fw";
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -030032static const char *firmware_DK = "tm6000_xc3028_DK_PAL_MTS.fw";
33static const char *firmware_MN = "tm6000_xc3028_MN_BTSC.fw";
Michel Ludwig701672e2007-07-18 10:29:10 -030034static const char *firmware_INIT0 = "tm6000_xc3028_INIT0.fw";
35static const char *firmware_8MHZ_INIT0 = "tm6000_xc3028_8MHZ_INIT0.fw";
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -030036
37struct xc2028_data {
Michel Ludwig701672e2007-07-18 10:29:10 -030038 v4l2_std_id firm_type; /* video stds supported
39 by current firmware */
40 fe_bandwidth_t bandwidth; /* Firmware bandwidth:
41 6M, 7M or 8M */
42 int need_load_generic; /* The generic firmware
43 were loaded? */
44 enum tuner_mode mode;
45 struct i2c_client *i2c_client;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -030046};
47
48#define i2c_send(rc,c,buf,size) \
49if (size != (rc = i2c_master_send(c, buf, size))) \
50 tuner_warn("i2c output error: rc = %d (should be %d)\n", \
51 rc, (int)size);
52
53#define i2c_rcv(rc,c,buf,size) \
54if (size != (rc = i2c_master_recv(c, buf, size))) \
55 tuner_warn("i2c input error: rc = %d (should be %d)\n", \
56 rc, (int)size);
57
58#define send_seq(c, data...) \
59{ int rc; \
60 const static u8 _val[] = data; \
61 if (sizeof(_val) != \
62 (rc = i2c_master_send \
63 (c, _val, sizeof(_val)))) { \
64 printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \
65 return; \
66 } \
67 msleep (10); \
68}
69
70static int xc2028_get_reg(struct i2c_client *c, u16 reg)
71{
72 int rc;
73 unsigned char buf[1];
74 struct tuner *t = i2c_get_clientdata(c);
75
76 buf[0]= reg;
77
78 i2c_send(rc, c, buf, sizeof(buf));
79 if (rc<0)
80 return rc;
81
82 if (t->tuner_callback) {
83 rc = t->tuner_callback( c->adapter->algo_data,
84 XC2028_RESET_CLK, 0);
85 if (rc<0)
86 return rc;
87 }
88
89 i2c_rcv(rc, c, buf, 2);
90 if (rc<0)
91 return rc;
92
93 return (buf[1])|(buf[0]<<8);
94}
95
96static int load_firmware (struct i2c_client *c, const char *name)
97{
98 const struct firmware *fw=NULL;
99 struct tuner *t = i2c_get_clientdata(c);
100 unsigned char *p, *endp;
101 int len=0, rc=0;
102 static const char firmware_ver[] = "tm6000/xcv v1";
103
Michel Ludwig701672e2007-07-18 10:29:10 -0300104 tuner_info("xc2028: Loading firmware %s\n", name);
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300105 rc = request_firmware(&fw, name, &c->dev);
106 if (rc < 0) {
107 tuner_info("Error %d while requesting firmware\n", rc);
108 return rc;
109 }
110 p=fw->data;
111 endp=p+fw->size;
112
113 if(fw->size==0) {
114 tuner_info("Error: firmware size is zero!\n");
115 rc=-EINVAL;
116 goto err;
117 }
118 if (fw->size<sizeof(firmware_ver)-1) {
119 /* Firmware is incorrect */
120 tuner_info("Error: firmware size is less than header (%d<%d)!\n",
121 (int)fw->size,(int)sizeof(firmware_ver)-1);
122 rc=-EINVAL;
123 goto err;
124 }
125
126 if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) {
127 /* Firmware is incorrect */
128 tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n");
129 rc=-EINVAL;
130 goto err;
131 }
132 p+=sizeof(firmware_ver)-1;
133
134 while(p<endp) {
135 if ((*p) & 0x80) {
136 /* Special callback command received */
137 rc = t->tuner_callback(c->adapter->algo_data,
138 XC2028_TUNER_RESET, (*p)&0x7f);
139 if (rc<0) {
140 tuner_info("Error at RESET code %d\n",
141 (*p)&0x7f);
142 goto err;
143 }
144 p++;
145 continue;
146 }
147 len=*p;
148 p++;
149 if (p+len+1>endp) {
150 /* Firmware is incorrect */
151 tuner_info("Error: firmware is truncated!\n");
152 rc=-EINVAL;
153 goto err;
154 }
155 if (len<=0) {
156 tuner_info("Error: firmware file is corrupted!\n");
157 rc=-EINVAL;
158 goto err;
159 }
160
161 i2c_send(rc, c, p, len);
162 if (rc<0)
163 goto err;
164 p+=len;
165
166 if (*p)
167 msleep(*p);
168 p++;
169 }
170
171
172err:
173 release_firmware(fw);
174
175 return rc;
176}
177
Michel Ludwig701672e2007-07-18 10:29:10 -0300178static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode,
179 fe_bandwidth_t bandwidth)
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300180{
181 int rc, version;
182 struct tuner *t = i2c_get_clientdata(c);
183 struct xc2028_data *xc2028 = t->priv;
184 const char *name;
Michel Ludwig701672e2007-07-18 10:29:10 -0300185 int change_digital_bandwidth;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300186
187 if (!t->tuner_callback) {
188 printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n");
189 return -EINVAL;
190 }
191
Michel Ludwig701672e2007-07-18 10:29:10 -0300192 printk(KERN_INFO "xc2028: I am in mode %u and I should switch to mode %i\n",
193 xc2028->mode, new_mode);
194
195 /* first of all, determine whether we have switched the mode */
196 if(new_mode != xc2028->mode) {
197 xc2028->mode = new_mode;
198 xc2028->need_load_generic = 1;
199 }
200
201 change_digital_bandwidth = (xc2028->mode == T_DIGITAL_TV
202 && bandwidth != xc2028->bandwidth) ? 1 : 0;
203 tuner_info("xc2028: old bandwidth %u, new bandwidth %u\n", xc2028->bandwidth,
204 bandwidth);
205
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300206 if (xc2028->need_load_generic) {
207 if (xc2028->bandwidth==6)
Michel Ludwig701672e2007-07-18 10:29:10 -0300208 name = firmware_INIT0;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300209 else
Michel Ludwig701672e2007-07-18 10:29:10 -0300210 name = firmware_8MHZ_INIT0;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300211 /* Reset is needed before loading firmware */
212 rc = t->tuner_callback(c->adapter->algo_data,
213 XC2028_TUNER_RESET, 0);
214 if (rc<0)
215 return rc;
216
217 rc = load_firmware(c,name);
218 if (rc<0)
219 return rc;
220
221 xc2028->need_load_generic=0;
222 xc2028->firm_type=0;
Michel Ludwig701672e2007-07-18 10:29:10 -0300223 if(xc2028->mode == T_DIGITAL_TV) {
224 change_digital_bandwidth=1;
225 }
226 }
227
228 tuner_info("xc2028: I should change bandwidth %u\n",
229 change_digital_bandwidth);
230
231 if (change_digital_bandwidth) {
232 switch(bandwidth) {
233 case BANDWIDTH_8_MHZ:
234 t->std = V4L2_STD_DTV_8MHZ;
235 break;
236
237 case BANDWIDTH_7_MHZ:
238 t->std = V4L2_STD_DTV_7MHZ;
239 break;
240
241 case BANDWIDTH_6_MHZ:
242 t->std = V4L2_STD_DTV_6MHZ;
243 break;
244
245 default:
246 tuner_info("error: bandwidth not supported.\n");
247 };
248 xc2028->bandwidth = bandwidth;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300249 }
250
251 if (xc2028->firm_type & t->std)
252 return 0;
253
Michel Ludwigc2622e52007-07-18 10:26:38 -0300254
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300255 if (t->std & V4L2_STD_MN)
256 name=firmware_MN;
Michel Ludwig701672e2007-07-18 10:29:10 -0300257 else if (t->std & V4L2_STD_DTV_6MHZ)
258 name=firmware_6M;
259 else if (t->std & V4L2_STD_DTV_7MHZ)
260 name=firmware_7M;
261 else if (t->std & V4L2_STD_DTV_8MHZ)
262 name=firmware_8M;
263 else if (t->std & V4L2_STD_PAL_B)
264 name=firmware_B;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300265 else
266 name=firmware_DK;
267
Michel Ludwig701672e2007-07-18 10:29:10 -0300268 tuner_info("xc2028: loading firmware named %s.\n", name);
269
270 rc = load_firmware(c, name);
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300271 if (rc<0)
272 return rc;
273
274 version = xc2028_get_reg(c, 0x4);
275 tuner_info("Firmware version is %d.%d\n",
276 (version>>4)&0x0f,(version)&0x0f);
277
278 xc2028->firm_type=t->std;
279
280 return 0;
281}
282
283static int xc2028_signal(struct i2c_client *c)
284{
285 int lock, signal;
286
Michel Ludwig701672e2007-07-18 10:29:10 -0300287 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300288
289 lock = xc2028_get_reg(c, 0x2);
290 if (lock<=0)
291 return lock;
292
293 /* Frequency is locked. Return signal quality */
294
295 signal = xc2028_get_reg(c, 0x40);
296
297 if(signal<=0)
298 return lock;
299
300 return signal;
301}
302
303#define DIV 15625
304
Michel Ludwig701672e2007-07-18 10:29:10 -0300305static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */,
306 enum tuner_mode new_mode, fe_bandwidth_t bandwidth)
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300307{
308 int rc;
309 unsigned char buf[5];
310 struct tuner *t = i2c_get_clientdata(c);
Michel Ludwig701672e2007-07-18 10:29:10 -0300311 u32 div, offset = 0;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300312
Michel Ludwig701672e2007-07-18 10:29:10 -0300313 printk("xc3028: should set frequency %d kHz)\n", freq / 1000);
314
315 if (check_firmware(c, new_mode, bandwidth)<0)
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300316 return;
317
Michel Ludwig701672e2007-07-18 10:29:10 -0300318 if(new_mode == T_DIGITAL_TV) {
319 switch(bandwidth) {
320 case BANDWIDTH_8_MHZ:
321 offset = 2750000;
322 break;
323
324 case BANDWIDTH_7_MHZ:
325 offset = 2750000;
326 break;
327
328 case BANDWIDTH_6_MHZ:
329 default:
330 printk(KERN_ERR "xc2028: bandwidth not implemented!\n");
331 }
332 }
333
334 div = (freq - offset + DIV/2)/DIV;
335
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300336 /* Reset GPIO 1 */
337 if (t->tuner_callback) {
338 rc = t->tuner_callback( c->adapter->algo_data,
339 XC2028_TUNER_RESET, 0);
340 if (rc<0)
341 return;
342 }
343 msleep(10);
344
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300345 /* CMD= Set frequency */
346 send_seq(c, {0x00, 0x02, 0x00, 0x00});
347 if (t->tuner_callback) {
348 rc = t->tuner_callback( c->adapter->algo_data,
349 XC2028_RESET_CLK, 1);
350 if (rc<0)
351 return;
352 }
353
354 msleep(10);
355// send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00});
356// msleep(100);
Michel Ludwig701672e2007-07-18 10:29:10 -0300357
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300358 buf[0]= 0xff & (div>>24);
359 buf[1]= 0xff & (div>>16);
360 buf[2]= 0xff & (div>>8);
361 buf[3]= 0xff & (div);
362 buf[4]= 0;
363
364 i2c_send(rc, c, buf, sizeof(buf));
365 if (rc<0)
366 return;
367 msleep(100);
368
369 printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
370 buf[1],buf[2],buf[3],buf[4],
371 freq / 16, freq % 16 * 100 / 16);
372// printk("signal=%d\n",xc2028_signal(c));
373}
374
375
Michel Ludwig701672e2007-07-18 10:29:10 -0300376static void set_tv_freq(struct i2c_client *c, unsigned int freq)
377{
378 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
379
380 generic_set_tv_freq(c, freq * 62500l, T_ANALOG_TV,
381 BANDWIDTH_8_MHZ /* unimportant */);
382}
383
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300384static void xc2028_release(struct i2c_client *c)
385{
386 struct tuner *t = i2c_get_clientdata(c);
387
388 kfree(t->priv);
389 t->priv = NULL;
390}
391
392static struct tuner_operations tea5767_tuner_ops = {
393 .set_tv_freq = set_tv_freq,
394 .has_signal = xc2028_signal,
395 .release = xc2028_release,
396// .is_stereo = xc2028_stereo,
397};
398
399
400static int init=0;
401
402int xc2028_tuner_init(struct i2c_client *c)
403{
404 struct tuner *t = i2c_get_clientdata(c);
405 int version = xc2028_get_reg(c, 0x4);
406 int prd_id = xc2028_get_reg(c, 0x8);
407 struct xc2028_data *xc2028;
408
Michel Ludwig701672e2007-07-18 10:29:10 -0300409 tuner_info("Xcv2028/3028 init called!\n");
410
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300411 if (init) {
412 printk (KERN_ERR "Module already initialized!\n");
413 return 0;
414 }
415 init++;
416
417 xc2028 = kzalloc(sizeof(*xc2028), GFP_KERNEL);
418 if (!xc2028)
419 return -ENOMEM;
420 t->priv = xc2028;
421
Michel Ludwig701672e2007-07-18 10:29:10 -0300422 xc2028->bandwidth=BANDWIDTH_6_MHZ;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300423 xc2028->need_load_generic=1;
Michel Ludwig701672e2007-07-18 10:29:10 -0300424 xc2028->mode = T_UNINITIALIZED;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300425
426 /* FIXME: Check where t->priv will be freed */
427
428 if (version<0)
429 version=0;
430
431 if (prd_id<0)
432 prd_id=0;
433
434 strlcpy(c->name, "xc2028", sizeof(c->name));
435 tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n",
436 t->type, c->name,
437 (version>>12)&0x0f,(version>>8)&0x0f,
438 (version>>4)&0x0f,(version)&0x0f, prd_id);
439
440 memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
441
442 return 0;
443}
Michel Ludwig701672e2007-07-18 10:29:10 -0300444
445static int xc3028_set_params(struct dvb_frontend *fe,
446 struct dvb_frontend_parameters *p)
447{
448 struct i2c_client *c = fe->tuner_priv;
449
450 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
451
452 generic_set_tv_freq(c, p->frequency, T_DIGITAL_TV,
453 p->u.ofdm.bandwidth);
454
455 return 0;
456}
457
458static int xc3028_dvb_release(struct dvb_frontend *fe)
459{
460 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
461
462 fe->tuner_priv = NULL;
463
464 return 0;
465}
466
467static int xc3028_dvb_init(struct dvb_frontend *fe)
468{
469 printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__);
470
471 return 0;
472}
473
474static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = {
475 .info = {
476 .name = "Xceive XC3028",
477 .frequency_min = 42000000,
478 .frequency_max = 864000000,
479 .frequency_step = 50000,
480 },
481
482 .release = xc3028_dvb_release,
483 .init = xc3028_dvb_init,
484
485// int (*sleep)(struct dvb_frontend *fe);
486
487 /** This is for simple PLLs - set all parameters in one go. */
488 .set_params = xc3028_set_params,
489
490 /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
491// int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
492
493// int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
494// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
495
496// int (*get_status)(struct dvb_frontend *fe, u32 *status);
497};
498
499int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe)
500{
501 fe->tuner_priv = c;
502
503 memcpy(&fe->ops.tuner_ops, &xc3028_dvb_tuner_ops, sizeof(fe->ops.tuner_ops));
504
505 return 0;
506}
507
508EXPORT_SYMBOL(xc2028_attach);
509