tuner-xc2028.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. /* tuner-xc2028
  2. *
  3. * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
  4. *
  5. * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
  6. * - frontend interface
  7. *
  8. * This code is placed under the terms of the GNU General Public License v2
  9. */
  10. #include <linux/i2c.h>
  11. #include <asm/div64.h>
  12. #include <linux/firmware.h>
  13. #include <linux/videodev.h>
  14. #include <linux/delay.h>
  15. #include <media/tuner.h>
  16. #include <linux/mutex.h>
  17. #include "tuner-i2c.h"
  18. #include "tuner-xc2028.h"
  19. #include "tuner-xc2028-types.h"
  20. #include <linux/dvb/frontend.h>
  21. #include "dvb_frontend.h"
  22. #define PREFIX "xc2028 "
  23. static LIST_HEAD(xc2028_list);
  24. /* struct for storing firmware table */
  25. struct firmware_description {
  26. unsigned int type;
  27. v4l2_std_id id;
  28. unsigned char *ptr;
  29. unsigned int size;
  30. };
  31. struct xc2028_data {
  32. struct list_head xc2028_list;
  33. struct tuner_i2c_props i2c_props;
  34. int (*tuner_callback) (void *dev,
  35. int command, int arg);
  36. struct device *dev;
  37. void *video_dev;
  38. int count;
  39. __u32 frequency;
  40. struct firmware_description *firm;
  41. int firm_size;
  42. __u16 version;
  43. struct xc2028_ctrl ctrl;
  44. v4l2_std_id firm_type; /* video stds supported
  45. by current firmware */
  46. fe_bandwidth_t bandwidth; /* Firmware bandwidth:
  47. 6M, 7M or 8M */
  48. int need_load_generic; /* The generic firmware
  49. were loaded? */
  50. int max_len; /* Max firmware chunk */
  51. enum tuner_mode mode;
  52. struct i2c_client *i2c_client;
  53. struct mutex lock;
  54. };
  55. #define i2c_send(rc, priv, buf, size) \
  56. if (size != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size))) \
  57. tuner_info("i2c output error: rc = %d (should be %d)\n", \
  58. rc, (int)size);
  59. #define i2c_rcv(rc, priv, buf, size) \
  60. if (size != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size))) \
  61. tuner_info("i2c input error: rc = %d (should be %d)\n", \
  62. rc, (int)size);
  63. #define send_seq(priv, data...) \
  64. { int rc; \
  65. static u8 _val[] = data; \
  66. if (sizeof(_val) != \
  67. (rc = tuner_i2c_xfer_send (&priv->i2c_props, \
  68. _val, sizeof(_val)))) { \
  69. tuner_info("Error on line %d: %d\n",__LINE__,rc); \
  70. return -EINVAL; \
  71. } \
  72. msleep (10); \
  73. }
  74. static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
  75. {
  76. int rc;
  77. unsigned char buf[1];
  78. tuner_info("%s called\n", __FUNCTION__);
  79. buf[0]= reg;
  80. i2c_send(rc, priv, buf, sizeof(buf));
  81. if (rc<0)
  82. return rc;
  83. i2c_rcv(rc, priv, buf, 2);
  84. if (rc<0)
  85. return rc;
  86. return (buf[1])|(buf[0]<<8);
  87. }
  88. static void free_firmware (struct xc2028_data *priv)
  89. {
  90. int i;
  91. if (!priv->firm)
  92. return;
  93. for (i=0;i<priv->firm_size;i++) {
  94. if (priv->firm[i].ptr)
  95. kfree(priv->firm[i].ptr);
  96. }
  97. kfree(priv->firm);
  98. priv->firm=NULL;
  99. priv->need_load_generic = 1;
  100. }
  101. static int load_all_firmwares (struct dvb_frontend *fe)
  102. {
  103. struct xc2028_data *priv = fe->tuner_priv;
  104. const struct firmware *fw=NULL;
  105. unsigned char *p, *endp;
  106. int rc=0, n, n_array;
  107. char name[33];
  108. tuner_info("%s called\n", __FUNCTION__);
  109. tuner_info("Loading firmware %s\n", priv->ctrl.fname);
  110. rc = request_firmware(&fw, priv->ctrl.fname, priv->dev);
  111. if (rc < 0) {
  112. if (rc==-ENOENT)
  113. tuner_info("Error: firmware %s not found.\n",
  114. priv->ctrl.fname);
  115. else
  116. tuner_info("Error %d while requesting firmware %s \n",
  117. rc, priv->ctrl.fname);
  118. return rc;
  119. }
  120. p=fw->data;
  121. endp=p+fw->size;
  122. if(fw->size<sizeof(name)-1+2) {
  123. tuner_info("Error: firmware size is zero!\n");
  124. rc=-EINVAL;
  125. goto done;
  126. }
  127. memcpy(name,p,sizeof(name)-1);
  128. name[sizeof(name)-1]=0;
  129. p+=sizeof(name)-1;
  130. priv->version = le16_to_cpu(*(__u16 *)p);
  131. p += 2;
  132. tuner_info("firmware: %s, ver %d.%d\n", name,
  133. priv->version>>8, priv->version&0xff);
  134. if (p+2>endp)
  135. goto corrupt;
  136. n_array = le16_to_cpu(*(__u16 *)p);
  137. p += 2;
  138. tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname);
  139. priv->firm=kzalloc(sizeof(*priv->firm)*n_array,GFP_KERNEL);
  140. if (!fw) {
  141. tuner_info("Not enough memory for loading firmware.\n");
  142. rc=-ENOMEM;
  143. goto done;
  144. }
  145. priv->firm_size = n_array;
  146. n=-1;
  147. while (p<endp) {
  148. __u32 type, size;
  149. v4l2_std_id id;
  150. n++;
  151. if (n >= n_array) {
  152. tuner_info("Too much firmwares at the file\n");
  153. goto corrupt;
  154. }
  155. /* Checks if there's enough bytes to read */
  156. if (p+sizeof(type)+sizeof(id)+sizeof(size)>endp) {
  157. tuner_info("Lost firmware!\n");
  158. goto corrupt;
  159. }
  160. type = le32_to_cpu(*(__u32 *)p);
  161. p += sizeof(type);
  162. id = le64_to_cpu(*(v4l2_std_id *)p);
  163. p += sizeof(id);
  164. size = le32_to_cpu(*(v4l2_std_id *)p);
  165. p += sizeof(size);
  166. if ((!size)||(size+p>endp)) {
  167. tuner_info("Firmware type %x, id %lx corrupt\n",
  168. type, (unsigned long) id);
  169. goto corrupt;
  170. }
  171. priv->firm[n].ptr=kzalloc(size,GFP_KERNEL);
  172. if (!priv->firm[n].ptr) {
  173. tuner_info("Not enough memory.\n");
  174. rc=-ENOMEM;
  175. goto err;
  176. }
  177. tuner_info("Loading firmware type %x, id %lx, size=%d.\n",
  178. type, (unsigned long) id, size);
  179. memcpy(priv->firm[n].ptr, p, size);
  180. priv->firm[n].type = type;
  181. priv->firm[n].id = id;
  182. priv->firm[n].size = size;
  183. p += size;
  184. }
  185. if (n+1 != priv->firm_size) {
  186. tuner_info("Firmware file is incomplete!\n");
  187. goto corrupt;
  188. }
  189. goto done;
  190. corrupt:
  191. rc=-EINVAL;
  192. tuner_info("Error: firmware file is corrupted!\n");
  193. err:
  194. tuner_info("Releasing loaded firmware file.\n");
  195. free_firmware(priv);
  196. done:
  197. release_firmware(fw);
  198. tuner_info("Firmware files loaded.\n");
  199. return rc;
  200. }
  201. static int load_firmware (struct dvb_frontend *fe, unsigned int type,
  202. v4l2_std_id *id)
  203. {
  204. struct xc2028_data *priv = fe->tuner_priv;
  205. int i, rc;
  206. unsigned char *p, *endp, buf[priv->max_len];
  207. tuner_info("%s called\n", __FUNCTION__);
  208. if (!priv->firm) {
  209. printk (KERN_ERR PREFIX "Error! firmware not loaded\n");
  210. return -EINVAL;
  211. }
  212. if ((type == 0) && (*id == 0))
  213. *id=V4L2_STD_PAL;
  214. /* Seek for exact match */
  215. for (i=0;i<priv->firm_size;i++) {
  216. if ( (type == priv->firm[i].type) &&
  217. (*id == priv->firm[i].id))
  218. goto found;
  219. }
  220. /* Seek for generic video standard match */
  221. for (i=0;i<priv->firm_size;i++) {
  222. if ( (type == priv->firm[i].type) && (*id & priv->firm[i].id))
  223. goto found;
  224. }
  225. /*FIXME: Would make sense to seek for type "hint" match ? */
  226. tuner_info ("Can't find firmware for type=%x, id=%lx\n", type,
  227. (long int)*id);
  228. return -EINVAL;
  229. found:
  230. *id = priv->firm[i].id;
  231. tuner_info ("Found firmware for type=%x, id=%lx\n", type,
  232. (long int)*id);
  233. p = priv->firm[i].ptr;
  234. if (!p) {
  235. printk(KERN_ERR PREFIX "Firmware pointer were freed!");
  236. return -EINVAL;
  237. }
  238. endp = p+priv->firm[i].size;
  239. while (p<endp) {
  240. __u16 size;
  241. /* Checks if there's enough bytes to read */
  242. if (p+sizeof(size)>endp) {
  243. tuner_info("missing bytes\n");
  244. return -EINVAL;
  245. }
  246. size = le16_to_cpu(*(__u16 *)p);
  247. p += sizeof(size);
  248. if (size == 0xffff)
  249. return 0;
  250. if (!size) {
  251. /* Special callback command received */
  252. rc = priv->tuner_callback(priv->video_dev,
  253. XC2028_TUNER_RESET, 0);
  254. if (rc<0) {
  255. tuner_info("Error at RESET code %d\n",
  256. (*p)&0x7f);
  257. return -EINVAL;
  258. }
  259. continue;
  260. }
  261. /* Checks for a sleep command */
  262. if (size & 0x8000) {
  263. msleep (size & 0x7fff);
  264. continue;
  265. }
  266. if ((size + p > endp)) {
  267. tuner_info("missing bytes: need %d, have %d\n",
  268. size, (int)(endp-p));
  269. return -EINVAL;
  270. }
  271. buf[0] = *p;
  272. p++;
  273. size--;
  274. /* Sends message chunks */
  275. while (size>0) {
  276. int len = (size<priv->max_len-1)?size:priv->max_len-1;
  277. memcpy(buf+1, p, len);
  278. i2c_send(rc, priv, buf, len+1);
  279. if (rc<0) {
  280. tuner_info("%d returned from send\n",rc);
  281. return -EINVAL;
  282. }
  283. p += len;
  284. size -= len;
  285. }
  286. }
  287. return -EINVAL;
  288. }
  289. static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
  290. v4l2_std_id std,
  291. fe_bandwidth_t bandwidth)
  292. {
  293. struct xc2028_data *priv = fe->tuner_priv;
  294. int rc, version;
  295. v4l2_std_id std0=0;
  296. unsigned int type0=0,type=0;
  297. int change_digital_bandwidth;
  298. tuner_info("%s called\n", __FUNCTION__);
  299. if (!priv->firm) {
  300. if (!priv->ctrl.fname)
  301. return -EINVAL;
  302. rc=load_all_firmwares(fe);
  303. if (rc<0)
  304. return rc;
  305. }
  306. tuner_info( "I am in mode %u and I should switch to mode %i\n",
  307. priv->mode, new_mode);
  308. /* first of all, determine whether we have switched the mode */
  309. if(new_mode != priv->mode) {
  310. priv->mode = new_mode;
  311. priv->need_load_generic = 1;
  312. }
  313. change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
  314. && bandwidth != priv->bandwidth) ? 1 : 0;
  315. tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
  316. bandwidth);
  317. if (priv->need_load_generic) {
  318. /* Reset is needed before loading firmware */
  319. rc = priv->tuner_callback(priv->video_dev,
  320. XC2028_TUNER_RESET, 0);
  321. if (rc<0)
  322. return rc;
  323. type0=BASE;
  324. if (priv->ctrl.type == XC2028_FIRM_MTS)
  325. type0 |= MTS;
  326. if (priv->bandwidth==8)
  327. type0 |= F8MHZ;
  328. /* FIXME: How to load FM and FM|INPUT1 firmwares? */
  329. rc = load_firmware(fe, type0, &std0);
  330. if (rc<0) {
  331. tuner_info("Error %d while loading generic firmware\n",
  332. rc);
  333. return rc;
  334. }
  335. priv->need_load_generic=0;
  336. priv->firm_type=0;
  337. if(priv->mode == T_DIGITAL_TV) {
  338. change_digital_bandwidth=1;
  339. }
  340. }
  341. tuner_info("I should change bandwidth %u\n",
  342. change_digital_bandwidth);
  343. if (change_digital_bandwidth) {
  344. /*FIXME: Should allow selecting between D2620 and D2633 */
  345. type |= D2620;
  346. /* FIXME: When should select a DTV78 firmware?
  347. */
  348. switch(bandwidth) {
  349. case BANDWIDTH_8_MHZ:
  350. type |= DTV8;
  351. break;
  352. case BANDWIDTH_7_MHZ:
  353. type |= DTV7;
  354. break;
  355. case BANDWIDTH_6_MHZ:
  356. /* FIXME: Should allow select also ATSC */
  357. type |= DTV6_QAM;
  358. break;
  359. default:
  360. tuner_info("error: bandwidth not supported.\n");
  361. };
  362. priv->bandwidth = bandwidth;
  363. }
  364. /* Load INIT1, if needed */
  365. tuner_info("Trying to load init1 firmware\n");
  366. type0 = BASE | INIT1 | priv->ctrl.type;
  367. if (priv->ctrl.type == XC2028_FIRM_MTS)
  368. type0 |= MTS;
  369. /* FIXME: Should handle errors - if INIT1 found */
  370. rc = load_firmware(fe, type0, &std0);
  371. /* FIXME: Should add support for FM radio
  372. */
  373. if (priv->ctrl.type == XC2028_FIRM_MTS)
  374. type |= MTS;
  375. tuner_info("firmware standard to load: %08lx\n",(unsigned long) std);
  376. if (priv->firm_type & std) {
  377. tuner_info("no need to load a std-specific firmware.\n");
  378. return 0;
  379. }
  380. rc = load_firmware(fe, type, &std);
  381. if (rc<0)
  382. return rc;
  383. version = xc2028_get_reg(priv, 0x4);
  384. tuner_info("Firmware version is %d.%d\n",
  385. (version>>4)&0x0f,(version)&0x0f);
  386. priv->firm_type=std;
  387. return 0;
  388. }
  389. static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
  390. {
  391. struct xc2028_data *priv = fe->tuner_priv;
  392. int frq_lock, signal=0;
  393. tuner_info("%s called\n", __FUNCTION__);
  394. mutex_lock(&priv->lock);
  395. *strength = 0;
  396. frq_lock = xc2028_get_reg(priv, 0x2);
  397. if (frq_lock<=0)
  398. goto ret;
  399. /* Frequency is locked. Return signal quality */
  400. signal = xc2028_get_reg(priv, 0x40);
  401. if(signal<=0) {
  402. signal=frq_lock;
  403. }
  404. ret:
  405. mutex_unlock(&priv->lock);
  406. *strength = signal;
  407. return 0;
  408. }
  409. #define DIV 15625
  410. static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
  411. enum tuner_mode new_mode,
  412. v4l2_std_id std,
  413. fe_bandwidth_t bandwidth)
  414. {
  415. struct xc2028_data *priv = fe->tuner_priv;
  416. int rc=-EINVAL;
  417. unsigned char buf[5];
  418. u32 div, offset = 0;
  419. tuner_info("%s called\n", __FUNCTION__);
  420. mutex_lock(&priv->lock);
  421. /* HACK: It seems that specific firmware need to be reloaded
  422. when freq is changed */
  423. priv->firm_type=0;
  424. /* Reset GPIO 1 */
  425. rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0);
  426. if (rc<0)
  427. goto ret;
  428. msleep(10);
  429. tuner_info("should set frequency %d kHz)\n", freq / 1000);
  430. if (check_firmware(fe, new_mode, std, bandwidth)<0)
  431. goto ret;
  432. if(new_mode == T_DIGITAL_TV)
  433. offset = 2750000;
  434. div = (freq - offset + DIV/2)/DIV;
  435. /* CMD= Set frequency */
  436. if (priv->version<0x0202) {
  437. send_seq(priv, {0x00, 0x02, 0x00, 0x00});
  438. } else {
  439. send_seq(priv, {0x80, 0x02, 0x00, 0x00});
  440. }
  441. rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
  442. if (rc<0)
  443. goto ret;
  444. msleep(10);
  445. buf[0]= 0xff & (div>>24);
  446. buf[1]= 0xff & (div>>16);
  447. buf[2]= 0xff & (div>>8);
  448. buf[3]= 0xff & (div);
  449. buf[4]= 0;
  450. i2c_send(rc, priv, buf, sizeof(buf));
  451. if (rc<0)
  452. goto ret;
  453. msleep(100);
  454. priv->frequency=freq;
  455. printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n",
  456. buf[1],buf[2],buf[3],buf[4],
  457. freq / 1000000, (freq%1000000)/10000);
  458. rc=0;
  459. ret:
  460. mutex_unlock(&priv->lock);
  461. return rc;
  462. }
  463. static int xc2028_set_tv_freq(struct dvb_frontend *fe,
  464. struct analog_parameters *p)
  465. {
  466. struct xc2028_data *priv = fe->tuner_priv;
  467. tuner_info("%s called\n", __FUNCTION__);
  468. return generic_set_tv_freq(fe, 62500l*p->frequency, T_ANALOG_TV,
  469. p->std,
  470. BANDWIDTH_8_MHZ /* NOT USED */);
  471. }
  472. static int xc2028_set_params(struct dvb_frontend *fe,
  473. struct dvb_frontend_parameters *p)
  474. {
  475. struct xc2028_data *priv = fe->tuner_priv;
  476. tuner_info("%s called\n", __FUNCTION__);
  477. /* FIXME: Only OFDM implemented */
  478. if (fe->ops.info.type != FE_OFDM) {
  479. tuner_info ("DTV type not implemented.\n");
  480. return -EINVAL;
  481. }
  482. return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV,
  483. 0, /* NOT USED */
  484. p->u.ofdm.bandwidth);
  485. }
  486. static int xc2028_dvb_release(struct dvb_frontend *fe)
  487. {
  488. struct xc2028_data *priv = fe->tuner_priv;
  489. tuner_info("%s called\n", __FUNCTION__);
  490. priv->count--;
  491. if (!priv->count) {
  492. list_del(&priv->xc2028_list);
  493. if (priv->ctrl.fname)
  494. kfree(priv->ctrl.fname);
  495. free_firmware(priv);
  496. kfree (priv);
  497. }
  498. return 0;
  499. }
  500. static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  501. {
  502. struct xc2028_data *priv = fe->tuner_priv;
  503. tuner_info("%s called\n", __FUNCTION__);
  504. *frequency = priv->frequency;
  505. return 0;
  506. }
  507. static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg)
  508. {
  509. struct xc2028_data *priv = fe->tuner_priv;
  510. struct xc2028_ctrl *p = priv_cfg;
  511. tuner_info("%s called\n", __FUNCTION__);
  512. priv->ctrl.type = p->type;
  513. if (p->fname) {
  514. if (priv->ctrl.fname)
  515. kfree(priv->ctrl.fname);
  516. priv->ctrl.fname = kmalloc(strlen(p->fname)+1, GFP_KERNEL);
  517. if (!priv->ctrl.fname)
  518. return -ENOMEM;
  519. free_firmware(priv);
  520. strcpy(priv->ctrl.fname, p->fname);
  521. }
  522. if (p->max_len>0)
  523. priv->max_len = p->max_len;
  524. tuner_info("%s OK\n", __FUNCTION__);
  525. return 0;
  526. }
  527. static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
  528. .info = {
  529. .name = "Xceive XC3028",
  530. .frequency_min = 42000000,
  531. .frequency_max = 864000000,
  532. .frequency_step = 50000,
  533. },
  534. .set_config = xc2028_set_config,
  535. .set_analog_params = xc2028_set_tv_freq,
  536. .release = xc2028_dvb_release,
  537. .get_frequency = xc2028_get_frequency,
  538. .get_rf_strength = xc2028_signal,
  539. .set_params = xc2028_set_params,
  540. // int (*sleep)(struct dvb_frontend *fe);
  541. // int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
  542. // int (*get_status)(struct dvb_frontend *fe, u32 *status);
  543. };
  544. int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
  545. u8 i2c_addr, struct device *dev, void *video_dev,
  546. int (*tuner_callback) (void *dev, int command,int arg))
  547. {
  548. struct xc2028_data *priv;
  549. printk( KERN_INFO PREFIX "Xcv2028/3028 init called!\n");
  550. if (NULL == dev)
  551. return -ENODEV;
  552. if (NULL == video_dev)
  553. return -ENODEV;
  554. if (!tuner_callback) {
  555. printk( KERN_ERR PREFIX "No tuner callback!\n");
  556. return -EINVAL;
  557. }
  558. list_for_each_entry(priv, &xc2028_list, xc2028_list) {
  559. if (priv->dev == dev) {
  560. dev = NULL;
  561. }
  562. }
  563. if (dev) {
  564. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  565. if (priv == NULL)
  566. return -ENOMEM;
  567. fe->tuner_priv = priv;
  568. priv->bandwidth=BANDWIDTH_6_MHZ;
  569. priv->need_load_generic=1;
  570. priv->mode = T_UNINITIALIZED;
  571. priv->i2c_props.addr = i2c_addr;
  572. priv->i2c_props.adap = i2c_adap;
  573. priv->dev = dev;
  574. priv->video_dev = video_dev;
  575. priv->tuner_callback = tuner_callback;
  576. priv->max_len = 13;
  577. mutex_init(&priv->lock);
  578. list_add_tail(&priv->xc2028_list,&xc2028_list);
  579. }
  580. priv->count++;
  581. memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
  582. sizeof(xc2028_dvb_tuner_ops));
  583. tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
  584. return 0;
  585. }
  586. EXPORT_SYMBOL(xc2028_attach);
  587. MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
  588. MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
  589. MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
  590. MODULE_LICENSE("GPL");