fc2580.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * FCI FC2580 silicon tuner driver
  4. *
  5. * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
  6. */
  7. #include "fc2580_priv.h"
  8. /*
  9. * TODO:
  10. * I2C write and read works only for one single register. Multiple registers
  11. * could not be accessed using normal register address auto-increment.
  12. * There could be (very likely) register to change that behavior....
  13. */
  14. /* write single register conditionally only when value differs from 0xff
  15. * XXX: This is special routine meant only for writing fc2580_freq_regs_lut[]
  16. * values. Do not use for the other purposes. */
  17. static int fc2580_wr_reg_ff(struct fc2580_dev *dev, u8 reg, u8 val)
  18. {
  19. if (val == 0xff)
  20. return 0;
  21. else
  22. return regmap_write(dev->regmap, reg, val);
  23. }
  24. static int fc2580_set_params(struct fc2580_dev *dev)
  25. {
  26. struct i2c_client *client = dev->client;
  27. int ret, i;
  28. unsigned int uitmp, div_ref, div_ref_val, div_n, k, k_cw, div_out;
  29. u64 f_vco;
  30. u8 synth_config;
  31. unsigned long timeout;
  32. if (!dev->active) {
  33. dev_dbg(&client->dev, "tuner is sleeping\n");
  34. return 0;
  35. }
  36. /*
  37. * Fractional-N synthesizer
  38. *
  39. * +---------------------------------------+
  40. * v |
  41. * Fref +----+ +----+ +-------+ +----+ +------+ +---+
  42. * ------> | /R | --> | PD | --> | VCO | ------> | /2 | --> | /N.F | <-- | K |
  43. * +----+ +----+ +-------+ +----+ +------+ +---+
  44. * |
  45. * |
  46. * v
  47. * +-------+ Fout
  48. * | /Rout | ------>
  49. * +-------+
  50. */
  51. for (i = 0; i < ARRAY_SIZE(fc2580_pll_lut); i++) {
  52. if (dev->f_frequency <= fc2580_pll_lut[i].freq)
  53. break;
  54. }
  55. if (i == ARRAY_SIZE(fc2580_pll_lut)) {
  56. ret = -EINVAL;
  57. goto err;
  58. }
  59. #define DIV_PRE_N 2
  60. #define F_REF dev->clk
  61. div_out = fc2580_pll_lut[i].div_out;
  62. f_vco = (u64) dev->f_frequency * div_out;
  63. synth_config = fc2580_pll_lut[i].band;
  64. if (f_vco < 2600000000ULL)
  65. synth_config |= 0x06;
  66. else
  67. synth_config |= 0x0e;
  68. /* select reference divider R (keep PLL div N in valid range) */
  69. #define DIV_N_MIN 76
  70. if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 1)) {
  71. div_ref = 1;
  72. div_ref_val = 0x00;
  73. } else if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 2)) {
  74. div_ref = 2;
  75. div_ref_val = 0x10;
  76. } else {
  77. div_ref = 4;
  78. div_ref_val = 0x20;
  79. }
  80. /* calculate PLL integer and fractional control word */
  81. uitmp = DIV_PRE_N * F_REF / div_ref;
  82. div_n = div_u64_rem(f_vco, uitmp, &k);
  83. k_cw = div_u64((u64) k * 0x100000, uitmp);
  84. dev_dbg(&client->dev,
  85. "frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_ref=%u div_n=%u k=%u div_out=%u k_cw=%0x\n",
  86. dev->f_frequency, dev->f_bandwidth, f_vco, F_REF, div_ref,
  87. div_n, k, div_out, k_cw);
  88. ret = regmap_write(dev->regmap, 0x02, synth_config);
  89. if (ret)
  90. goto err;
  91. ret = regmap_write(dev->regmap, 0x18, div_ref_val << 0 | k_cw >> 16);
  92. if (ret)
  93. goto err;
  94. ret = regmap_write(dev->regmap, 0x1a, (k_cw >> 8) & 0xff);
  95. if (ret)
  96. goto err;
  97. ret = regmap_write(dev->regmap, 0x1b, (k_cw >> 0) & 0xff);
  98. if (ret)
  99. goto err;
  100. ret = regmap_write(dev->regmap, 0x1c, div_n);
  101. if (ret)
  102. goto err;
  103. /* registers */
  104. for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs_lut); i++) {
  105. if (dev->f_frequency <= fc2580_freq_regs_lut[i].freq)
  106. break;
  107. }
  108. if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) {
  109. ret = -EINVAL;
  110. goto err;
  111. }
  112. ret = fc2580_wr_reg_ff(dev, 0x25, fc2580_freq_regs_lut[i].r25_val);
  113. if (ret)
  114. goto err;
  115. ret = fc2580_wr_reg_ff(dev, 0x27, fc2580_freq_regs_lut[i].r27_val);
  116. if (ret)
  117. goto err;
  118. ret = fc2580_wr_reg_ff(dev, 0x28, fc2580_freq_regs_lut[i].r28_val);
  119. if (ret)
  120. goto err;
  121. ret = fc2580_wr_reg_ff(dev, 0x29, fc2580_freq_regs_lut[i].r29_val);
  122. if (ret)
  123. goto err;
  124. ret = fc2580_wr_reg_ff(dev, 0x2b, fc2580_freq_regs_lut[i].r2b_val);
  125. if (ret)
  126. goto err;
  127. ret = fc2580_wr_reg_ff(dev, 0x2c, fc2580_freq_regs_lut[i].r2c_val);
  128. if (ret)
  129. goto err;
  130. ret = fc2580_wr_reg_ff(dev, 0x2d, fc2580_freq_regs_lut[i].r2d_val);
  131. if (ret)
  132. goto err;
  133. ret = fc2580_wr_reg_ff(dev, 0x30, fc2580_freq_regs_lut[i].r30_val);
  134. if (ret)
  135. goto err;
  136. ret = fc2580_wr_reg_ff(dev, 0x44, fc2580_freq_regs_lut[i].r44_val);
  137. if (ret)
  138. goto err;
  139. ret = fc2580_wr_reg_ff(dev, 0x50, fc2580_freq_regs_lut[i].r50_val);
  140. if (ret)
  141. goto err;
  142. ret = fc2580_wr_reg_ff(dev, 0x53, fc2580_freq_regs_lut[i].r53_val);
  143. if (ret)
  144. goto err;
  145. ret = fc2580_wr_reg_ff(dev, 0x5f, fc2580_freq_regs_lut[i].r5f_val);
  146. if (ret)
  147. goto err;
  148. ret = fc2580_wr_reg_ff(dev, 0x61, fc2580_freq_regs_lut[i].r61_val);
  149. if (ret)
  150. goto err;
  151. ret = fc2580_wr_reg_ff(dev, 0x62, fc2580_freq_regs_lut[i].r62_val);
  152. if (ret)
  153. goto err;
  154. ret = fc2580_wr_reg_ff(dev, 0x63, fc2580_freq_regs_lut[i].r63_val);
  155. if (ret)
  156. goto err;
  157. ret = fc2580_wr_reg_ff(dev, 0x67, fc2580_freq_regs_lut[i].r67_val);
  158. if (ret)
  159. goto err;
  160. ret = fc2580_wr_reg_ff(dev, 0x68, fc2580_freq_regs_lut[i].r68_val);
  161. if (ret)
  162. goto err;
  163. ret = fc2580_wr_reg_ff(dev, 0x69, fc2580_freq_regs_lut[i].r69_val);
  164. if (ret)
  165. goto err;
  166. ret = fc2580_wr_reg_ff(dev, 0x6a, fc2580_freq_regs_lut[i].r6a_val);
  167. if (ret)
  168. goto err;
  169. ret = fc2580_wr_reg_ff(dev, 0x6b, fc2580_freq_regs_lut[i].r6b_val);
  170. if (ret)
  171. goto err;
  172. ret = fc2580_wr_reg_ff(dev, 0x6c, fc2580_freq_regs_lut[i].r6c_val);
  173. if (ret)
  174. goto err;
  175. ret = fc2580_wr_reg_ff(dev, 0x6d, fc2580_freq_regs_lut[i].r6d_val);
  176. if (ret)
  177. goto err;
  178. ret = fc2580_wr_reg_ff(dev, 0x6e, fc2580_freq_regs_lut[i].r6e_val);
  179. if (ret)
  180. goto err;
  181. ret = fc2580_wr_reg_ff(dev, 0x6f, fc2580_freq_regs_lut[i].r6f_val);
  182. if (ret)
  183. goto err;
  184. /* IF filters */
  185. for (i = 0; i < ARRAY_SIZE(fc2580_if_filter_lut); i++) {
  186. if (dev->f_bandwidth <= fc2580_if_filter_lut[i].freq)
  187. break;
  188. }
  189. if (i == ARRAY_SIZE(fc2580_if_filter_lut)) {
  190. ret = -EINVAL;
  191. goto err;
  192. }
  193. ret = regmap_write(dev->regmap, 0x36, fc2580_if_filter_lut[i].r36_val);
  194. if (ret)
  195. goto err;
  196. uitmp = (unsigned int) 8058000 - (dev->f_bandwidth * 122 / 100 / 2);
  197. uitmp = div64_u64((u64) dev->clk * uitmp, 1000000000000ULL);
  198. ret = regmap_write(dev->regmap, 0x37, uitmp);
  199. if (ret)
  200. goto err;
  201. ret = regmap_write(dev->regmap, 0x39, fc2580_if_filter_lut[i].r39_val);
  202. if (ret)
  203. goto err;
  204. timeout = jiffies + msecs_to_jiffies(30);
  205. for (uitmp = ~0xc0; !time_after(jiffies, timeout) && uitmp != 0xc0;) {
  206. /* trigger filter */
  207. ret = regmap_write(dev->regmap, 0x2e, 0x09);
  208. if (ret)
  209. goto err;
  210. /* locked when [7:6] are set (val: d7 6MHz, d5 7MHz, cd 8MHz) */
  211. ret = regmap_read(dev->regmap, 0x2f, &uitmp);
  212. if (ret)
  213. goto err;
  214. uitmp &= 0xc0;
  215. ret = regmap_write(dev->regmap, 0x2e, 0x01);
  216. if (ret)
  217. goto err;
  218. }
  219. if (uitmp != 0xc0)
  220. dev_dbg(&client->dev, "filter did not lock %02x\n", uitmp);
  221. return 0;
  222. err:
  223. dev_dbg(&client->dev, "failed=%d\n", ret);
  224. return ret;
  225. }
  226. static int fc2580_init(struct fc2580_dev *dev)
  227. {
  228. struct i2c_client *client = dev->client;
  229. int ret, i;
  230. dev_dbg(&client->dev, "\n");
  231. for (i = 0; i < ARRAY_SIZE(fc2580_init_reg_vals); i++) {
  232. ret = regmap_write(dev->regmap, fc2580_init_reg_vals[i].reg,
  233. fc2580_init_reg_vals[i].val);
  234. if (ret)
  235. goto err;
  236. }
  237. dev->active = true;
  238. return 0;
  239. err:
  240. dev_dbg(&client->dev, "failed=%d\n", ret);
  241. return ret;
  242. }
  243. static int fc2580_sleep(struct fc2580_dev *dev)
  244. {
  245. struct i2c_client *client = dev->client;
  246. int ret;
  247. dev_dbg(&client->dev, "\n");
  248. dev->active = false;
  249. ret = regmap_write(dev->regmap, 0x02, 0x0a);
  250. if (ret)
  251. goto err;
  252. return 0;
  253. err:
  254. dev_dbg(&client->dev, "failed=%d\n", ret);
  255. return ret;
  256. }
  257. /*
  258. * DVB API
  259. */
  260. static int fc2580_dvb_set_params(struct dvb_frontend *fe)
  261. {
  262. struct fc2580_dev *dev = fe->tuner_priv;
  263. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  264. dev->f_frequency = c->frequency;
  265. dev->f_bandwidth = c->bandwidth_hz;
  266. return fc2580_set_params(dev);
  267. }
  268. static int fc2580_dvb_init(struct dvb_frontend *fe)
  269. {
  270. return fc2580_init(fe->tuner_priv);
  271. }
  272. static int fc2580_dvb_sleep(struct dvb_frontend *fe)
  273. {
  274. return fc2580_sleep(fe->tuner_priv);
  275. }
  276. static int fc2580_dvb_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
  277. {
  278. *frequency = 0; /* Zero-IF */
  279. return 0;
  280. }
  281. static const struct dvb_tuner_ops fc2580_dvb_tuner_ops = {
  282. .info = {
  283. .name = "FCI FC2580",
  284. .frequency_min_hz = 174 * MHz,
  285. .frequency_max_hz = 862 * MHz,
  286. },
  287. .init = fc2580_dvb_init,
  288. .sleep = fc2580_dvb_sleep,
  289. .set_params = fc2580_dvb_set_params,
  290. .get_if_frequency = fc2580_dvb_get_if_frequency,
  291. };
  292. /*
  293. * V4L2 API
  294. */
  295. #if IS_ENABLED(CONFIG_VIDEO_V4L2)
  296. static const struct v4l2_frequency_band bands[] = {
  297. {
  298. .type = V4L2_TUNER_RF,
  299. .index = 0,
  300. .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
  301. .rangelow = 130000000,
  302. .rangehigh = 2000000000,
  303. },
  304. };
  305. static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd)
  306. {
  307. return container_of(sd, struct fc2580_dev, subdev);
  308. }
  309. static int fc2580_standby(struct v4l2_subdev *sd)
  310. {
  311. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  312. int ret;
  313. ret = fc2580_sleep(dev);
  314. if (ret)
  315. return ret;
  316. return fc2580_set_params(dev);
  317. }
  318. static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
  319. {
  320. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  321. struct i2c_client *client = dev->client;
  322. dev_dbg(&client->dev, "index=%d\n", v->index);
  323. strscpy(v->name, "FCI FC2580", sizeof(v->name));
  324. v->type = V4L2_TUNER_RF;
  325. v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
  326. v->rangelow = bands[0].rangelow;
  327. v->rangehigh = bands[0].rangehigh;
  328. return 0;
  329. }
  330. static int fc2580_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
  331. {
  332. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  333. struct i2c_client *client = dev->client;
  334. dev_dbg(&client->dev, "index=%d\n", v->index);
  335. return 0;
  336. }
  337. static int fc2580_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
  338. {
  339. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  340. struct i2c_client *client = dev->client;
  341. dev_dbg(&client->dev, "tuner=%d\n", f->tuner);
  342. f->frequency = dev->f_frequency;
  343. return 0;
  344. }
  345. static int fc2580_s_frequency(struct v4l2_subdev *sd,
  346. const struct v4l2_frequency *f)
  347. {
  348. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  349. struct i2c_client *client = dev->client;
  350. dev_dbg(&client->dev, "tuner=%d type=%d frequency=%u\n",
  351. f->tuner, f->type, f->frequency);
  352. dev->f_frequency = clamp_t(unsigned int, f->frequency,
  353. bands[0].rangelow, bands[0].rangehigh);
  354. return fc2580_set_params(dev);
  355. }
  356. static int fc2580_enum_freq_bands(struct v4l2_subdev *sd,
  357. struct v4l2_frequency_band *band)
  358. {
  359. struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
  360. struct i2c_client *client = dev->client;
  361. dev_dbg(&client->dev, "tuner=%d type=%d index=%d\n",
  362. band->tuner, band->type, band->index);
  363. if (band->index >= ARRAY_SIZE(bands))
  364. return -EINVAL;
  365. band->capability = bands[band->index].capability;
  366. band->rangelow = bands[band->index].rangelow;
  367. band->rangehigh = bands[band->index].rangehigh;
  368. return 0;
  369. }
  370. static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = {
  371. .standby = fc2580_standby,
  372. .g_tuner = fc2580_g_tuner,
  373. .s_tuner = fc2580_s_tuner,
  374. .g_frequency = fc2580_g_frequency,
  375. .s_frequency = fc2580_s_frequency,
  376. .enum_freq_bands = fc2580_enum_freq_bands,
  377. };
  378. static const struct v4l2_subdev_ops fc2580_subdev_ops = {
  379. .tuner = &fc2580_subdev_tuner_ops,
  380. };
  381. static int fc2580_s_ctrl(struct v4l2_ctrl *ctrl)
  382. {
  383. struct fc2580_dev *dev = container_of(ctrl->handler, struct fc2580_dev, hdl);
  384. struct i2c_client *client = dev->client;
  385. int ret;
  386. dev_dbg(&client->dev, "ctrl: id=%d name=%s cur.val=%d val=%d\n",
  387. ctrl->id, ctrl->name, ctrl->cur.val, ctrl->val);
  388. switch (ctrl->id) {
  389. case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
  390. case V4L2_CID_RF_TUNER_BANDWIDTH:
  391. /*
  392. * TODO: Auto logic does not work 100% correctly as tuner driver
  393. * do not have information to calculate maximum suitable
  394. * bandwidth. Calculating it is responsible of master driver.
  395. */
  396. dev->f_bandwidth = dev->bandwidth->val;
  397. ret = fc2580_set_params(dev);
  398. break;
  399. default:
  400. dev_dbg(&client->dev, "unknown ctrl");
  401. ret = -EINVAL;
  402. }
  403. return ret;
  404. }
  405. static const struct v4l2_ctrl_ops fc2580_ctrl_ops = {
  406. .s_ctrl = fc2580_s_ctrl,
  407. };
  408. #endif
  409. static struct v4l2_subdev *fc2580_get_v4l2_subdev(struct i2c_client *client)
  410. {
  411. struct fc2580_dev *dev = i2c_get_clientdata(client);
  412. if (dev->subdev.ops)
  413. return &dev->subdev;
  414. else
  415. return NULL;
  416. }
  417. static int fc2580_probe(struct i2c_client *client,
  418. const struct i2c_device_id *id)
  419. {
  420. struct fc2580_dev *dev;
  421. struct fc2580_platform_data *pdata = client->dev.platform_data;
  422. struct dvb_frontend *fe = pdata->dvb_frontend;
  423. int ret;
  424. unsigned int uitmp;
  425. static const struct regmap_config regmap_config = {
  426. .reg_bits = 8,
  427. .val_bits = 8,
  428. };
  429. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  430. if (!dev) {
  431. ret = -ENOMEM;
  432. goto err;
  433. }
  434. if (pdata->clk)
  435. dev->clk = pdata->clk;
  436. else
  437. dev->clk = 16384000; /* internal clock */
  438. dev->client = client;
  439. dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
  440. if (IS_ERR(dev->regmap)) {
  441. ret = PTR_ERR(dev->regmap);
  442. goto err_kfree;
  443. }
  444. /* check if the tuner is there */
  445. ret = regmap_read(dev->regmap, 0x01, &uitmp);
  446. if (ret)
  447. goto err_kfree;
  448. dev_dbg(&client->dev, "chip_id=%02x\n", uitmp);
  449. switch (uitmp) {
  450. case 0x56:
  451. case 0x5a:
  452. break;
  453. default:
  454. ret = -ENODEV;
  455. goto err_kfree;
  456. }
  457. #if IS_ENABLED(CONFIG_VIDEO_V4L2)
  458. /* Register controls */
  459. v4l2_ctrl_handler_init(&dev->hdl, 2);
  460. dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops,
  461. V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
  462. 0, 1, 1, 1);
  463. dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops,
  464. V4L2_CID_RF_TUNER_BANDWIDTH,
  465. 3000, 10000000, 1, 3000);
  466. v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
  467. if (dev->hdl.error) {
  468. ret = dev->hdl.error;
  469. dev_err(&client->dev, "Could not initialize controls\n");
  470. v4l2_ctrl_handler_free(&dev->hdl);
  471. goto err_kfree;
  472. }
  473. dev->subdev.ctrl_handler = &dev->hdl;
  474. dev->f_frequency = bands[0].rangelow;
  475. dev->f_bandwidth = dev->bandwidth->val;
  476. v4l2_i2c_subdev_init(&dev->subdev, client, &fc2580_subdev_ops);
  477. #endif
  478. fe->tuner_priv = dev;
  479. memcpy(&fe->ops.tuner_ops, &fc2580_dvb_tuner_ops,
  480. sizeof(fe->ops.tuner_ops));
  481. pdata->get_v4l2_subdev = fc2580_get_v4l2_subdev;
  482. i2c_set_clientdata(client, dev);
  483. dev_info(&client->dev, "FCI FC2580 successfully identified\n");
  484. return 0;
  485. err_kfree:
  486. kfree(dev);
  487. err:
  488. dev_dbg(&client->dev, "failed=%d\n", ret);
  489. return ret;
  490. }
  491. static int fc2580_remove(struct i2c_client *client)
  492. {
  493. struct fc2580_dev *dev = i2c_get_clientdata(client);
  494. dev_dbg(&client->dev, "\n");
  495. #if IS_ENABLED(CONFIG_VIDEO_V4L2)
  496. v4l2_ctrl_handler_free(&dev->hdl);
  497. #endif
  498. kfree(dev);
  499. return 0;
  500. }
  501. static const struct i2c_device_id fc2580_id_table[] = {
  502. {"fc2580", 0},
  503. {}
  504. };
  505. MODULE_DEVICE_TABLE(i2c, fc2580_id_table);
  506. static struct i2c_driver fc2580_driver = {
  507. .driver = {
  508. .name = "fc2580",
  509. .suppress_bind_attrs = true,
  510. },
  511. .probe = fc2580_probe,
  512. .remove = fc2580_remove,
  513. .id_table = fc2580_id_table,
  514. };
  515. module_i2c_driver(fc2580_driver);
  516. MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver");
  517. MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
  518. MODULE_LICENSE("GPL");