.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * drivers/media/radio/si470x/radio-si470x-i2c.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Copyright (c) 2009 Samsung Electronics Co.Ltd |
---|
7 | 8 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
12 | | - * (at your option) any later version. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, |
---|
15 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
17 | | - * GNU General Public License for more details. |
---|
18 | 9 | */ |
---|
19 | 10 | |
---|
20 | 11 | |
---|
.. | .. |
---|
28 | 19 | #include <linux/i2c.h> |
---|
29 | 20 | #include <linux/slab.h> |
---|
30 | 21 | #include <linux/delay.h> |
---|
| 22 | +#include <linux/gpio/consumer.h> |
---|
31 | 23 | #include <linux/interrupt.h> |
---|
32 | 24 | |
---|
33 | 25 | #include "radio-si470x.h" |
---|
.. | .. |
---|
229 | 221 | static int si470x_vidioc_querycap(struct file *file, void *priv, |
---|
230 | 222 | struct v4l2_capability *capability) |
---|
231 | 223 | { |
---|
232 | | - strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); |
---|
233 | | - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); |
---|
234 | | - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | |
---|
235 | | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; |
---|
236 | | - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; |
---|
237 | | - |
---|
| 224 | + strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); |
---|
| 225 | + strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); |
---|
238 | 226 | return 0; |
---|
239 | 227 | } |
---|
240 | 228 | |
---|
.. | .. |
---|
342 | 330 | /* |
---|
343 | 331 | * si470x_i2c_probe - probe for the device |
---|
344 | 332 | */ |
---|
345 | | -static int si470x_i2c_probe(struct i2c_client *client, |
---|
346 | | - const struct i2c_device_id *id) |
---|
| 333 | +static int si470x_i2c_probe(struct i2c_client *client) |
---|
347 | 334 | { |
---|
348 | 335 | struct si470x_device *radio; |
---|
349 | 336 | int retval = 0; |
---|
350 | 337 | unsigned char version_warning = 0; |
---|
351 | 338 | |
---|
352 | 339 | /* private data allocation and initialization */ |
---|
353 | | - radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); |
---|
| 340 | + radio = devm_kzalloc(&client->dev, sizeof(*radio), GFP_KERNEL); |
---|
354 | 341 | if (!radio) { |
---|
355 | 342 | retval = -ENOMEM; |
---|
356 | 343 | goto err_initial; |
---|
.. | .. |
---|
370 | 357 | retval = v4l2_device_register(&client->dev, &radio->v4l2_dev); |
---|
371 | 358 | if (retval < 0) { |
---|
372 | 359 | dev_err(&client->dev, "couldn't register v4l2_device\n"); |
---|
373 | | - goto err_radio; |
---|
| 360 | + goto err_initial; |
---|
374 | 361 | } |
---|
375 | 362 | |
---|
376 | 363 | v4l2_ctrl_handler_init(&radio->hdl, 2); |
---|
.. | .. |
---|
390 | 377 | radio->videodev.lock = &radio->lock; |
---|
391 | 378 | radio->videodev.v4l2_dev = &radio->v4l2_dev; |
---|
392 | 379 | radio->videodev.release = video_device_release_empty; |
---|
| 380 | + radio->videodev.device_caps = |
---|
| 381 | + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | |
---|
| 382 | + V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; |
---|
393 | 383 | video_set_drvdata(&radio->videodev, radio); |
---|
| 384 | + |
---|
| 385 | + radio->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", |
---|
| 386 | + GPIOD_OUT_LOW); |
---|
| 387 | + if (IS_ERR(radio->gpio_reset)) { |
---|
| 388 | + retval = PTR_ERR(radio->gpio_reset); |
---|
| 389 | + dev_err(&client->dev, "Failed to request gpio: %d\n", retval); |
---|
| 390 | + goto err_all; |
---|
| 391 | + } |
---|
| 392 | + |
---|
| 393 | + if (radio->gpio_reset) |
---|
| 394 | + gpiod_set_value(radio->gpio_reset, 1); |
---|
394 | 395 | |
---|
395 | 396 | /* power up : need 110ms */ |
---|
396 | 397 | radio->registers[POWERCFG] = POWERCFG_ENABLE; |
---|
397 | 398 | if (si470x_set_register(radio, POWERCFG) < 0) { |
---|
398 | 399 | retval = -EIO; |
---|
399 | | - goto err_ctrl; |
---|
| 400 | + goto err_all; |
---|
400 | 401 | } |
---|
401 | 402 | msleep(110); |
---|
402 | 403 | |
---|
403 | 404 | /* get device and chip versions */ |
---|
404 | 405 | if (si470x_get_all_registers(radio) < 0) { |
---|
405 | 406 | retval = -EIO; |
---|
406 | | - goto err_ctrl; |
---|
| 407 | + goto err_all; |
---|
407 | 408 | } |
---|
408 | 409 | dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", |
---|
409 | 410 | radio->registers[DEVICEID], radio->registers[SI_CHIPID]); |
---|
.. | .. |
---|
430 | 431 | |
---|
431 | 432 | /* rds buffer allocation */ |
---|
432 | 433 | radio->buf_size = rds_buf * 3; |
---|
433 | | - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); |
---|
| 434 | + radio->buffer = devm_kmalloc(&client->dev, radio->buf_size, GFP_KERNEL); |
---|
434 | 435 | if (!radio->buffer) { |
---|
435 | 436 | retval = -EIO; |
---|
436 | | - goto err_ctrl; |
---|
| 437 | + goto err_all; |
---|
437 | 438 | } |
---|
438 | 439 | |
---|
439 | 440 | /* rds buffer configuration */ |
---|
.. | .. |
---|
441 | 442 | radio->rd_index = 0; |
---|
442 | 443 | init_waitqueue_head(&radio->read_queue); |
---|
443 | 444 | |
---|
444 | | - retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt, |
---|
445 | | - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRIVER_NAME, |
---|
446 | | - radio); |
---|
| 445 | + retval = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
---|
| 446 | + si470x_i2c_interrupt, |
---|
| 447 | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
---|
| 448 | + DRIVER_NAME, radio); |
---|
447 | 449 | if (retval) { |
---|
448 | 450 | dev_err(&client->dev, "Failed to register interrupt\n"); |
---|
449 | | - goto err_rds; |
---|
| 451 | + goto err_all; |
---|
450 | 452 | } |
---|
451 | 453 | |
---|
452 | 454 | /* register video device */ |
---|
.. | .. |
---|
460 | 462 | |
---|
461 | 463 | return 0; |
---|
462 | 464 | err_all: |
---|
463 | | - free_irq(client->irq, radio); |
---|
464 | | -err_rds: |
---|
465 | | - kfree(radio->buffer); |
---|
466 | | -err_ctrl: |
---|
467 | 465 | v4l2_ctrl_handler_free(&radio->hdl); |
---|
468 | 466 | v4l2_device_unregister(&radio->v4l2_dev); |
---|
469 | | -err_radio: |
---|
470 | | - kfree(radio); |
---|
471 | 467 | err_initial: |
---|
472 | 468 | return retval; |
---|
473 | 469 | } |
---|
.. | .. |
---|
480 | 476 | { |
---|
481 | 477 | struct si470x_device *radio = i2c_get_clientdata(client); |
---|
482 | 478 | |
---|
483 | | - free_irq(client->irq, radio); |
---|
484 | 479 | video_unregister_device(&radio->videodev); |
---|
| 480 | + |
---|
| 481 | + if (radio->gpio_reset) |
---|
| 482 | + gpiod_set_value(radio->gpio_reset, 0); |
---|
485 | 483 | |
---|
486 | 484 | v4l2_ctrl_handler_free(&radio->hdl); |
---|
487 | 485 | v4l2_device_unregister(&radio->v4l2_dev); |
---|
488 | | - kfree(radio); |
---|
489 | 486 | return 0; |
---|
490 | 487 | } |
---|
491 | 488 | |
---|
.. | .. |
---|
528 | 525 | static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume); |
---|
529 | 526 | #endif |
---|
530 | 527 | |
---|
| 528 | +#if IS_ENABLED(CONFIG_OF) |
---|
| 529 | +static const struct of_device_id si470x_of_match[] = { |
---|
| 530 | + { .compatible = "silabs,si470x" }, |
---|
| 531 | + { }, |
---|
| 532 | +}; |
---|
| 533 | +MODULE_DEVICE_TABLE(of, si470x_of_match); |
---|
| 534 | +#endif |
---|
531 | 535 | |
---|
532 | 536 | /* |
---|
533 | 537 | * si470x_i2c_driver - i2c driver interface |
---|
.. | .. |
---|
535 | 539 | static struct i2c_driver si470x_i2c_driver = { |
---|
536 | 540 | .driver = { |
---|
537 | 541 | .name = "si470x", |
---|
| 542 | + .of_match_table = of_match_ptr(si470x_of_match), |
---|
538 | 543 | #ifdef CONFIG_PM_SLEEP |
---|
539 | 544 | .pm = &si470x_i2c_pm, |
---|
540 | 545 | #endif |
---|
541 | 546 | }, |
---|
542 | | - .probe = si470x_i2c_probe, |
---|
| 547 | + .probe_new = si470x_i2c_probe, |
---|
543 | 548 | .remove = si470x_i2c_remove, |
---|
544 | 549 | .id_table = si470x_i2c_id, |
---|
545 | 550 | }; |
---|