si2168.c revision 88ac8f860640f28ae6fae43ca690adc3f7294b90
1/* 2 * Silicon Labs Si2168 DVB-T/T2/C demodulator driver 3 * 4 * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include "si2168_priv.h" 18 19static const struct dvb_frontend_ops si2168_ops; 20 21/* execute firmware command */ 22static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) 23{ 24 int ret; 25 unsigned long timeout; 26 27 mutex_lock(&s->i2c_mutex); 28 29 if (cmd->wlen) { 30 /* write cmd and args for firmware */ 31 ret = i2c_master_send(s->client, cmd->args, cmd->wlen); 32 if (ret < 0) { 33 goto err_mutex_unlock; 34 } else if (ret != cmd->wlen) { 35 ret = -EREMOTEIO; 36 goto err_mutex_unlock; 37 } 38 } 39 40 if (cmd->rlen) { 41 /* wait cmd execution terminate */ 42 #define TIMEOUT 50 43 timeout = jiffies + msecs_to_jiffies(TIMEOUT); 44 while (!time_after(jiffies, timeout)) { 45 ret = i2c_master_recv(s->client, cmd->args, cmd->rlen); 46 if (ret < 0) { 47 goto err_mutex_unlock; 48 } else if (ret != cmd->rlen) { 49 ret = -EREMOTEIO; 50 goto err_mutex_unlock; 51 } 52 53 /* firmware ready? */ 54 if ((cmd->args[0] >> 7) & 0x01) 55 break; 56 } 57 58 dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", 59 __func__, 60 jiffies_to_msecs(jiffies) - 61 (jiffies_to_msecs(timeout) - TIMEOUT)); 62 63 if (!(cmd->args[0] >> 7) & 0x01) { 64 ret = -ETIMEDOUT; 65 goto err_mutex_unlock; 66 } 67 } 68 69 ret = 0; 70 71err_mutex_unlock: 72 mutex_unlock(&s->i2c_mutex); 73 if (ret) 74 goto err; 75 76 return 0; 77err: 78 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); 79 return ret; 80} 81 82static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) 83{ 84 struct si2168 *s = fe->demodulator_priv; 85 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 86 int ret; 87 struct si2168_cmd cmd; 88 89 *status = 0; 90 91 if (!s->active) { 92 ret = -EAGAIN; 93 goto err; 94 } 95 96 switch (c->delivery_system) { 97 case SYS_DVBT: 98 memcpy(cmd.args, "\xa0\x01", 2); 99 cmd.wlen = 2; 100 cmd.rlen = 13; 101 break; 102 case SYS_DVBC_ANNEX_A: 103 memcpy(cmd.args, "\x90\x01", 2); 104 cmd.wlen = 2; 105 cmd.rlen = 9; 106 break; 107 case SYS_DVBT2: 108 memcpy(cmd.args, "\x50\x01", 2); 109 cmd.wlen = 2; 110 cmd.rlen = 14; 111 break; 112 default: 113 ret = -EINVAL; 114 goto err; 115 } 116 117 ret = si2168_cmd_execute(s, &cmd); 118 if (ret) 119 goto err; 120 121 /* 122 * Possible values seen, in order from strong signal to weak: 123 * 16 0001 0110 full lock 124 * 1e 0001 1110 partial lock 125 * 1a 0001 1010 partial lock 126 * 18 0001 1000 no lock 127 * 128 * [b3:b1] lock bits 129 * [b4] statistics ready? Set in a few secs after lock is gained. 130 */ 131 132 switch ((cmd.args[2] >> 1) & 0x03) { 133 case 0x01: 134 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; 135 break; 136 case 0x03: 137 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | 138 FE_HAS_SYNC | FE_HAS_LOCK; 139 break; 140 } 141 142 s->fe_status = *status; 143 144 if (*status & FE_HAS_LOCK) { 145 c->cnr.len = 1; 146 c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 147 c->cnr.stat[0].svalue = cmd.args[3] * 1000 / 4; 148 } else { 149 c->cnr.len = 1; 150 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 151 } 152 153 dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n", 154 __func__, *status, cmd.rlen, cmd.args); 155 156 return 0; 157err: 158 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); 159 return ret; 160} 161 162static int si2168_set_frontend(struct dvb_frontend *fe) 163{ 164 struct si2168 *s = fe->demodulator_priv; 165 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 166 int ret; 167 struct si2168_cmd cmd; 168 u8 bandwidth, delivery_system; 169 170 dev_dbg(&s->client->dev, 171 "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n", 172 __func__, c->delivery_system, c->modulation, 173 c->frequency, c->bandwidth_hz, c->symbol_rate, 174 c->inversion); 175 176 if (!s->active) { 177 ret = -EAGAIN; 178 goto err; 179 } 180 181 switch (c->delivery_system) { 182 case SYS_DVBT: 183 delivery_system = 0x20; 184 break; 185 case SYS_DVBC_ANNEX_A: 186 delivery_system = 0x30; 187 break; 188 case SYS_DVBT2: 189 delivery_system = 0x70; 190 break; 191 default: 192 ret = -EINVAL; 193 goto err; 194 } 195 196 if (c->bandwidth_hz <= 5000000) 197 bandwidth = 0x05; 198 else if (c->bandwidth_hz <= 6000000) 199 bandwidth = 0x06; 200 else if (c->bandwidth_hz <= 7000000) 201 bandwidth = 0x07; 202 else if (c->bandwidth_hz <= 8000000) 203 bandwidth = 0x08; 204 else if (c->bandwidth_hz <= 9000000) 205 bandwidth = 0x09; 206 else if (c->bandwidth_hz <= 10000000) 207 bandwidth = 0x0a; 208 else 209 bandwidth = 0x0f; 210 211 /* program tuner */ 212 if (fe->ops.tuner_ops.set_params) { 213 ret = fe->ops.tuner_ops.set_params(fe); 214 if (ret) 215 goto err; 216 } 217 218 memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5); 219 cmd.wlen = 5; 220 cmd.rlen = 5; 221 ret = si2168_cmd_execute(s, &cmd); 222 if (ret) 223 goto err; 224 225 /* that has no big effect */ 226 if (c->delivery_system == SYS_DVBT) 227 memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6); 228 else if (c->delivery_system == SYS_DVBC_ANNEX_A) 229 memcpy(cmd.args, "\x89\x21\x06\x11\x89\xf0", 6); 230 else if (c->delivery_system == SYS_DVBT2) 231 memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6); 232 cmd.wlen = 6; 233 cmd.rlen = 3; 234 ret = si2168_cmd_execute(s, &cmd); 235 if (ret) 236 goto err; 237 238 memcpy(cmd.args, "\x51\x03", 2); 239 cmd.wlen = 2; 240 cmd.rlen = 12; 241 ret = si2168_cmd_execute(s, &cmd); 242 if (ret) 243 goto err; 244 245 memcpy(cmd.args, "\x12\x08\x04", 3); 246 cmd.wlen = 3; 247 cmd.rlen = 3; 248 ret = si2168_cmd_execute(s, &cmd); 249 if (ret) 250 goto err; 251 252 memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6); 253 cmd.wlen = 6; 254 cmd.rlen = 1; 255 ret = si2168_cmd_execute(s, &cmd); 256 if (ret) 257 goto err; 258 259 memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6); 260 cmd.wlen = 6; 261 cmd.rlen = 1; 262 ret = si2168_cmd_execute(s, &cmd); 263 if (ret) 264 goto err; 265 266 memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6); 267 cmd.wlen = 6; 268 cmd.rlen = 1; 269 ret = si2168_cmd_execute(s, &cmd); 270 if (ret) 271 goto err; 272 273 memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6); 274 cmd.wlen = 6; 275 cmd.rlen = 1; 276 ret = si2168_cmd_execute(s, &cmd); 277 if (ret) 278 goto err; 279 280 memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6); 281 cmd.wlen = 6; 282 cmd.rlen = 1; 283 ret = si2168_cmd_execute(s, &cmd); 284 if (ret) 285 goto err; 286 287 memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6); 288 cmd.wlen = 6; 289 cmd.rlen = 1; 290 ret = si2168_cmd_execute(s, &cmd); 291 if (ret) 292 goto err; 293 294 memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6); 295 cmd.wlen = 6; 296 cmd.rlen = 1; 297 ret = si2168_cmd_execute(s, &cmd); 298 if (ret) 299 goto err; 300 301 memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); 302 cmd.args[4] = delivery_system | bandwidth; 303 cmd.wlen = 6; 304 cmd.rlen = 1; 305 ret = si2168_cmd_execute(s, &cmd); 306 if (ret) 307 goto err; 308 309 memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6); 310 cmd.wlen = 6; 311 cmd.rlen = 1; 312 ret = si2168_cmd_execute(s, &cmd); 313 if (ret) 314 goto err; 315 316 memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6); 317 cmd.wlen = 6; 318 cmd.rlen = 1; 319 ret = si2168_cmd_execute(s, &cmd); 320 if (ret) 321 goto err; 322 323 memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6); 324 cmd.wlen = 6; 325 cmd.rlen = 1; 326 ret = si2168_cmd_execute(s, &cmd); 327 if (ret) 328 goto err; 329 330 memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6); 331 cmd.wlen = 6; 332 cmd.rlen = 1; 333 ret = si2168_cmd_execute(s, &cmd); 334 if (ret) 335 goto err; 336 337 memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); 338 cmd.wlen = 6; 339 cmd.rlen = 1; 340 ret = si2168_cmd_execute(s, &cmd); 341 if (ret) 342 goto err; 343 344 memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6); 345 cmd.wlen = 6; 346 cmd.rlen = 1; 347 ret = si2168_cmd_execute(s, &cmd); 348 if (ret) 349 goto err; 350 351 memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6); 352 cmd.wlen = 6; 353 cmd.rlen = 1; 354 ret = si2168_cmd_execute(s, &cmd); 355 if (ret) 356 goto err; 357 358 memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6); 359 cmd.wlen = 6; 360 cmd.rlen = 1; 361 ret = si2168_cmd_execute(s, &cmd); 362 if (ret) 363 goto err; 364 365 memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6); 366 cmd.wlen = 6; 367 cmd.rlen = 1; 368 ret = si2168_cmd_execute(s, &cmd); 369 if (ret) 370 goto err; 371 372 memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6); 373 cmd.wlen = 6; 374 cmd.rlen = 1; 375 ret = si2168_cmd_execute(s, &cmd); 376 if (ret) 377 goto err; 378 379 memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6); 380 cmd.wlen = 6; 381 cmd.rlen = 1; 382 ret = si2168_cmd_execute(s, &cmd); 383 if (ret) 384 goto err; 385 386 memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6); 387 cmd.wlen = 6; 388 cmd.rlen = 1; 389 ret = si2168_cmd_execute(s, &cmd); 390 if (ret) 391 goto err; 392 393 memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6); 394 cmd.wlen = 6; 395 cmd.rlen = 1; 396 ret = si2168_cmd_execute(s, &cmd); 397 if (ret) 398 goto err; 399 400 memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6); 401 cmd.wlen = 6; 402 cmd.rlen = 1; 403 ret = si2168_cmd_execute(s, &cmd); 404 if (ret) 405 goto err; 406 407 memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6); 408 cmd.wlen = 6; 409 cmd.rlen = 1; 410 ret = si2168_cmd_execute(s, &cmd); 411 if (ret) 412 goto err; 413 414 memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6); 415 cmd.wlen = 6; 416 cmd.rlen = 1; 417 ret = si2168_cmd_execute(s, &cmd); 418 if (ret) 419 goto err; 420 421 memcpy(cmd.args, "\x85", 1); 422 cmd.wlen = 1; 423 cmd.rlen = 1; 424 ret = si2168_cmd_execute(s, &cmd); 425 if (ret) 426 goto err; 427 428 s->delivery_system = c->delivery_system; 429 430 return 0; 431err: 432 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); 433 return ret; 434} 435 436static int si2168_init(struct dvb_frontend *fe) 437{ 438 struct si2168 *s = fe->demodulator_priv; 439 int ret, len, remaining; 440 const struct firmware *fw = NULL; 441 u8 *fw_file = SI2168_FIRMWARE; 442 const unsigned int i2c_wr_max = 8; 443 struct si2168_cmd cmd; 444 445 dev_dbg(&s->client->dev, "%s:\n", __func__); 446 447 memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); 448 cmd.wlen = 13; 449 cmd.rlen = 0; 450 ret = si2168_cmd_execute(s, &cmd); 451 if (ret) 452 goto err; 453 454 memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); 455 cmd.wlen = 8; 456 cmd.rlen = 1; 457 ret = si2168_cmd_execute(s, &cmd); 458 if (ret) 459 goto err; 460 461 memcpy(cmd.args, "\x02", 1); 462 cmd.wlen = 1; 463 cmd.rlen = 13; 464 ret = si2168_cmd_execute(s, &cmd); 465 if (ret) 466 goto err; 467 468 cmd.args[0] = 0x05; 469 cmd.args[1] = 0x00; 470 cmd.args[2] = 0xaa; 471 cmd.args[3] = 0x4d; 472 cmd.args[4] = 0x56; 473 cmd.args[5] = 0x40; 474 cmd.args[6] = 0x00; 475 cmd.args[7] = 0x00; 476 cmd.wlen = 8; 477 cmd.rlen = 1; 478 ret = si2168_cmd_execute(s, &cmd); 479 if (ret) 480 goto err; 481 482 /* cold state - try to download firmware */ 483 dev_info(&s->client->dev, "%s: found a '%s' in cold state\n", 484 KBUILD_MODNAME, si2168_ops.info.name); 485 486 /* request the firmware, this will block and timeout */ 487 ret = request_firmware(&fw, fw_file, &s->client->dev); 488 if (ret) { 489 dev_err(&s->client->dev, "%s: firmare file '%s' not found\n", 490 KBUILD_MODNAME, fw_file); 491 goto err; 492 } 493 494 dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n", 495 KBUILD_MODNAME, fw_file); 496 497 for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { 498 len = remaining; 499 if (len > i2c_wr_max) 500 len = i2c_wr_max; 501 502 memcpy(cmd.args, &fw->data[fw->size - remaining], len); 503 cmd.wlen = len; 504 cmd.rlen = 1; 505 ret = si2168_cmd_execute(s, &cmd); 506 if (ret) { 507 dev_err(&s->client->dev, 508 "%s: firmware download failed=%d\n", 509 KBUILD_MODNAME, ret); 510 goto err; 511 } 512 } 513 514 release_firmware(fw); 515 fw = NULL; 516 517 memcpy(cmd.args, "\x01\x01", 2); 518 cmd.wlen = 2; 519 cmd.rlen = 1; 520 ret = si2168_cmd_execute(s, &cmd); 521 if (ret) 522 goto err; 523 524 dev_info(&s->client->dev, "%s: found a '%s' in warm state\n", 525 KBUILD_MODNAME, si2168_ops.info.name); 526 527 s->active = true; 528 529 return 0; 530err: 531 if (fw) 532 release_firmware(fw); 533 534 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); 535 return ret; 536} 537 538static int si2168_sleep(struct dvb_frontend *fe) 539{ 540 struct si2168 *s = fe->demodulator_priv; 541 int ret; 542 struct si2168_cmd cmd; 543 544 dev_dbg(&s->client->dev, "%s:\n", __func__); 545 546 s->active = false; 547 548 memcpy(cmd.args, "\x13", 1); 549 cmd.wlen = 1; 550 cmd.rlen = 0; 551 ret = si2168_cmd_execute(s, &cmd); 552 if (ret) 553 goto err; 554 555 return 0; 556err: 557 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); 558 return ret; 559} 560 561static int si2168_get_tune_settings(struct dvb_frontend *fe, 562 struct dvb_frontend_tune_settings *s) 563{ 564 s->min_delay_ms = 900; 565 566 return 0; 567} 568 569/* 570 * I2C gate logic 571 * We must use unlocked i2c_transfer() here because I2C lock is already taken 572 * by tuner driver. 573 */ 574static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) 575{ 576 struct si2168 *s = mux_priv; 577 int ret; 578 struct i2c_msg gate_open_msg = { 579 .addr = s->client->addr, 580 .flags = 0, 581 .len = 3, 582 .buf = "\xc0\x0d\x01", 583 }; 584 585 mutex_lock(&s->i2c_mutex); 586 587 /* open tuner I2C gate */ 588 ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1); 589 if (ret != 1) { 590 dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", 591 KBUILD_MODNAME, ret); 592 if (ret >= 0) 593 ret = -EREMOTEIO; 594 } else { 595 ret = 0; 596 } 597 598 return ret; 599} 600 601static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) 602{ 603 struct si2168 *s = mux_priv; 604 int ret; 605 struct i2c_msg gate_close_msg = { 606 .addr = s->client->addr, 607 .flags = 0, 608 .len = 3, 609 .buf = "\xc0\x0d\x00", 610 }; 611 612 /* close tuner I2C gate */ 613 ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1); 614 if (ret != 1) { 615 dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", 616 KBUILD_MODNAME, ret); 617 if (ret >= 0) 618 ret = -EREMOTEIO; 619 } else { 620 ret = 0; 621 } 622 623 mutex_unlock(&s->i2c_mutex); 624 625 return ret; 626} 627 628static const struct dvb_frontend_ops si2168_ops = { 629 .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, 630 .info = { 631 .name = "Silicon Labs Si2168", 632 .caps = FE_CAN_FEC_1_2 | 633 FE_CAN_FEC_2_3 | 634 FE_CAN_FEC_3_4 | 635 FE_CAN_FEC_5_6 | 636 FE_CAN_FEC_7_8 | 637 FE_CAN_FEC_AUTO | 638 FE_CAN_QPSK | 639 FE_CAN_QAM_16 | 640 FE_CAN_QAM_32 | 641 FE_CAN_QAM_64 | 642 FE_CAN_QAM_128 | 643 FE_CAN_QAM_256 | 644 FE_CAN_QAM_AUTO | 645 FE_CAN_TRANSMISSION_MODE_AUTO | 646 FE_CAN_GUARD_INTERVAL_AUTO | 647 FE_CAN_HIERARCHY_AUTO | 648 FE_CAN_MUTE_TS | 649 FE_CAN_2G_MODULATION 650 }, 651 652 .get_tune_settings = si2168_get_tune_settings, 653 654 .init = si2168_init, 655 .sleep = si2168_sleep, 656 657 .set_frontend = si2168_set_frontend, 658 659 .read_status = si2168_read_status, 660}; 661 662static int si2168_probe(struct i2c_client *client, 663 const struct i2c_device_id *id) 664{ 665 struct si2168_config *config = client->dev.platform_data; 666 struct si2168 *s; 667 int ret; 668 struct si2168_cmd cmd; 669 670 dev_dbg(&client->dev, "%s:\n", __func__); 671 672 s = kzalloc(sizeof(struct si2168), GFP_KERNEL); 673 if (!s) { 674 ret = -ENOMEM; 675 dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); 676 goto err; 677 } 678 679 s->client = client; 680 mutex_init(&s->i2c_mutex); 681 682 /* check if the demod is there */ 683 cmd.wlen = 0; 684 cmd.rlen = 1; 685 ret = si2168_cmd_execute(s, &cmd); 686 if (ret) 687 goto err; 688 689 /* create mux i2c adapter for tuner */ 690 s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s, 691 0, 0, 0, si2168_select, si2168_deselect); 692 if (s->adapter == NULL) 693 goto err; 694 695 /* create dvb_frontend */ 696 memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops)); 697 s->fe.demodulator_priv = s; 698 699 *config->i2c_adapter = s->adapter; 700 *config->fe = &s->fe; 701 702 i2c_set_clientdata(client, s); 703 704 dev_info(&s->client->dev, 705 "%s: Silicon Labs Si2168 successfully attached\n", 706 KBUILD_MODNAME); 707 return 0; 708err: 709 kfree(s); 710 dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); 711 return ret; 712} 713 714static int si2168_remove(struct i2c_client *client) 715{ 716 struct si2168 *s = i2c_get_clientdata(client); 717 718 dev_dbg(&client->dev, "%s:\n", __func__); 719 720 i2c_del_mux_adapter(s->adapter); 721 722 s->fe.ops.release = NULL; 723 s->fe.demodulator_priv = NULL; 724 725 kfree(s); 726 727 return 0; 728} 729 730static const struct i2c_device_id si2168_id[] = { 731 {"si2168", 0}, 732 {} 733}; 734MODULE_DEVICE_TABLE(i2c, si2168_id); 735 736static struct i2c_driver si2168_driver = { 737 .driver = { 738 .owner = THIS_MODULE, 739 .name = "si2168", 740 }, 741 .probe = si2168_probe, 742 .remove = si2168_remove, 743 .id_table = si2168_id, 744}; 745 746module_i2c_driver(si2168_driver); 747 748MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 749MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver"); 750MODULE_LICENSE("GPL"); 751MODULE_FIRMWARE(SI2168_FIRMWARE); 752