aboutsummaryrefslogtreecommitdiffstats
path: root/sound/i2c/other/tea575x-tuner.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/i2c/other/tea575x-tuner.c')
-rw-r--r--sound/i2c/other/tea575x-tuner.c302
1 files changed, 207 insertions, 95 deletions
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index 9d98a6658ac9..d31c373e076d 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -24,6 +24,7 @@
24#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/init.h> 26#include <linux/init.h>
27#include <linux/version.h>
27#include <sound/core.h> 28#include <sound/core.h>
28#include <sound/tea575x-tuner.h> 29#include <sound/tea575x-tuner.h>
29 30
@@ -31,6 +32,13 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
31MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); 32MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
32MODULE_LICENSE("GPL"); 33MODULE_LICENSE("GPL");
33 34
35static int radio_nr = -1;
36module_param(radio_nr, int, 0);
37
38#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
39#define FREQ_LO (87 * 16000)
40#define FREQ_HI (108 * 16000)
41
34/* 42/*
35 * definitions 43 * definitions
36 */ 44 */
@@ -53,6 +61,17 @@ MODULE_LICENSE("GPL");
53#define TEA575X_BIT_DUMMY (1<<15) /* buffer */ 61#define TEA575X_BIT_DUMMY (1<<15) /* buffer */
54#define TEA575X_BIT_FREQ_MASK 0x7fff 62#define TEA575X_BIT_FREQ_MASK 0x7fff
55 63
64static struct v4l2_queryctrl radio_qctrl[] = {
65 {
66 .id = V4L2_CID_AUDIO_MUTE,
67 .name = "Mute",
68 .minimum = 0,
69 .maximum = 1,
70 .default_value = 1,
71 .type = V4L2_CTRL_TYPE_BOOLEAN,
72 }
73};
74
56/* 75/*
57 * lowlevel part 76 * lowlevel part
58 */ 77 */
@@ -84,94 +103,146 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
84 * Linux Video interface 103 * Linux Video interface
85 */ 104 */
86 105
87static long snd_tea575x_ioctl(struct file *file, 106static int vidioc_querycap(struct file *file, void *priv,
88 unsigned int cmd, unsigned long data) 107 struct v4l2_capability *v)
89{ 108{
90 struct snd_tea575x *tea = video_drvdata(file); 109 struct snd_tea575x *tea = video_drvdata(file);
91 void __user *arg = (void __user *)data; 110
92 111 strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
93 switch(cmd) { 112 strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
94 case VIDIOCGCAP: 113 strlcpy(v->card, "Maestro Radio", sizeof(v->card));
95 { 114 sprintf(v->bus_info, "PCI");
96 struct video_capability v; 115 v->version = RADIO_VERSION;
97 v.type = VID_TYPE_TUNER; 116 v->capabilities = V4L2_CAP_TUNER;
98 v.channels = 1; 117 return 0;
99 v.audios = 1; 118}
100 /* No we don't do pictures */ 119
101 v.maxwidth = 0; 120static int vidioc_g_tuner(struct file *file, void *priv,
102 v.maxheight = 0; 121 struct v4l2_tuner *v)
103 v.minwidth = 0; 122{
104 v.minheight = 0; 123 if (v->index > 0)
105 strcpy(v.name, tea->tea5759 ? "TEA5759" : "TEA5757"); 124 return -EINVAL;
106 if (copy_to_user(arg,&v,sizeof(v))) 125
107 return -EFAULT; 126 strcpy(v->name, "FM");
108 return 0; 127 v->type = V4L2_TUNER_RADIO;
109 } 128 v->rangelow = FREQ_LO;
110 case VIDIOCGTUNER: 129 v->rangehigh = FREQ_HI;
111 { 130 v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
112 struct video_tuner v; 131 v->capability = V4L2_TUNER_CAP_LOW;
113 if (copy_from_user(&v, arg,sizeof(v))!=0) 132 v->audmode = V4L2_TUNER_MODE_MONO;
114 return -EFAULT; 133 v->signal = 0xffff;
115 if (v.tuner) /* Only 1 tuner */ 134 return 0;
116 return -EINVAL; 135}
117 v.rangelow = (87*16000); 136
118 v.rangehigh = (108*16000); 137static int vidioc_s_tuner(struct file *file, void *priv,
119 v.flags = VIDEO_TUNER_LOW; 138 struct v4l2_tuner *v)
120 v.mode = VIDEO_MODE_AUTO; 139{
121 strcpy(v.name, "FM"); 140 if (v->index > 0)
122 v.signal = 0xFFFF; 141 return -EINVAL;
123 if (copy_to_user(arg, &v, sizeof(v))) 142 return 0;
124 return -EFAULT; 143}
125 return 0; 144
126 } 145static int vidioc_g_frequency(struct file *file, void *priv,
127 case VIDIOCSTUNER: 146 struct v4l2_frequency *f)
128 { 147{
129 struct video_tuner v; 148 struct snd_tea575x *tea = video_drvdata(file);
130 if(copy_from_user(&v, arg, sizeof(v))) 149
131 return -EFAULT; 150 f->type = V4L2_TUNER_RADIO;
132 if(v.tuner!=0) 151 f->frequency = tea->freq;
133 return -EINVAL; 152 return 0;
134 /* Only 1 tuner so no setting needed ! */ 153}
154
155static int vidioc_s_frequency(struct file *file, void *priv,
156 struct v4l2_frequency *f)
157{
158 struct snd_tea575x *tea = video_drvdata(file);
159
160 if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
161 return -EINVAL;
162
163 tea->freq = f->frequency;
164
165 snd_tea575x_set_freq(tea);
166
167 return 0;
168}
169
170static int vidioc_g_audio(struct file *file, void *priv,
171 struct v4l2_audio *a)
172{
173 if (a->index > 1)
174 return -EINVAL;
175
176 strcpy(a->name, "Radio");
177 a->capability = V4L2_AUDCAP_STEREO;
178 return 0;
179}
180
181static int vidioc_s_audio(struct file *file, void *priv,
182 struct v4l2_audio *a)
183{
184 if (a->index != 0)
185 return -EINVAL;
186 return 0;
187}
188
189static int vidioc_queryctrl(struct file *file, void *priv,
190 struct v4l2_queryctrl *qc)
191{
192 int i;
193
194 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
195 if (qc->id && qc->id == radio_qctrl[i].id) {
196 memcpy(qc, &(radio_qctrl[i]),
197 sizeof(*qc));
135 return 0; 198 return 0;
136 } 199 }
137 case VIDIOCGFREQ: 200 }
138 if(copy_to_user(arg, &tea->freq, sizeof(tea->freq))) 201 return -EINVAL;
139 return -EFAULT; 202}
140 return 0; 203
141 case VIDIOCSFREQ: 204static int vidioc_g_ctrl(struct file *file, void *priv,
142 if(copy_from_user(&tea->freq, arg, sizeof(tea->freq))) 205 struct v4l2_control *ctrl)
143 return -EFAULT; 206{
144 snd_tea575x_set_freq(tea); 207 struct snd_tea575x *tea = video_drvdata(file);
145 return 0; 208
146 case VIDIOCGAUDIO: 209 switch (ctrl->id) {
147 { 210 case V4L2_CID_AUDIO_MUTE:
148 struct video_audio v; 211 if (tea->ops->mute) {
149 memset(&v, 0, sizeof(v)); 212 ctrl->value = tea->mute;
150 strcpy(v.name, "Radio");
151 if(copy_to_user(arg,&v, sizeof(v)))
152 return -EFAULT;
153 return 0; 213 return 0;
154 } 214 }
155 case VIDIOCSAUDIO: 215 }
156 { 216 return -EINVAL;
157 struct video_audio v; 217}
158 if(copy_from_user(&v, arg, sizeof(v))) 218
159 return -EFAULT; 219static int vidioc_s_ctrl(struct file *file, void *priv,
160 if (tea->ops->mute) 220 struct v4l2_control *ctrl)
161 tea->ops->mute(tea, 221{
162 (v.flags & 222 struct snd_tea575x *tea = video_drvdata(file);
163 VIDEO_AUDIO_MUTE) ? 1 : 0); 223
164 if(v.audio) 224 switch (ctrl->id) {
165 return -EINVAL; 225 case V4L2_CID_AUDIO_MUTE:
226 if (tea->ops->mute) {
227 tea->ops->mute(tea, ctrl->value);
228 tea->mute = 1;
166 return 0; 229 return 0;
167 } 230 }
168 default:
169 return -ENOIOCTLCMD;
170 } 231 }
232 return -EINVAL;
233}
234
235static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
236{
237 *i = 0;
238 return 0;
171} 239}
172 240
173static void snd_tea575x_release(struct video_device *vfd) 241static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
174{ 242{
243 if (i != 0)
244 return -EINVAL;
245 return 0;
175} 246}
176 247
177static int snd_tea575x_exclusive_open(struct file *file) 248static int snd_tea575x_exclusive_open(struct file *file)
@@ -189,50 +260,91 @@ static int snd_tea575x_exclusive_release(struct file *file)
189 return 0; 260 return 0;
190} 261}
191 262
263static const struct v4l2_file_operations tea575x_fops = {
264 .owner = THIS_MODULE,
265 .open = snd_tea575x_exclusive_open,
266 .release = snd_tea575x_exclusive_release,
267 .ioctl = video_ioctl2,
268};
269
270static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
271 .vidioc_querycap = vidioc_querycap,
272 .vidioc_g_tuner = vidioc_g_tuner,
273 .vidioc_s_tuner = vidioc_s_tuner,
274 .vidioc_g_audio = vidioc_g_audio,
275 .vidioc_s_audio = vidioc_s_audio,
276 .vidioc_g_input = vidioc_g_input,
277 .vidioc_s_input = vidioc_s_input,
278 .vidioc_g_frequency = vidioc_g_frequency,
279 .vidioc_s_frequency = vidioc_s_frequency,
280 .vidioc_queryctrl = vidioc_queryctrl,
281 .vidioc_g_ctrl = vidioc_g_ctrl,
282 .vidioc_s_ctrl = vidioc_s_ctrl,
283};
284
285static struct video_device tea575x_radio = {
286 .name = "tea575x-tuner",
287 .fops = &tea575x_fops,
288 .ioctl_ops = &tea575x_ioctl_ops,
289 .release = video_device_release,
290};
291
192/* 292/*
193 * initialize all the tea575x chips 293 * initialize all the tea575x chips
194 */ 294 */
195void snd_tea575x_init(struct snd_tea575x *tea) 295void snd_tea575x_init(struct snd_tea575x *tea)
196{ 296{
297 int retval;
197 unsigned int val; 298 unsigned int val;
299 struct video_device *tea575x_radio_inst;
198 300
199 val = tea->ops->read(tea); 301 val = tea->ops->read(tea);
200 if (val == 0x1ffffff || val == 0) { 302 if (val == 0x1ffffff || val == 0) {
201 snd_printk(KERN_ERR "Cannot find TEA575x chip\n"); 303 snd_printk(KERN_ERR
304 "tea575x-tuner: Cannot find TEA575x chip\n");
202 return; 305 return;
203 } 306 }
204 307
205 memset(&tea->vd, 0, sizeof(tea->vd));
206 strcpy(tea->vd.name, tea->tea5759 ? "TEA5759 radio" : "TEA5757 radio");
207 tea->vd.release = snd_tea575x_release;
208 video_set_drvdata(&tea->vd, tea);
209 tea->vd.fops = &tea->fops;
210 tea->in_use = 0; 308 tea->in_use = 0;
211 tea->fops.owner = tea->card->module; 309 tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
212 tea->fops.open = snd_tea575x_exclusive_open; 310 tea->freq = 90500 * 16; /* 90.5Mhz default */
213 tea->fops.release = snd_tea575x_exclusive_release; 311
214 tea->fops.ioctl = snd_tea575x_ioctl; 312 tea575x_radio_inst = video_device_alloc();
215 if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) { 313 if (tea575x_radio_inst == NULL) {
216 snd_printk(KERN_ERR "unable to register tea575x tuner\n"); 314 printk(KERN_ERR "tea575x-tuner: not enough memory\n");
217 return; 315 return;
218 } 316 }
219 tea->vd_registered = 1;
220 317
221 tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; 318 memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
222 tea->freq = 90500 * 16; /* 90.5Mhz default */ 319
320 strcpy(tea575x_radio.name, tea->tea5759 ?
321 "TEA5759 radio" : "TEA5757 radio");
322
323 video_set_drvdata(tea575x_radio_inst, tea);
324
325 retval = video_register_device(tea575x_radio_inst,
326 VFL_TYPE_RADIO, radio_nr);
327 if (retval) {
328 printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
329 kfree(tea575x_radio_inst);
330 return;
331 }
223 332
224 snd_tea575x_set_freq(tea); 333 snd_tea575x_set_freq(tea);
225 334
226 /* mute on init */ 335 /* mute on init */
227 if (tea->ops->mute) 336 if (tea->ops->mute) {
228 tea->ops->mute(tea, 1); 337 tea->ops->mute(tea, 1);
338 tea->mute = 1;
339 }
340 tea->vd = tea575x_radio_inst;
229} 341}
230 342
231void snd_tea575x_exit(struct snd_tea575x *tea) 343void snd_tea575x_exit(struct snd_tea575x *tea)
232{ 344{
233 if (tea->vd_registered) { 345 if (tea->vd) {
234 video_unregister_device(&tea->vd); 346 video_unregister_device(tea->vd);
235 tea->vd_registered = 0; 347 tea->vd = NULL;
236 } 348 }
237} 349}
238 350