Path: blob/master/drivers/media/radio/radio-timb.c
15112 views
/*1* radio-timb.c Timberdale FPGA Radio driver2* Copyright (c) 2009 Intel Corporation3*4* This program is free software; you can redistribute it and/or modify5* it under the terms of the GNU General Public License version 2 as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program; if not, write to the Free Software15* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.16*/1718#include <linux/version.h>19#include <linux/io.h>20#include <media/v4l2-ioctl.h>21#include <media/v4l2-device.h>22#include <linux/platform_device.h>23#include <linux/interrupt.h>24#include <linux/slab.h>25#include <linux/i2c.h>26#include <media/timb_radio.h>2728#define DRIVER_NAME "timb-radio"2930struct timbradio {31struct timb_radio_platform_data pdata;32struct v4l2_subdev *sd_tuner;33struct v4l2_subdev *sd_dsp;34struct video_device video_dev;35struct v4l2_device v4l2_dev;36struct mutex lock;37};383940static int timbradio_vidioc_querycap(struct file *file, void *priv,41struct v4l2_capability *v)42{43strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));44strlcpy(v->card, "Timberdale Radio", sizeof(v->card));45snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);46v->version = KERNEL_VERSION(0, 0, 1);47v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;48return 0;49}5051static int timbradio_vidioc_g_tuner(struct file *file, void *priv,52struct v4l2_tuner *v)53{54struct timbradio *tr = video_drvdata(file);55return v4l2_subdev_call(tr->sd_tuner, tuner, g_tuner, v);56}5758static int timbradio_vidioc_s_tuner(struct file *file, void *priv,59struct v4l2_tuner *v)60{61struct timbradio *tr = video_drvdata(file);62return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);63}6465static int timbradio_vidioc_g_input(struct file *filp, void *priv,66unsigned int *i)67{68*i = 0;69return 0;70}7172static int timbradio_vidioc_s_input(struct file *filp, void *priv,73unsigned int i)74{75return i ? -EINVAL : 0;76}7778static int timbradio_vidioc_g_audio(struct file *file, void *priv,79struct v4l2_audio *a)80{81a->index = 0;82strlcpy(a->name, "Radio", sizeof(a->name));83a->capability = V4L2_AUDCAP_STEREO;84return 0;85}8687static int timbradio_vidioc_s_audio(struct file *file, void *priv,88struct v4l2_audio *a)89{90return a->index ? -EINVAL : 0;91}9293static int timbradio_vidioc_s_frequency(struct file *file, void *priv,94struct v4l2_frequency *f)95{96struct timbradio *tr = video_drvdata(file);97return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f);98}99100static int timbradio_vidioc_g_frequency(struct file *file, void *priv,101struct v4l2_frequency *f)102{103struct timbradio *tr = video_drvdata(file);104return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);105}106107static int timbradio_vidioc_queryctrl(struct file *file, void *priv,108struct v4l2_queryctrl *qc)109{110struct timbradio *tr = video_drvdata(file);111return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);112}113114static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,115struct v4l2_control *ctrl)116{117struct timbradio *tr = video_drvdata(file);118return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);119}120121static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,122struct v4l2_control *ctrl)123{124struct timbradio *tr = video_drvdata(file);125return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);126}127128static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {129.vidioc_querycap = timbradio_vidioc_querycap,130.vidioc_g_tuner = timbradio_vidioc_g_tuner,131.vidioc_s_tuner = timbradio_vidioc_s_tuner,132.vidioc_g_frequency = timbradio_vidioc_g_frequency,133.vidioc_s_frequency = timbradio_vidioc_s_frequency,134.vidioc_g_input = timbradio_vidioc_g_input,135.vidioc_s_input = timbradio_vidioc_s_input,136.vidioc_g_audio = timbradio_vidioc_g_audio,137.vidioc_s_audio = timbradio_vidioc_s_audio,138.vidioc_queryctrl = timbradio_vidioc_queryctrl,139.vidioc_g_ctrl = timbradio_vidioc_g_ctrl,140.vidioc_s_ctrl = timbradio_vidioc_s_ctrl141};142143static const struct v4l2_file_operations timbradio_fops = {144.owner = THIS_MODULE,145.unlocked_ioctl = video_ioctl2,146};147148static int __devinit timbradio_probe(struct platform_device *pdev)149{150struct timb_radio_platform_data *pdata = pdev->dev.platform_data;151struct timbradio *tr;152int err;153154if (!pdata) {155dev_err(&pdev->dev, "Platform data missing\n");156err = -EINVAL;157goto err;158}159160tr = kzalloc(sizeof(*tr), GFP_KERNEL);161if (!tr) {162err = -ENOMEM;163goto err;164}165166tr->pdata = *pdata;167mutex_init(&tr->lock);168169strlcpy(tr->video_dev.name, "Timberdale Radio",170sizeof(tr->video_dev.name));171tr->video_dev.fops = &timbradio_fops;172tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;173tr->video_dev.release = video_device_release_empty;174tr->video_dev.minor = -1;175tr->video_dev.lock = &tr->lock;176177strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));178err = v4l2_device_register(NULL, &tr->v4l2_dev);179if (err)180goto err_v4l2_dev;181182tr->video_dev.v4l2_dev = &tr->v4l2_dev;183184err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);185if (err) {186dev_err(&pdev->dev, "Error reg video\n");187goto err_video_req;188}189190video_set_drvdata(&tr->video_dev, tr);191192platform_set_drvdata(pdev, tr);193return 0;194195err_video_req:196video_device_release_empty(&tr->video_dev);197v4l2_device_unregister(&tr->v4l2_dev);198err_v4l2_dev:199kfree(tr);200err:201dev_err(&pdev->dev, "Failed to register: %d\n", err);202203return err;204}205206static int __devexit timbradio_remove(struct platform_device *pdev)207{208struct timbradio *tr = platform_get_drvdata(pdev);209210video_unregister_device(&tr->video_dev);211video_device_release_empty(&tr->video_dev);212213v4l2_device_unregister(&tr->v4l2_dev);214215kfree(tr);216217return 0;218}219220static struct platform_driver timbradio_platform_driver = {221.driver = {222.name = DRIVER_NAME,223.owner = THIS_MODULE,224},225.probe = timbradio_probe,226.remove = timbradio_remove,227};228229/*--------------------------------------------------------------------------*/230231static int __init timbradio_init(void)232{233return platform_driver_register(&timbradio_platform_driver);234}235236static void __exit timbradio_exit(void)237{238platform_driver_unregister(&timbradio_platform_driver);239}240241module_init(timbradio_init);242module_exit(timbradio_exit);243244MODULE_DESCRIPTION("Timberdale Radio driver");245MODULE_AUTHOR("Mocean Laboratories <[email protected]>");246MODULE_LICENSE("GPL v2");247MODULE_ALIAS("platform:"DRIVER_NAME);248249250