V4L/DVB (6430): Convert tuner-xc2028 driver to the newer hybrid approach
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / media / video / tuner-xc2028.c
CommitLineData
6cb45879
MCC
1/* tuner-xc2028
2 *
3 * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
701672eb
ML
4 * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
5 * - frontend interface
6cb45879
MCC
6 * 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>
701672eb 14#include <media/tuner.h>
3b20532c 15#include <linux/mutex.h>
215b95ba 16#include "tuner-i2c.h"
6cb45879
MCC
17#include "tuner-xc2028.h"
18
701672eb
ML
19#include <linux/dvb/frontend.h>
20#include "dvb_frontend.h"
21
215b95ba
MCC
22#define PREFIX "xc2028 "
23
24static LIST_HEAD(xc2028_list);
701672eb 25
6cb45879 26/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */
2e4160ca
MCC
27
28/* Generic firmwares */
29static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw";
30static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw";
31static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw";
32
33/* Standard-specific firmwares */
34static const char *firmware_6M = "tm_xc3028_DTV_6M.fw";
ff7326d4
ML
35static const char *firmware_7M = "tm_xc3028_DTV_7M.fw";
36static const char *firmware_8M = "tm_xc3028_DTV_8M.fw";
2e4160ca
MCC
37static const char *firmware_B = "tm_xc3028_B_PAL.fw";
38static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw";
39static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw";
6cb45879
MCC
40
41struct xc2028_data {
215b95ba
MCC
42 struct list_head xc2028_list;
43 struct tuner_i2c_props i2c_props;
44 int (*tuner_callback) (void *dev,
45 int command, int arg);
46 struct device *dev;
47 void *video_dev;
48 int count;
49 u32 frequency;
50
701672eb
ML
51 v4l2_std_id firm_type; /* video stds supported
52 by current firmware */
53 fe_bandwidth_t bandwidth; /* Firmware bandwidth:
54 6M, 7M or 8M */
55 int need_load_generic; /* The generic firmware
56 were loaded? */
57 enum tuner_mode mode;
58 struct i2c_client *i2c_client;
215b95ba
MCC
59
60 struct mutex lock;
6cb45879
MCC
61};
62
215b95ba
MCC
63#define i2c_send(rc, priv, buf, size) \
64if (size != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size))) \
65 tuner_info("i2c output error: rc = %d (should be %d)\n", \
6cb45879
MCC
66 rc, (int)size);
67
215b95ba
MCC
68#define i2c_rcv(rc, priv, buf, size) \
69if (size != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size))) \
70 tuner_info("i2c input error: rc = %d (should be %d)\n", \
6cb45879
MCC
71 rc, (int)size);
72
215b95ba 73#define send_seq(priv, data...) \
6cb45879 74{ int rc; \
215b95ba 75 static u8 _val[] = data; \
6cb45879 76 if (sizeof(_val) != \
215b95ba
MCC
77 (rc = tuner_i2c_xfer_send (&priv->i2c_props, \
78 _val, sizeof(_val)))) { \
79 tuner_info("Error on line %d: %d\n",__LINE__,rc); \
80 return -EINVAL; \
6cb45879
MCC
81 } \
82 msleep (10); \
83}
84
215b95ba 85static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
6cb45879
MCC
86{
87 int rc;
88 unsigned char buf[1];
215b95ba
MCC
89
90 tuner_info("%s called\n", __FUNCTION__);
6cb45879
MCC
91
92 buf[0]= reg;
93
215b95ba 94 i2c_send(rc, priv, buf, sizeof(buf));
6cb45879
MCC
95 if (rc<0)
96 return rc;
97
215b95ba 98 i2c_rcv(rc, priv, buf, 2);
6cb45879
MCC
99 if (rc<0)
100 return rc;
101
102 return (buf[1])|(buf[0]<<8);
103}
104
215b95ba 105static int load_firmware (struct dvb_frontend *fe, const char *name)
6cb45879 106{
215b95ba 107 struct xc2028_data *priv = fe->tuner_priv;
6cb45879 108 const struct firmware *fw=NULL;
6cb45879
MCC
109 unsigned char *p, *endp;
110 int len=0, rc=0;
111 static const char firmware_ver[] = "tm6000/xcv v1";
112
215b95ba
MCC
113 tuner_info("%s called\n", __FUNCTION__);
114
115 tuner_info("Loading firmware %s\n", name);
116 rc = request_firmware(&fw, name, priv->dev);
6cb45879 117 if (rc < 0) {
2e4160ca
MCC
118 if (rc==-ENOENT)
119 tuner_info("Error: firmware %s not found.\n", name);
120 else
121 tuner_info("Error %d while requesting firmware %s \n", rc, name);
122
6cb45879
MCC
123 return rc;
124 }
125 p=fw->data;
126 endp=p+fw->size;
127
128 if(fw->size==0) {
129 tuner_info("Error: firmware size is zero!\n");
130 rc=-EINVAL;
131 goto err;
132 }
133 if (fw->size<sizeof(firmware_ver)-1) {
134 /* Firmware is incorrect */
135 tuner_info("Error: firmware size is less than header (%d<%d)!\n",
136 (int)fw->size,(int)sizeof(firmware_ver)-1);
137 rc=-EINVAL;
138 goto err;
139 }
140
141 if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) {
142 /* Firmware is incorrect */
143 tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n");
144 rc=-EINVAL;
145 goto err;
146 }
147 p+=sizeof(firmware_ver)-1;
148
149 while(p<endp) {
150 if ((*p) & 0x80) {
151 /* Special callback command received */
215b95ba 152 rc = priv->tuner_callback(priv->video_dev,
6cb45879
MCC
153 XC2028_TUNER_RESET, (*p)&0x7f);
154 if (rc<0) {
155 tuner_info("Error at RESET code %d\n",
156 (*p)&0x7f);
157 goto err;
158 }
159 p++;
160 continue;
161 }
162 len=*p;
163 p++;
164 if (p+len+1>endp) {
165 /* Firmware is incorrect */
166 tuner_info("Error: firmware is truncated!\n");
167 rc=-EINVAL;
168 goto err;
169 }
170 if (len<=0) {
171 tuner_info("Error: firmware file is corrupted!\n");
172 rc=-EINVAL;
173 goto err;
174 }
175
215b95ba 176 i2c_send(rc, priv, p, len);
6cb45879
MCC
177 if (rc<0)
178 goto err;
179 p+=len;
180
181 if (*p)
182 msleep(*p);
183 p++;
184 }
185
186
187err:
188 release_firmware(fw);
189
190 return rc;
191}
192
215b95ba
MCC
193static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
194 v4l2_std_id std,
701672eb 195 fe_bandwidth_t bandwidth)
6cb45879 196{
215b95ba 197 struct xc2028_data *priv = fe->tuner_priv;
6cb45879 198 int rc, version;
6cb45879 199 const char *name;
701672eb 200 int change_digital_bandwidth;
6cb45879 201
215b95ba 202 tuner_info("%s called\n", __FUNCTION__);
6cb45879 203
215b95ba
MCC
204 tuner_info( "I am in mode %u and I should switch to mode %i\n",
205 priv->mode, new_mode);
701672eb
ML
206
207 /* first of all, determine whether we have switched the mode */
215b95ba
MCC
208 if(new_mode != priv->mode) {
209 priv->mode = new_mode;
210 priv->need_load_generic = 1;
701672eb
ML
211 }
212
215b95ba
MCC
213 change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
214 && bandwidth != priv->bandwidth) ? 1 : 0;
215 tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
701672eb
ML
216 bandwidth);
217
215b95ba
MCC
218 if (priv->need_load_generic) {
219 if (priv->bandwidth==8)
701672eb 220 name = firmware_8MHZ_INIT0;
2e4160ca
MCC
221 else
222 name = firmware_INIT0;
223
6cb45879 224 /* Reset is needed before loading firmware */
215b95ba
MCC
225 rc = priv->tuner_callback(priv->video_dev,
226 XC2028_TUNER_RESET, 0);
6cb45879
MCC
227 if (rc<0)
228 return rc;
229
215b95ba 230 rc = load_firmware(fe,name);
6cb45879
MCC
231 if (rc<0)
232 return rc;
233
215b95ba
MCC
234 priv->need_load_generic=0;
235 priv->firm_type=0;
236 if(priv->mode == T_DIGITAL_TV) {
701672eb
ML
237 change_digital_bandwidth=1;
238 }
239 }
240
215b95ba 241 tuner_info("I should change bandwidth %u\n",
701672eb
ML
242 change_digital_bandwidth);
243
215b95ba 244 /* FIXME: t->std makes no sense here */
701672eb
ML
245 if (change_digital_bandwidth) {
246 switch(bandwidth) {
247 case BANDWIDTH_8_MHZ:
215b95ba 248 std = V4L2_STD_DTV_8MHZ;
701672eb
ML
249 break;
250
251 case BANDWIDTH_7_MHZ:
215b95ba 252 std = V4L2_STD_DTV_7MHZ;
701672eb
ML
253 break;
254
255 case BANDWIDTH_6_MHZ:
215b95ba 256 std = V4L2_STD_DTV_6MHZ;
701672eb
ML
257 break;
258
259 default:
260 tuner_info("error: bandwidth not supported.\n");
261 };
215b95ba 262 priv->bandwidth = bandwidth;
6cb45879
MCC
263 }
264
215b95ba 265 if (priv->firm_type & std) {
2e4160ca 266 tuner_info("xc3028: no need to load a std-specific firmware.\n");
6cb45879 267 return 0;
2e4160ca 268 }
6cb45879 269
215b95ba 270 rc = load_firmware(fe,firmware_INIT1);
c2622e5f 271
215b95ba 272 if (std & V4L2_STD_MN)
6cb45879 273 name=firmware_MN;
215b95ba 274 else if (std & V4L2_STD_DTV_6MHZ)
701672eb 275 name=firmware_6M;
215b95ba 276 else if (std & V4L2_STD_DTV_7MHZ)
701672eb 277 name=firmware_7M;
215b95ba 278 else if (std & V4L2_STD_DTV_8MHZ)
701672eb 279 name=firmware_8M;
215b95ba 280 else if (std & V4L2_STD_PAL_B)
701672eb 281 name=firmware_B;
6cb45879
MCC
282 else
283 name=firmware_DK;
284
215b95ba
MCC
285 tuner_info("loading firmware named %s.\n", name);
286 rc = load_firmware(fe, name);
6cb45879
MCC
287 if (rc<0)
288 return rc;
289
215b95ba 290 version = xc2028_get_reg(priv, 0x4);
6cb45879
MCC
291 tuner_info("Firmware version is %d.%d\n",
292 (version>>4)&0x0f,(version)&0x0f);
293
215b95ba 294 priv->firm_type=std;
6cb45879
MCC
295
296 return 0;
297}
298
215b95ba 299static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
6cb45879 300{
215b95ba 301 struct xc2028_data *priv = fe->tuner_priv;
3b20532c
MCC
302 int frq_lock, signal=0;
303
215b95ba 304 tuner_info("%s called\n", __FUNCTION__);
6cb45879 305
215b95ba 306 mutex_lock(&priv->lock);
6cb45879 307
215b95ba
MCC
308 *strength = 0;
309
310 frq_lock = xc2028_get_reg(priv, 0x2);
3b20532c
MCC
311 if (frq_lock<=0)
312 goto ret;
6cb45879
MCC
313
314 /* Frequency is locked. Return signal quality */
315
215b95ba 316 signal = xc2028_get_reg(priv, 0x40);
6cb45879 317
3b20532c
MCC
318 if(signal<=0) {
319 signal=frq_lock;
320 }
321
322ret:
215b95ba
MCC
323 mutex_unlock(&priv->lock);
324
325 *strength = signal;
6cb45879 326
215b95ba 327 return 0;
6cb45879
MCC
328}
329
330#define DIV 15625
331
215b95ba
MCC
332static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
333 enum tuner_mode new_mode,
334 v4l2_std_id std,
335 fe_bandwidth_t bandwidth)
6cb45879 336{
215b95ba
MCC
337 struct xc2028_data *priv = fe->tuner_priv;
338 int rc=-EINVAL;
6cb45879 339 unsigned char buf[5];
701672eb 340 u32 div, offset = 0;
6cb45879 341
215b95ba
MCC
342 tuner_info("%s called\n", __FUNCTION__);
343
d4e76681
MCC
344 /* HACK: It seems that specific firmware need to be reloaded
345 when freq is changed */
701672eb 346
215b95ba 347 mutex_lock(&priv->lock);
3b20532c 348
215b95ba 349 priv->firm_type=0;
701672eb 350
6cb45879 351 /* Reset GPIO 1 */
215b95ba
MCC
352 rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0);
353 if (rc<0)
354 goto ret;
355
6cb45879 356 msleep(10);
215b95ba 357 tuner_info("should set frequency %d kHz)\n", freq / 1000);
6cb45879 358
215b95ba 359 if (check_firmware(fe, new_mode, std, bandwidth)<0)
3b20532c 360 goto ret;
2e4160ca 361
d4e76681
MCC
362 if(new_mode == T_DIGITAL_TV)
363 offset = 2750000;
2e4160ca 364
d4e76681 365 div = (freq - offset + DIV/2)/DIV;
2e4160ca 366
6cb45879 367 /* CMD= Set frequency */
215b95ba
MCC
368 send_seq(priv, {0x00, 0x02, 0x00, 0x00});
369 rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
370 if (rc<0)
371 goto ret;
6cb45879
MCC
372
373 msleep(10);
701672eb 374
6cb45879
MCC
375 buf[0]= 0xff & (div>>24);
376 buf[1]= 0xff & (div>>16);
377 buf[2]= 0xff & (div>>8);
378 buf[3]= 0xff & (div);
379 buf[4]= 0;
380
215b95ba 381 i2c_send(rc, priv, buf, sizeof(buf));
6cb45879 382 if (rc<0)
3b20532c 383 goto ret;
6cb45879
MCC
384 msleep(100);
385
215b95ba
MCC
386 priv->frequency=freq;
387
6cb45879
MCC
388 printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
389 buf[1],buf[2],buf[3],buf[4],
215b95ba 390 freq / 1000000, (freq%1000000)/10000);
3b20532c 391
215b95ba 392 rc=0;
6cb45879 393
215b95ba
MCC
394ret:
395 mutex_unlock(&priv->lock);
6cb45879 396
215b95ba 397 return rc;
701672eb
ML
398}
399
215b95ba
MCC
400static int xc2028_set_tv_freq(struct dvb_frontend *fe,
401 struct analog_parameters *p)
6cb45879 402{
215b95ba 403 struct xc2028_data *priv = fe->tuner_priv;
6cb45879 404
215b95ba 405 tuner_info("%s called\n", __FUNCTION__);
6cb45879 406
215b95ba
MCC
407 return generic_set_tv_freq(fe, 62500l*p->frequency, T_ANALOG_TV,
408 p->std,
409 BANDWIDTH_8_MHZ /* NOT USED */);
410}
6cb45879 411
215b95ba
MCC
412static int xc2028_set_params(struct dvb_frontend *fe,
413 struct dvb_frontend_parameters *p)
6cb45879 414{
215b95ba 415 struct xc2028_data *priv = fe->tuner_priv;
6cb45879 416
215b95ba 417 tuner_info("%s called\n", __FUNCTION__);
701672eb 418
215b95ba
MCC
419 /* FIXME: Only OFDM implemented */
420 if (fe->ops.info.type != FE_OFDM) {
421 tuner_info ("DTV type not implemented.\n");
422 return -EINVAL;
6cb45879 423 }
6cb45879 424
215b95ba
MCC
425 return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV,
426 0, /* NOT USED */
427 p->u.ofdm.bandwidth);
6cb45879 428
6cb45879 429}
701672eb 430
215b95ba 431static int xc2028_dvb_release(struct dvb_frontend *fe)
701672eb 432{
215b95ba
MCC
433 struct xc2028_data *priv = fe->tuner_priv;
434
435 tuner_info("%s called\n", __FUNCTION__);
701672eb 436
215b95ba 437 priv->count--;
701672eb 438
215b95ba
MCC
439 if (!priv->count)
440 kfree (priv);
701672eb
ML
441
442 return 0;
443}
444
215b95ba 445static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
701672eb 446{
215b95ba 447 struct xc2028_data *priv = fe->tuner_priv;
701672eb 448
215b95ba 449 tuner_info("%s called\n", __FUNCTION__);
701672eb 450
215b95ba 451 *frequency = priv->frequency;
701672eb
ML
452
453 return 0;
454}
455
215b95ba 456static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
701672eb
ML
457 .info = {
458 .name = "Xceive XC3028",
459 .frequency_min = 42000000,
460 .frequency_max = 864000000,
461 .frequency_step = 50000,
462 },
463
215b95ba
MCC
464 .set_analog_params = xc2028_set_tv_freq,
465 .release = xc2028_dvb_release,
466 .get_frequency = xc2028_get_frequency,
467 .get_rf_strength = xc2028_signal,
468 .set_params = xc2028_set_params,
701672eb
ML
469
470// int (*sleep)(struct dvb_frontend *fe);
701672eb 471// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
701672eb
ML
472// int (*get_status)(struct dvb_frontend *fe, u32 *status);
473};
474
215b95ba
MCC
475int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
476 u8 i2c_addr, struct device *dev, void *video_dev,
477 int (*tuner_callback) (void *dev, int command,int arg))
701672eb 478{
215b95ba 479 struct xc2028_data *priv;
701672eb 480
215b95ba 481 printk( KERN_INFO PREFIX "Xcv2028/3028 init called!\n");
701672eb 482
215b95ba
MCC
483 if (NULL == dev)
484 return -ENODEV;
485
486 if (NULL == video_dev)
487 return -ENODEV;
488
489 if (!tuner_callback) {
490 printk( KERN_ERR PREFIX "No tuner callback!\n");
491 return -EINVAL;
492 }
493
494 list_for_each_entry(priv, &xc2028_list, xc2028_list) {
495 if (priv->dev == dev) {
496 dev = NULL;
497 priv->count++;
498 }
499 }
500
501 if (dev) {
502 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
503 if (priv == NULL)
504 return -ENOMEM;
701672eb 505
215b95ba 506 fe->tuner_priv = priv;
3b20532c 507
215b95ba
MCC
508 priv->bandwidth=BANDWIDTH_6_MHZ;
509 priv->need_load_generic=1;
510 priv->mode = T_UNINITIALIZED;
511 priv->i2c_props.addr = i2c_addr;
512 priv->i2c_props.adap = i2c_adap;
513 priv->dev = dev;
514 priv->video_dev = video_dev;
515 priv->tuner_callback = tuner_callback;
516
517 mutex_init(&priv->lock);
518
519 list_add_tail(&priv->xc2028_list,&xc2028_list);
520 }
521
522 memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
523 sizeof(xc2028_dvb_tuner_ops));
524
525 tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
526
527 return 0;
528}
3b20532c 529
701672eb
ML
530EXPORT_SYMBOL(xc2028_attach);
531
215b95ba
MCC
532MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
533MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
534MODULE_LICENSE("GPL");