2 * radio-timb.c Timberdale FPGA Radio driver
3 * Copyright (c) 2009 Intel Corporation
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <media/v4l2-ioctl.h>
17 #include <media/v4l2-device.h>
18 #include <media/v4l2-ctrls.h>
19 #include <media/v4l2-event.h>
20 #include <linux/platform_device.h>
21 #include <linux/interrupt.h>
22 #include <linux/slab.h>
23 #include <linux/i2c.h>
24 #include <linux/module.h>
25 #include <linux/platform_data/media/timb_radio.h>
27 #define DRIVER_NAME "timb-radio"
30 struct timb_radio_platform_data pdata
;
31 struct v4l2_subdev
*sd_tuner
;
32 struct v4l2_subdev
*sd_dsp
;
33 struct video_device video_dev
;
34 struct v4l2_device v4l2_dev
;
39 static int timbradio_vidioc_querycap(struct file
*file
, void *priv
,
40 struct v4l2_capability
*v
)
42 strlcpy(v
->driver
, DRIVER_NAME
, sizeof(v
->driver
));
43 strlcpy(v
->card
, "Timberdale Radio", sizeof(v
->card
));
44 snprintf(v
->bus_info
, sizeof(v
->bus_info
), "platform:"DRIVER_NAME
);
45 v
->device_caps
= V4L2_CAP_TUNER
| V4L2_CAP_RADIO
;
46 v
->capabilities
= v
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
50 static int timbradio_vidioc_g_tuner(struct file
*file
, void *priv
,
53 struct timbradio
*tr
= video_drvdata(file
);
54 return v4l2_subdev_call(tr
->sd_tuner
, tuner
, g_tuner
, v
);
57 static int timbradio_vidioc_s_tuner(struct file
*file
, void *priv
,
58 const struct v4l2_tuner
*v
)
60 struct timbradio
*tr
= video_drvdata(file
);
61 return v4l2_subdev_call(tr
->sd_tuner
, tuner
, s_tuner
, v
);
64 static int timbradio_vidioc_s_frequency(struct file
*file
, void *priv
,
65 const struct v4l2_frequency
*f
)
67 struct timbradio
*tr
= video_drvdata(file
);
68 return v4l2_subdev_call(tr
->sd_tuner
, tuner
, s_frequency
, f
);
71 static int timbradio_vidioc_g_frequency(struct file
*file
, void *priv
,
72 struct v4l2_frequency
*f
)
74 struct timbradio
*tr
= video_drvdata(file
);
75 return v4l2_subdev_call(tr
->sd_tuner
, tuner
, g_frequency
, f
);
78 static const struct v4l2_ioctl_ops timbradio_ioctl_ops
= {
79 .vidioc_querycap
= timbradio_vidioc_querycap
,
80 .vidioc_g_tuner
= timbradio_vidioc_g_tuner
,
81 .vidioc_s_tuner
= timbradio_vidioc_s_tuner
,
82 .vidioc_g_frequency
= timbradio_vidioc_g_frequency
,
83 .vidioc_s_frequency
= timbradio_vidioc_s_frequency
,
84 .vidioc_log_status
= v4l2_ctrl_log_status
,
85 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
86 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
89 static const struct v4l2_file_operations timbradio_fops
= {
92 .release
= v4l2_fh_release
,
93 .poll
= v4l2_ctrl_poll
,
94 .unlocked_ioctl
= video_ioctl2
,
97 static int timbradio_probe(struct platform_device
*pdev
)
99 struct timb_radio_platform_data
*pdata
= pdev
->dev
.platform_data
;
100 struct timbradio
*tr
;
104 dev_err(&pdev
->dev
, "Platform data missing\n");
109 tr
= devm_kzalloc(&pdev
->dev
, sizeof(*tr
), GFP_KERNEL
);
116 mutex_init(&tr
->lock
);
118 strlcpy(tr
->video_dev
.name
, "Timberdale Radio",
119 sizeof(tr
->video_dev
.name
));
120 tr
->video_dev
.fops
= &timbradio_fops
;
121 tr
->video_dev
.ioctl_ops
= &timbradio_ioctl_ops
;
122 tr
->video_dev
.release
= video_device_release_empty
;
123 tr
->video_dev
.minor
= -1;
124 tr
->video_dev
.lock
= &tr
->lock
;
126 strlcpy(tr
->v4l2_dev
.name
, DRIVER_NAME
, sizeof(tr
->v4l2_dev
.name
));
127 err
= v4l2_device_register(NULL
, &tr
->v4l2_dev
);
131 tr
->video_dev
.v4l2_dev
= &tr
->v4l2_dev
;
133 tr
->sd_tuner
= v4l2_i2c_new_subdev_board(&tr
->v4l2_dev
,
134 i2c_get_adapter(pdata
->i2c_adapter
), pdata
->tuner
, NULL
);
135 tr
->sd_dsp
= v4l2_i2c_new_subdev_board(&tr
->v4l2_dev
,
136 i2c_get_adapter(pdata
->i2c_adapter
), pdata
->dsp
, NULL
);
137 if (tr
->sd_tuner
== NULL
|| tr
->sd_dsp
== NULL
) {
142 tr
->v4l2_dev
.ctrl_handler
= tr
->sd_dsp
->ctrl_handler
;
144 err
= video_register_device(&tr
->video_dev
, VFL_TYPE_RADIO
, -1);
146 dev_err(&pdev
->dev
, "Error reg video\n");
150 video_set_drvdata(&tr
->video_dev
, tr
);
152 platform_set_drvdata(pdev
, tr
);
156 v4l2_device_unregister(&tr
->v4l2_dev
);
158 dev_err(&pdev
->dev
, "Failed to register: %d\n", err
);
163 static int timbradio_remove(struct platform_device
*pdev
)
165 struct timbradio
*tr
= platform_get_drvdata(pdev
);
167 video_unregister_device(&tr
->video_dev
);
168 v4l2_device_unregister(&tr
->v4l2_dev
);
172 static struct platform_driver timbradio_platform_driver
= {
176 .probe
= timbradio_probe
,
177 .remove
= timbradio_remove
,
180 module_platform_driver(timbradio_platform_driver
);
182 MODULE_DESCRIPTION("Timberdale Radio driver");
183 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
184 MODULE_LICENSE("GPL v2");
185 MODULE_VERSION("0.0.2");
186 MODULE_ALIAS("platform:"DRIVER_NAME
);