3 * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
4 * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
6 * This code is placed under the terms of the GNU General Public License v2
10 #include <asm/div64.h>
11 #include <linux/firmware.h>
12 #include <linux/videodev.h>
13 #include <linux/delay.h>
14 #include <media/tuner.h>
15 #include "tuner-driver.h"
16 #include "tuner-xc2028.h"
18 #include <linux/dvb/frontend.h>
19 #include "dvb_frontend.h"
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)
26 /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */
28 /* Generic firmwares */
29 static const char *firmware_INIT0
= "tm_xc3028_MTS_init0.fw";
30 static const char *firmware_8MHZ_INIT0
= "tm_xc3028_8M_MTS_init0.fw";
31 static const char *firmware_INIT1
= "tm_xc3028_68M_MTS_init1.fw";
33 /* Standard-specific firmwares */
34 static const char *firmware_6M
= "tm_xc3028_DTV_6M.fw";
35 static const char *firmware_7M
= "tm_xc3028_7M.fw";
36 static const char *firmware_8M
= "tm_xc3028_8M.fw";
37 static const char *firmware_B
= "tm_xc3028_B_PAL.fw";
38 static const char *firmware_DK
= "tm_xc3028_DK_PAL_MTS.fw";
39 static const char *firmware_MN
= "tm_xc3028_MN_BTSC.fw";
42 v4l2_std_id firm_type
; /* video stds supported
43 by current firmware */
44 fe_bandwidth_t bandwidth
; /* Firmware bandwidth:
46 int need_load_generic
; /* The generic firmware
49 struct i2c_client
*i2c_client
;
52 #define i2c_send(rc,c,buf,size) \
53 if (size != (rc = i2c_master_send(c, buf, size))) \
54 tuner_warn("i2c output error: rc = %d (should be %d)\n", \
57 #define i2c_rcv(rc,c,buf,size) \
58 if (size != (rc = i2c_master_recv(c, buf, size))) \
59 tuner_warn("i2c input error: rc = %d (should be %d)\n", \
62 #define send_seq(c, data...) \
64 const static u8 _val[] = data; \
66 (rc = i2c_master_send \
67 (c, _val, sizeof(_val)))) { \
68 printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \
74 static int xc2028_get_reg(struct i2c_client
*c
, u16 reg
)
78 struct tuner
*t
= i2c_get_clientdata(c
);
82 i2c_send(rc
, c
, buf
, sizeof(buf
));
86 i2c_rcv(rc
, c
, buf
, 2);
90 return (buf
[1])|(buf
[0]<<8);
93 static int load_firmware (struct i2c_client
*c
, const char *name
)
95 const struct firmware
*fw
=NULL
;
96 struct tuner
*t
= i2c_get_clientdata(c
);
97 unsigned char *p
, *endp
;
99 static const char firmware_ver
[] = "tm6000/xcv v1";
101 tuner_info("xc2028: Loading firmware %s\n", name
);
102 rc
= request_firmware(&fw
, name
, &c
->dev
);
105 tuner_info("Error: firmware %s not found.\n", name
);
107 tuner_info("Error %d while requesting firmware %s \n", rc
, name
);
115 tuner_info("Error: firmware size is zero!\n");
119 if (fw
->size
<sizeof(firmware_ver
)-1) {
120 /* Firmware is incorrect */
121 tuner_info("Error: firmware size is less than header (%d<%d)!\n",
122 (int)fw
->size
,(int)sizeof(firmware_ver
)-1);
127 if (memcmp(p
,firmware_ver
,sizeof(firmware_ver
)-1)) {
128 /* Firmware is incorrect */
129 tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n");
133 p
+=sizeof(firmware_ver
)-1;
137 /* Special callback command received */
138 rc
= t
->tuner_callback(c
->adapter
->algo_data
,
139 XC2028_TUNER_RESET
, (*p
)&0x7f);
141 tuner_info("Error at RESET code %d\n",
151 /* Firmware is incorrect */
152 tuner_info("Error: firmware is truncated!\n");
157 tuner_info("Error: firmware file is corrupted!\n");
162 i2c_send(rc
, c
, p
, len
);
174 release_firmware(fw
);
179 static int check_firmware(struct i2c_client
*c
, enum tuner_mode new_mode
,
180 fe_bandwidth_t bandwidth
)
183 struct tuner
*t
= i2c_get_clientdata(c
);
184 struct xc2028_data
*xc2028
= t
->priv
;
186 int change_digital_bandwidth
;
188 if (!t
->tuner_callback
) {
189 printk(KERN_ERR
"xc2028: need tuner_callback to load firmware\n");
193 printk(KERN_INFO
"xc2028: I am in mode %u and I should switch to mode %i\n",
194 xc2028
->mode
, new_mode
);
196 /* first of all, determine whether we have switched the mode */
197 if(new_mode
!= xc2028
->mode
) {
198 xc2028
->mode
= new_mode
;
199 xc2028
->need_load_generic
= 1;
202 change_digital_bandwidth
= (xc2028
->mode
== T_DIGITAL_TV
203 && bandwidth
!= xc2028
->bandwidth
) ? 1 : 0;
204 tuner_info("xc2028: old bandwidth %u, new bandwidth %u\n", xc2028
->bandwidth
,
207 if (xc2028
->need_load_generic
) {
208 if (xc2028
->bandwidth
==8)
209 name
= firmware_8MHZ_INIT0
;
211 name
= firmware_INIT0
;
213 /* Reset is needed before loading firmware */
214 rc
= t
->tuner_callback(c
->adapter
->algo_data
,
215 XC2028_TUNER_RESET
, 0);
219 rc
= load_firmware(c
,name
);
223 xc2028
->need_load_generic
=0;
225 if(xc2028
->mode
== T_DIGITAL_TV
) {
226 change_digital_bandwidth
=1;
230 tuner_info("xc2028: I should change bandwidth %u\n",
231 change_digital_bandwidth
);
233 if (change_digital_bandwidth
) {
235 case BANDWIDTH_8_MHZ
:
236 t
->std
= V4L2_STD_DTV_8MHZ
;
239 case BANDWIDTH_7_MHZ
:
240 t
->std
= V4L2_STD_DTV_7MHZ
;
243 case BANDWIDTH_6_MHZ
:
244 t
->std
= V4L2_STD_DTV_6MHZ
;
248 tuner_info("error: bandwidth not supported.\n");
250 xc2028
->bandwidth
= bandwidth
;
253 if (xc2028
->firm_type
& t
->std
) {
254 tuner_info("xc3028: no need to load a std-specific firmware.\n");
258 rc
= load_firmware(c
,firmware_INIT1
);
260 if (t
->std
& V4L2_STD_MN
)
262 else if (t
->std
& V4L2_STD_DTV_6MHZ
)
264 else if (t
->std
& V4L2_STD_DTV_7MHZ
)
266 else if (t
->std
& V4L2_STD_DTV_8MHZ
)
268 else if (t
->std
& V4L2_STD_PAL_B
)
273 tuner_info("xc2028: loading firmware named %s.\n", name
);
274 rc
= load_firmware(c
, name
);
278 version
= xc2028_get_reg(c
, 0x4);
279 tuner_info("Firmware version is %d.%d\n",
280 (version
>>4)&0x0f,(version
)&0x0f);
282 xc2028
->firm_type
=t
->std
;
287 static int xc2028_signal(struct i2c_client
*c
)
291 printk(KERN_INFO
"xc2028: %s called\n", __FUNCTION__
);
293 lock
= xc2028_get_reg(c
, 0x2);
297 /* Frequency is locked. Return signal quality */
299 signal
= xc2028_get_reg(c
, 0x40);
309 static void generic_set_tv_freq(struct i2c_client
*c
, u32 freq
/* in Hz */,
310 enum tuner_mode new_mode
, fe_bandwidth_t bandwidth
)
313 unsigned char buf
[5];
314 struct tuner
*t
= i2c_get_clientdata(c
);
317 printk("xc3028: should set frequency %d kHz)\n", freq
/ 1000);
319 if (check_firmware(c
, new_mode
, bandwidth
)<0)
322 if(new_mode
== T_DIGITAL_TV
) {
324 case BANDWIDTH_8_MHZ
:
328 case BANDWIDTH_7_MHZ
:
332 case BANDWIDTH_6_MHZ
:
334 printk(KERN_ERR
"xc2028: bandwidth not implemented!\n");
338 div
= (freq
- offset
+ DIV
/2)/DIV
;
341 if (t
->tuner_callback
) {
342 rc
= t
->tuner_callback( c
->adapter
->algo_data
,
343 XC2028_TUNER_RESET
, 0);
351 rc
= load_firmware(c
,firmware_INIT1
);
353 if (t
->std
& V4L2_STD_MN
)
358 rc
= load_firmware(c
,name
);
359 /* CMD= Set frequency */
360 send_seq(c
, {0x00, 0x02, 0x00, 0x00});
361 if (t
->tuner_callback
) {
362 rc
= t
->tuner_callback( c
->adapter
->algo_data
,
363 XC2028_RESET_CLK
, 1);
369 // send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00});
372 buf
[0]= 0xff & (div
>>24);
373 buf
[1]= 0xff & (div
>>16);
374 buf
[2]= 0xff & (div
>>8);
375 buf
[3]= 0xff & (div
);
378 i2c_send(rc
, c
, buf
, sizeof(buf
));
383 printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
384 buf
[1],buf
[2],buf
[3],buf
[4],
385 freq
/ 16, freq
% 16 * 100 / 16);
386 // printk("signal=%d\n",xc2028_signal(c));
390 static void set_tv_freq(struct i2c_client
*c
, unsigned int freq
)
392 printk(KERN_INFO
"xc2028: %s called\n", __FUNCTION__
);
394 generic_set_tv_freq(c
, freq
* 62500l, T_ANALOG_TV
,
395 BANDWIDTH_8_MHZ
/* unimportant */);
398 static void xc2028_release(struct i2c_client
*c
)
400 struct tuner
*t
= i2c_get_clientdata(c
);
406 static struct tuner_operations tea5767_tuner_ops
= {
407 .set_tv_freq
= set_tv_freq
,
408 .has_signal
= xc2028_signal
,
409 .release
= xc2028_release
,
410 // .is_stereo = xc2028_stereo,
416 int xc2028_tuner_init(struct i2c_client
*c
)
418 struct tuner
*t
= i2c_get_clientdata(c
);
419 int version
= xc2028_get_reg(c
, 0x4);
420 int prd_id
= xc2028_get_reg(c
, 0x8);
421 struct xc2028_data
*xc2028
;
423 tuner_info("Xcv2028/3028 init called!\n");
426 printk (KERN_ERR
"Module already initialized!\n");
431 xc2028
= kzalloc(sizeof(*xc2028
), GFP_KERNEL
);
436 xc2028
->bandwidth
=BANDWIDTH_6_MHZ
;
437 xc2028
->need_load_generic
=1;
438 xc2028
->mode
= T_UNINITIALIZED
;
440 /* FIXME: Check where t->priv will be freed */
448 strlcpy(c
->name
, "xc2028", sizeof(c
->name
));
449 tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n",
451 (version
>>12)&0x0f,(version
>>8)&0x0f,
452 (version
>>4)&0x0f,(version
)&0x0f, prd_id
);
454 memcpy(&t
->ops
, &tea5767_tuner_ops
, sizeof(struct tuner_operations
));
459 static int xc3028_set_params(struct dvb_frontend
*fe
,
460 struct dvb_frontend_parameters
*p
)
462 struct i2c_client
*c
= fe
->tuner_priv
;
464 printk(KERN_INFO
"xc2028: %s called\n", __FUNCTION__
);
466 generic_set_tv_freq(c
, p
->frequency
, T_DIGITAL_TV
,
467 p
->u
.ofdm
.bandwidth
);
472 static int xc3028_dvb_release(struct dvb_frontend
*fe
)
474 printk(KERN_INFO
"xc2028: %s called\n", __FUNCTION__
);
476 fe
->tuner_priv
= NULL
;
481 static int xc3028_dvb_init(struct dvb_frontend
*fe
)
483 printk(KERN_INFO
"xc2028: %s called\n", __FUNCTION__
);
488 static const struct dvb_tuner_ops xc3028_dvb_tuner_ops
= {
490 .name
= "Xceive XC3028",
491 .frequency_min
= 42000000,
492 .frequency_max
= 864000000,
493 .frequency_step
= 50000,
496 .release
= xc3028_dvb_release
,
497 .init
= xc3028_dvb_init
,
499 // int (*sleep)(struct dvb_frontend *fe);
501 /** This is for simple PLLs - set all parameters in one go. */
502 .set_params
= xc3028_set_params
,
504 /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
505 // int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
507 // int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
508 // int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
510 // int (*get_status)(struct dvb_frontend *fe, u32 *status);
513 int xc2028_attach(struct i2c_client
*c
, struct dvb_frontend
*fe
)
517 memcpy(&fe
->ops
.tuner_ops
, &xc3028_dvb_tuner_ops
, sizeof(fe
->ops
.tuner_ops
));
522 EXPORT_SYMBOL(xc2028_attach
);