tea575x.c revision 54f6019b5860ec062d1149b3a97a5a63ad3e4da9
1/* 2 * ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips 3 * 4 * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23#include <asm/io.h> 24#include <linux/delay.h> 25#include <linux/module.h> 26#include <linux/init.h> 27#include <linux/slab.h> 28#include <linux/sched.h> 29#include <media/v4l2-device.h> 30#include <media/v4l2-dev.h> 31#include <media/v4l2-fh.h> 32#include <media/v4l2-ioctl.h> 33#include <media/v4l2-event.h> 34#include <sound/tea575x-tuner.h> 35 36MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 37MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); 38MODULE_LICENSE("GPL"); 39 40#define FREQ_LO (76U * 16000) 41#define FREQ_HI (108U * 16000) 42 43/* 44 * definitions 45 */ 46 47#define TEA575X_BIT_SEARCH (1<<24) /* 1 = search action, 0 = tuned */ 48#define TEA575X_BIT_UPDOWN (1<<23) /* 0 = search down, 1 = search up */ 49#define TEA575X_BIT_MONO (1<<22) /* 0 = stereo, 1 = mono */ 50#define TEA575X_BIT_BAND_MASK (3<<20) 51#define TEA575X_BIT_BAND_FM (0<<20) 52#define TEA575X_BIT_BAND_MW (1<<20) 53#define TEA575X_BIT_BAND_LW (1<<21) 54#define TEA575X_BIT_BAND_SW (1<<22) 55#define TEA575X_BIT_PORT_0 (1<<19) /* user bit */ 56#define TEA575X_BIT_PORT_1 (1<<18) /* user bit */ 57#define TEA575X_BIT_SEARCH_MASK (3<<16) /* search level */ 58#define TEA575X_BIT_SEARCH_5_28 (0<<16) /* FM >5uV, AM >28uV */ 59#define TEA575X_BIT_SEARCH_10_40 (1<<16) /* FM >10uV, AM > 40uV */ 60#define TEA575X_BIT_SEARCH_30_63 (2<<16) /* FM >30uV, AM > 63uV */ 61#define TEA575X_BIT_SEARCH_150_1000 (3<<16) /* FM > 150uV, AM > 1000uV */ 62#define TEA575X_BIT_DUMMY (1<<15) /* buffer */ 63#define TEA575X_BIT_FREQ_MASK 0x7fff 64 65/* 66 * lowlevel part 67 */ 68 69static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) 70{ 71 u16 l; 72 u8 data; 73 74 tea->ops->set_direction(tea, 1); 75 udelay(16); 76 77 for (l = 25; l > 0; l--) { 78 data = (val >> 24) & TEA575X_DATA; 79 val <<= 1; /* shift data */ 80 tea->ops->set_pins(tea, data | TEA575X_WREN); 81 udelay(2); 82 tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK); 83 udelay(2); 84 tea->ops->set_pins(tea, data | TEA575X_WREN); 85 udelay(2); 86 } 87 88 if (!tea->mute) 89 tea->ops->set_pins(tea, 0); 90} 91 92static u32 snd_tea575x_read(struct snd_tea575x *tea) 93{ 94 u16 l, rdata; 95 u32 data = 0; 96 97 tea->ops->set_direction(tea, 0); 98 tea->ops->set_pins(tea, 0); 99 udelay(16); 100 101 for (l = 24; l--;) { 102 tea->ops->set_pins(tea, TEA575X_CLK); 103 udelay(2); 104 if (!l) 105 tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1; 106 tea->ops->set_pins(tea, 0); 107 udelay(2); 108 data <<= 1; /* shift data */ 109 rdata = tea->ops->get_pins(tea); 110 if (!l) 111 tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1; 112 if (rdata & TEA575X_DATA) 113 data++; 114 udelay(2); 115 } 116 117 if (tea->mute) 118 tea->ops->set_pins(tea, TEA575X_WREN); 119 120 return data; 121} 122 123static u32 snd_tea575x_get_freq(struct snd_tea575x *tea) 124{ 125 u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; 126 127 if (freq == 0) 128 return freq; 129 130 /* freq *= 12.5 */ 131 freq *= 125; 132 freq /= 10; 133 /* crystal fixup */ 134 if (tea->tea5759) 135 freq += TEA575X_FMIF; 136 else 137 freq -= TEA575X_FMIF; 138 139 return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */ 140} 141 142static void snd_tea575x_set_freq(struct snd_tea575x *tea) 143{ 144 u32 freq = tea->freq; 145 146 freq /= 16; /* to kHz */ 147 /* crystal fixup */ 148 if (tea->tea5759) 149 freq -= TEA575X_FMIF; 150 else 151 freq += TEA575X_FMIF; 152 /* freq /= 12.5 */ 153 freq *= 10; 154 freq /= 125; 155 156 tea->val &= ~TEA575X_BIT_FREQ_MASK; 157 tea->val |= freq & TEA575X_BIT_FREQ_MASK; 158 snd_tea575x_write(tea, tea->val); 159} 160 161/* 162 * Linux Video interface 163 */ 164 165static int vidioc_querycap(struct file *file, void *priv, 166 struct v4l2_capability *v) 167{ 168 struct snd_tea575x *tea = video_drvdata(file); 169 170 strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); 171 strlcpy(v->card, tea->card, sizeof(v->card)); 172 strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); 173 strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); 174 v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; 175 if (!tea->cannot_read_data) 176 v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; 177 v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; 178 return 0; 179} 180 181static int vidioc_g_tuner(struct file *file, void *priv, 182 struct v4l2_tuner *v) 183{ 184 struct snd_tea575x *tea = video_drvdata(file); 185 186 if (v->index > 0) 187 return -EINVAL; 188 189 snd_tea575x_read(tea); 190 191 strcpy(v->name, "FM"); 192 v->type = V4L2_TUNER_RADIO; 193 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; 194 if (!tea->cannot_read_data) 195 v->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED; 196 v->rangelow = FREQ_LO; 197 v->rangehigh = FREQ_HI; 198 v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; 199 v->audmode = (tea->val & TEA575X_BIT_MONO) ? 200 V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; 201 v->signal = tea->tuned ? 0xffff : 0; 202 return 0; 203} 204 205static int vidioc_s_tuner(struct file *file, void *priv, 206 struct v4l2_tuner *v) 207{ 208 struct snd_tea575x *tea = video_drvdata(file); 209 210 if (v->index) 211 return -EINVAL; 212 tea->val &= ~TEA575X_BIT_MONO; 213 if (v->audmode == V4L2_TUNER_MODE_MONO) 214 tea->val |= TEA575X_BIT_MONO; 215 snd_tea575x_write(tea, tea->val); 216 return 0; 217} 218 219static int vidioc_g_frequency(struct file *file, void *priv, 220 struct v4l2_frequency *f) 221{ 222 struct snd_tea575x *tea = video_drvdata(file); 223 224 if (f->tuner != 0) 225 return -EINVAL; 226 f->type = V4L2_TUNER_RADIO; 227 f->frequency = tea->freq; 228 return 0; 229} 230 231static int vidioc_s_frequency(struct file *file, void *priv, 232 struct v4l2_frequency *f) 233{ 234 struct snd_tea575x *tea = video_drvdata(file); 235 236 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) 237 return -EINVAL; 238 239 tea->val &= ~TEA575X_BIT_SEARCH; 240 tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI); 241 snd_tea575x_set_freq(tea); 242 return 0; 243} 244 245static int vidioc_s_hw_freq_seek(struct file *file, void *fh, 246 struct v4l2_hw_freq_seek *a) 247{ 248 struct snd_tea575x *tea = video_drvdata(file); 249 unsigned long timeout; 250 int i; 251 252 if (tea->cannot_read_data) 253 return -ENOTTY; 254 if (a->tuner || a->wrap_around) 255 return -EINVAL; 256 257 /* clear the frequency, HW will fill it in */ 258 tea->val &= ~TEA575X_BIT_FREQ_MASK; 259 tea->val |= TEA575X_BIT_SEARCH; 260 if (a->seek_upward) 261 tea->val |= TEA575X_BIT_UPDOWN; 262 else 263 tea->val &= ~TEA575X_BIT_UPDOWN; 264 snd_tea575x_write(tea, tea->val); 265 timeout = jiffies + msecs_to_jiffies(10000); 266 for (;;) { 267 if (time_after(jiffies, timeout)) 268 break; 269 if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { 270 /* some signal arrived, stop search */ 271 tea->val &= ~TEA575X_BIT_SEARCH; 272 snd_tea575x_set_freq(tea); 273 return -ERESTARTSYS; 274 } 275 if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) { 276 u32 freq; 277 278 /* Found a frequency, wait until it can be read */ 279 for (i = 0; i < 100; i++) { 280 msleep(10); 281 freq = snd_tea575x_get_freq(tea); 282 if (freq) /* available */ 283 break; 284 } 285 if (freq == 0) /* shouldn't happen */ 286 break; 287 /* 288 * if we moved by less than 50 kHz, or in the wrong 289 * direction, continue seeking 290 */ 291 if (abs(tea->freq - freq) < 16 * 50 || 292 (a->seek_upward && freq < tea->freq) || 293 (!a->seek_upward && freq > tea->freq)) { 294 snd_tea575x_write(tea, tea->val); 295 continue; 296 } 297 tea->freq = freq; 298 tea->val &= ~TEA575X_BIT_SEARCH; 299 return 0; 300 } 301 } 302 tea->val &= ~TEA575X_BIT_SEARCH; 303 snd_tea575x_set_freq(tea); 304 return -ENODATA; 305} 306 307static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl) 308{ 309 struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler); 310 311 switch (ctrl->id) { 312 case V4L2_CID_AUDIO_MUTE: 313 tea->mute = ctrl->val; 314 snd_tea575x_set_freq(tea); 315 return 0; 316 } 317 318 return -EINVAL; 319} 320 321static const struct v4l2_file_operations tea575x_fops = { 322 .owner = THIS_MODULE, 323 .unlocked_ioctl = video_ioctl2, 324 .open = v4l2_fh_open, 325 .release = v4l2_fh_release, 326 .poll = v4l2_ctrl_poll, 327}; 328 329static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { 330 .vidioc_querycap = vidioc_querycap, 331 .vidioc_g_tuner = vidioc_g_tuner, 332 .vidioc_s_tuner = vidioc_s_tuner, 333 .vidioc_g_frequency = vidioc_g_frequency, 334 .vidioc_s_frequency = vidioc_s_frequency, 335 .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, 336 .vidioc_log_status = v4l2_ctrl_log_status, 337 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 338 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 339}; 340 341static const struct video_device tea575x_radio = { 342 .fops = &tea575x_fops, 343 .ioctl_ops = &tea575x_ioctl_ops, 344 .release = video_device_release_empty, 345}; 346 347static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { 348 .s_ctrl = tea575x_s_ctrl, 349}; 350 351/* 352 * initialize all the tea575x chips 353 */ 354int snd_tea575x_init(struct snd_tea575x *tea) 355{ 356 int retval; 357 358 tea->mute = true; 359 360 /* Not all devices can or know how to read the data back. 361 Such devices can set cannot_read_data to true. */ 362 if (!tea->cannot_read_data) { 363 snd_tea575x_write(tea, 0x55AA); 364 if (snd_tea575x_read(tea) != 0x55AA) 365 return -ENODEV; 366 } 367 368 tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28; 369 tea->freq = 90500 * 16; /* 90.5Mhz default */ 370 snd_tea575x_set_freq(tea); 371 372 tea->vd = tea575x_radio; 373 video_set_drvdata(&tea->vd, tea); 374 mutex_init(&tea->mutex); 375 strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); 376 tea->vd.lock = &tea->mutex; 377 tea->vd.v4l2_dev = tea->v4l2_dev; 378 tea->vd.ctrl_handler = &tea->ctrl_handler; 379 set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); 380 /* disable hw_freq_seek if we can't use it */ 381 if (tea->cannot_read_data) 382 v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK); 383 384 v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); 385 v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); 386 retval = tea->ctrl_handler.error; 387 if (retval) { 388 v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); 389 v4l2_ctrl_handler_free(&tea->ctrl_handler); 390 return retval; 391 } 392 393 if (tea->ext_init) { 394 retval = tea->ext_init(tea); 395 if (retval) { 396 v4l2_ctrl_handler_free(&tea->ctrl_handler); 397 return retval; 398 } 399 } 400 401 v4l2_ctrl_handler_setup(&tea->ctrl_handler); 402 403 retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr); 404 if (retval) { 405 v4l2_err(tea->v4l2_dev, "can't register video device!\n"); 406 v4l2_ctrl_handler_free(&tea->ctrl_handler); 407 return retval; 408 } 409 410 return 0; 411} 412 413void snd_tea575x_exit(struct snd_tea575x *tea) 414{ 415 video_unregister_device(&tea->vd); 416 v4l2_ctrl_handler_free(&tea->ctrl_handler); 417} 418 419static int __init alsa_tea575x_module_init(void) 420{ 421 return 0; 422} 423 424static void __exit alsa_tea575x_module_exit(void) 425{ 426} 427 428module_init(alsa_tea575x_module_init) 429module_exit(alsa_tea575x_module_exit) 430 431EXPORT_SYMBOL(snd_tea575x_init); 432EXPORT_SYMBOL(snd_tea575x_exit); 433