1 /* 2 * driver/media/radio/radio-tea5764.c 3 * 4 * Driver for TEA5764 radio chip for linux 2.6. 5 * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola. 6 * The I2C protocol is used for communicate with chip. 7 * 8 * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation 9 * 10 * Copyright (c) 2008 Fabio Belavenuto <belavenuto@gmail.com> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 * 26 * History: 27 * 2008-12-06 Fabio Belavenuto <belavenuto@gmail.com> 28 * initial code 29 * 30 * TODO: 31 * add platform_data support for IRQs platform dependencies 32 * add RDS support 33 */ 34 #include <linux/kernel.h> 35 #include <linux/slab.h> 36 #include <linux/module.h> 37 #include <linux/init.h> /* Initdata */ 38 #include <linux/videodev2.h> /* kernel radio structs */ 39 #include <linux/i2c.h> /* I2C */ 40 #include <media/v4l2-common.h> 41 #include <media/v4l2-ioctl.h> 42 43 #define DRIVER_VERSION "0.0.2" 44 45 #define DRIVER_AUTHOR "Fabio Belavenuto <belavenuto@gmail.com>" 46 #define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones." 47 48 #define PINFO(format, ...)\ 49 printk(KERN_INFO KBUILD_MODNAME ": "\ 50 DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) 51 #define PWARN(format, ...)\ 52 printk(KERN_WARNING KBUILD_MODNAME ": "\ 53 DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) 54 # define PDEBUG(format, ...)\ 55 printk(KERN_DEBUG KBUILD_MODNAME ": "\ 56 DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) 57 58 /* Frequency limits in MHz -- these are European values. For Japanese 59 devices, that would be 76000 and 91000. */ 60 #define FREQ_MIN 87500 61 #define FREQ_MAX 108000 62 #define FREQ_MUL 16 63 64 /* TEA5764 registers */ 65 #define TEA5764_MANID 0x002b 66 #define TEA5764_CHIPID 0x5764 67 68 #define TEA5764_INTREG_BLMSK 0x0001 69 #define TEA5764_INTREG_FRRMSK 0x0002 70 #define TEA5764_INTREG_LEVMSK 0x0008 71 #define TEA5764_INTREG_IFMSK 0x0010 72 #define TEA5764_INTREG_BLMFLAG 0x0100 73 #define TEA5764_INTREG_FRRFLAG 0x0200 74 #define TEA5764_INTREG_LEVFLAG 0x0800 75 #define TEA5764_INTREG_IFFLAG 0x1000 76 77 #define TEA5764_FRQSET_SUD 0x8000 78 #define TEA5764_FRQSET_SM 0x4000 79 80 #define TEA5764_TNCTRL_PUPD1 0x8000 81 #define TEA5764_TNCTRL_PUPD0 0x4000 82 #define TEA5764_TNCTRL_BLIM 0x2000 83 #define TEA5764_TNCTRL_SWPM 0x1000 84 #define TEA5764_TNCTRL_IFCTC 0x0800 85 #define TEA5764_TNCTRL_AFM 0x0400 86 #define TEA5764_TNCTRL_SMUTE 0x0200 87 #define TEA5764_TNCTRL_SNC 0x0100 88 #define TEA5764_TNCTRL_MU 0x0080 89 #define TEA5764_TNCTRL_SSL1 0x0040 90 #define TEA5764_TNCTRL_SSL0 0x0020 91 #define TEA5764_TNCTRL_HLSI 0x0010 92 #define TEA5764_TNCTRL_MST 0x0008 93 #define TEA5764_TNCTRL_SWP 0x0004 94 #define TEA5764_TNCTRL_DTC 0x0002 95 #define TEA5764_TNCTRL_AHLSI 0x0001 96 97 #define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4) 98 #define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9) 99 #define TEA5764_TUNCHK_TUNTO 0x0100 100 #define TEA5764_TUNCHK_LD 0x0008 101 #define TEA5764_TUNCHK_STEREO 0x0004 102 103 #define TEA5764_TESTREG_TRIGFR 0x0800 104 105 struct tea5764_regs { 106 u16 intreg; /* INTFLAG & INTMSK */ 107 u16 frqset; /* FRQSETMSB & FRQSETLSB */ 108 u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ 109 u16 frqchk; /* FRQCHKMSB & FRQCHKLSB */ 110 u16 tunchk; /* IFCHK & LEVCHK */ 111 u16 testreg; /* TESTBITS & TESTMODE */ 112 u16 rdsstat; /* RDSSTAT1 & RDSSTAT2 */ 113 u16 rdslb; /* RDSLBMSB & RDSLBLSB */ 114 u16 rdspb; /* RDSPBMSB & RDSPBLSB */ 115 u16 rdsbc; /* RDSBBC & RDSGBC */ 116 u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ 117 u16 rdsbbl; /* PAUSEDET & RDSBBL */ 118 u16 manid; /* MANID1 & MANID2 */ 119 u16 chipid; /* CHIPID1 & CHIPID2 */ 120 } __attribute__ ((packed)); 121 122 struct tea5764_write_regs { 123 u8 intreg; /* INTMSK */ 124 u16 frqset; /* FRQSETMSB & FRQSETLSB */ 125 u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ 126 u16 testreg; /* TESTBITS & TESTMODE */ 127 u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ 128 u16 rdsbbl; /* PAUSEDET & RDSBBL */ 129 } __attribute__ ((packed)); 130 131 #ifdef CONFIG_RADIO_TEA5764_XTAL 132 #define RADIO_TEA5764_XTAL 1 133 #else 134 #define RADIO_TEA5764_XTAL 0 135 #endif 136 137 static int radio_nr = -1; 138 static int use_xtal = RADIO_TEA5764_XTAL; 139 140 struct tea5764_device { 141 struct i2c_client *i2c_client; 142 struct video_device *videodev; 143 struct tea5764_regs regs; 144 struct mutex mutex; 145 }; 146 147 /* I2C code related */ 148 static int tea5764_i2c_read(struct tea5764_device *radio) 149 { 150 int i; 151 u16 *p = (u16 *) &radio->regs; 152 153 struct i2c_msg msgs[1] = { 154 { .addr = radio->i2c_client->addr, 155 .flags = I2C_M_RD, 156 .len = sizeof(radio->regs), 157 .buf = (void *)&radio->regs 158 }, 159 }; 160 if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) 161 return -EIO; 162 for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++) 163 p[i] = __be16_to_cpu(p[i]); 164 165 return 0; 166 } 167 168 static int tea5764_i2c_write(struct tea5764_device *radio) 169 { 170 struct tea5764_write_regs wr; 171 struct tea5764_regs *r = &radio->regs; 172 struct i2c_msg msgs[1] = { 173 { 174 .addr = radio->i2c_client->addr, 175 .len = sizeof(wr), 176 .buf = (void *)&wr 177 }, 178 }; 179 wr.intreg = r->intreg & 0xff; 180 wr.frqset = __cpu_to_be16(r->frqset); 181 wr.tnctrl = __cpu_to_be16(r->tnctrl); 182 wr.testreg = __cpu_to_be16(r->testreg); 183 wr.rdsctrl = __cpu_to_be16(r->rdsctrl); 184 wr.rdsbbl = __cpu_to_be16(r->rdsbbl); 185 if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) 186 return -EIO; 187 return 0; 188 } 189 190 /* V4L2 code related */ 191 static struct v4l2_queryctrl radio_qctrl[] = { 192 { 193 .id = V4L2_CID_AUDIO_MUTE, 194 .name = "Mute", 195 .minimum = 0, 196 .maximum = 1, 197 .default_value = 1, 198 .type = V4L2_CTRL_TYPE_BOOLEAN, 199 } 200 }; 201 202 static void tea5764_power_up(struct tea5764_device *radio) 203 { 204 struct tea5764_regs *r = &radio->regs; 205 206 if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) { 207 r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU | 208 TEA5764_TNCTRL_HLSI); 209 if (!use_xtal) 210 r->testreg |= TEA5764_TESTREG_TRIGFR; 211 else 212 r->testreg &= ~TEA5764_TESTREG_TRIGFR; 213 214 r->tnctrl |= TEA5764_TNCTRL_PUPD0; 215 tea5764_i2c_write(radio); 216 } 217 } 218 219 static void tea5764_power_down(struct tea5764_device *radio) 220 { 221 struct tea5764_regs *r = &radio->regs; 222 223 if (r->tnctrl & TEA5764_TNCTRL_PUPD0) { 224 r->tnctrl &= ~TEA5764_TNCTRL_PUPD0; 225 tea5764_i2c_write(radio); 226 } 227 } 228 229 static void tea5764_set_freq(struct tea5764_device *radio, int freq) 230 { 231 struct tea5764_regs *r = &radio->regs; 232 233 /* formula: (freq [+ or -] 225000) / 8192 */ 234 if (r->tnctrl & TEA5764_TNCTRL_HLSI) 235 r->frqset = (freq + 225000) / 8192; 236 else 237 r->frqset = (freq - 225000) / 8192; 238 } 239 240 static int tea5764_get_freq(struct tea5764_device *radio) 241 { 242 struct tea5764_regs *r = &radio->regs; 243 244 if (r->tnctrl & TEA5764_TNCTRL_HLSI) 245 return (r->frqchk * 8192) - 225000; 246 else 247 return (r->frqchk * 8192) + 225000; 248 } 249 250 /* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 251 static void tea5764_tune(struct tea5764_device *radio, int freq) 252 { 253 tea5764_set_freq(radio, freq); 254 if (tea5764_i2c_write(radio)) 255 PWARN("Could not set frequency!"); 256 } 257 258 static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode) 259 { 260 struct tea5764_regs *r = &radio->regs; 261 int tnctrl = r->tnctrl; 262 263 if (audmode == V4L2_TUNER_MODE_MONO) 264 r->tnctrl |= TEA5764_TNCTRL_MST; 265 else 266 r->tnctrl &= ~TEA5764_TNCTRL_MST; 267 if (tnctrl != r->tnctrl) 268 tea5764_i2c_write(radio); 269 } 270 271 static int tea5764_get_audout_mode(struct tea5764_device *radio) 272 { 273 struct tea5764_regs *r = &radio->regs; 274 275 if (r->tnctrl & TEA5764_TNCTRL_MST) 276 return V4L2_TUNER_MODE_MONO; 277 else 278 return V4L2_TUNER_MODE_STEREO; 279 } 280 281 static void tea5764_mute(struct tea5764_device *radio, int on) 282 { 283 struct tea5764_regs *r = &radio->regs; 284 int tnctrl = r->tnctrl; 285 286 if (on) 287 r->tnctrl |= TEA5764_TNCTRL_MU; 288 else 289 r->tnctrl &= ~TEA5764_TNCTRL_MU; 290 if (tnctrl != r->tnctrl) 291 tea5764_i2c_write(radio); 292 } 293 294 static int tea5764_is_muted(struct tea5764_device *radio) 295 { 296 return radio->regs.tnctrl & TEA5764_TNCTRL_MU; 297 } 298 299 /* V4L2 vidioc */ 300 static int vidioc_querycap(struct file *file, void *priv, 301 struct v4l2_capability *v) 302 { 303 struct tea5764_device *radio = video_drvdata(file); 304 struct video_device *dev = radio->videodev; 305 306 strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver)); 307 strlcpy(v->card, dev->name, sizeof(v->card)); 308 snprintf(v->bus_info, sizeof(v->bus_info), 309 "I2C:%s", dev_name(&dev->dev)); 310 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; 311 return 0; 312 } 313 314 static int vidioc_g_tuner(struct file *file, void *priv, 315 struct v4l2_tuner *v) 316 { 317 struct tea5764_device *radio = video_drvdata(file); 318 struct tea5764_regs *r = &radio->regs; 319 320 if (v->index > 0) 321 return -EINVAL; 322 323 memset(v, 0, sizeof(*v)); 324 strcpy(v->name, "FM"); 325 v->type = V4L2_TUNER_RADIO; 326 tea5764_i2c_read(radio); 327 v->rangelow = FREQ_MIN * FREQ_MUL; 328 v->rangehigh = FREQ_MAX * FREQ_MUL; 329 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; 330 if (r->tunchk & TEA5764_TUNCHK_STEREO) 331 v->rxsubchans = V4L2_TUNER_SUB_STEREO; 332 else 333 v->rxsubchans = V4L2_TUNER_SUB_MONO; 334 v->audmode = tea5764_get_audout_mode(radio); 335 v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf; 336 v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk); 337 338 return 0; 339 } 340 341 static int vidioc_s_tuner(struct file *file, void *priv, 342 struct v4l2_tuner *v) 343 { 344 struct tea5764_device *radio = video_drvdata(file); 345 346 if (v->index > 0) 347 return -EINVAL; 348 349 tea5764_set_audout_mode(radio, v->audmode); 350 return 0; 351 } 352 353 static int vidioc_s_frequency(struct file *file, void *priv, 354 struct v4l2_frequency *f) 355 { 356 struct tea5764_device *radio = video_drvdata(file); 357 358 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) 359 return -EINVAL; 360 if (f->frequency == 0) { 361 /* We special case this as a power down control. */ 362 tea5764_power_down(radio); 363 } 364 if (f->frequency < (FREQ_MIN * FREQ_MUL)) 365 return -EINVAL; 366 if (f->frequency > (FREQ_MAX * FREQ_MUL)) 367 return -EINVAL; 368 tea5764_power_up(radio); 369 tea5764_tune(radio, (f->frequency * 125) / 2); 370 return 0; 371 } 372 373 static int vidioc_g_frequency(struct file *file, void *priv, 374 struct v4l2_frequency *f) 375 { 376 struct tea5764_device *radio = video_drvdata(file); 377 struct tea5764_regs *r = &radio->regs; 378 379 if (f->tuner != 0) 380 return -EINVAL; 381 tea5764_i2c_read(radio); 382 memset(f, 0, sizeof(*f)); 383 f->type = V4L2_TUNER_RADIO; 384 if (r->tnctrl & TEA5764_TNCTRL_PUPD0) 385 f->frequency = (tea5764_get_freq(radio) * 2) / 125; 386 else 387 f->frequency = 0; 388 389 return 0; 390 } 391 392 static int vidioc_queryctrl(struct file *file, void *priv, 393 struct v4l2_queryctrl *qc) 394 { 395 int i; 396 397 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 398 if (qc->id && qc->id == radio_qctrl[i].id) { 399 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); 400 return 0; 401 } 402 } 403 return -EINVAL; 404 } 405 406 static int vidioc_g_ctrl(struct file *file, void *priv, 407 struct v4l2_control *ctrl) 408 { 409 struct tea5764_device *radio = video_drvdata(file); 410 411 switch (ctrl->id) { 412 case V4L2_CID_AUDIO_MUTE: 413 tea5764_i2c_read(radio); 414 ctrl->value = tea5764_is_muted(radio) ? 1 : 0; 415 return 0; 416 } 417 return -EINVAL; 418 } 419 420 static int vidioc_s_ctrl(struct file *file, void *priv, 421 struct v4l2_control *ctrl) 422 { 423 struct tea5764_device *radio = video_drvdata(file); 424 425 switch (ctrl->id) { 426 case V4L2_CID_AUDIO_MUTE: 427 tea5764_mute(radio, ctrl->value); 428 return 0; 429 } 430 return -EINVAL; 431 } 432 433 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 434 { 435 *i = 0; 436 return 0; 437 } 438 439 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 440 { 441 if (i != 0) 442 return -EINVAL; 443 return 0; 444 } 445 446 static int vidioc_g_audio(struct file *file, void *priv, 447 struct v4l2_audio *a) 448 { 449 if (a->index > 1) 450 return -EINVAL; 451 452 strcpy(a->name, "Radio"); 453 a->capability = V4L2_AUDCAP_STEREO; 454 return 0; 455 } 456 457 static int vidioc_s_audio(struct file *file, void *priv, 458 const struct v4l2_audio *a) 459 { 460 if (a->index != 0) 461 return -EINVAL; 462 463 return 0; 464 } 465 466 /* File system interface */ 467 static const struct v4l2_file_operations tea5764_fops = { 468 .owner = THIS_MODULE, 469 .unlocked_ioctl = video_ioctl2, 470 }; 471 472 static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { 473 .vidioc_querycap = vidioc_querycap, 474 .vidioc_g_tuner = vidioc_g_tuner, 475 .vidioc_s_tuner = vidioc_s_tuner, 476 .vidioc_g_audio = vidioc_g_audio, 477 .vidioc_s_audio = vidioc_s_audio, 478 .vidioc_g_input = vidioc_g_input, 479 .vidioc_s_input = vidioc_s_input, 480 .vidioc_g_frequency = vidioc_g_frequency, 481 .vidioc_s_frequency = vidioc_s_frequency, 482 .vidioc_queryctrl = vidioc_queryctrl, 483 .vidioc_g_ctrl = vidioc_g_ctrl, 484 .vidioc_s_ctrl = vidioc_s_ctrl, 485 }; 486 487 /* V4L2 interface */ 488 static struct video_device tea5764_radio_template = { 489 .name = "TEA5764 FM-Radio", 490 .fops = &tea5764_fops, 491 .ioctl_ops = &tea5764_ioctl_ops, 492 .release = video_device_release, 493 }; 494 495 /* I2C probe: check if the device exists and register with v4l if it is */ 496 static int __devinit tea5764_i2c_probe(struct i2c_client *client, 497 const struct i2c_device_id *id) 498 { 499 struct tea5764_device *radio; 500 struct tea5764_regs *r; 501 int ret; 502 503 PDEBUG("probe"); 504 radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL); 505 if (!radio) 506 return -ENOMEM; 507 508 mutex_init(&radio->mutex); 509 radio->i2c_client = client; 510 ret = tea5764_i2c_read(radio); 511 if (ret) 512 goto errfr; 513 r = &radio->regs; 514 PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid); 515 if (r->chipid != TEA5764_CHIPID || 516 (r->manid & 0x0fff) != TEA5764_MANID) { 517 PWARN("This chip is not a TEA5764!"); 518 ret = -EINVAL; 519 goto errfr; 520 } 521 522 radio->videodev = video_device_alloc(); 523 if (!(radio->videodev)) { 524 ret = -ENOMEM; 525 goto errfr; 526 } 527 memcpy(radio->videodev, &tea5764_radio_template, 528 sizeof(tea5764_radio_template)); 529 530 i2c_set_clientdata(client, radio); 531 video_set_drvdata(radio->videodev, radio); 532 radio->videodev->lock = &radio->mutex; 533 534 /* initialize and power off the chip */ 535 tea5764_i2c_read(radio); 536 tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO); 537 tea5764_mute(radio, 1); 538 tea5764_power_down(radio); 539 540 ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); 541 if (ret < 0) { 542 PWARN("Could not register video device!"); 543 goto errrel; 544 } 545 546 PINFO("registered."); 547 return 0; 548 errrel: 549 video_device_release(radio->videodev); 550 errfr: 551 kfree(radio); 552 return ret; 553 } 554 555 static int __devexit tea5764_i2c_remove(struct i2c_client *client) 556 { 557 struct tea5764_device *radio = i2c_get_clientdata(client); 558 559 PDEBUG("remove"); 560 if (radio) { 561 tea5764_power_down(radio); 562 video_unregister_device(radio->videodev); 563 kfree(radio); 564 } 565 return 0; 566 } 567 568 /* I2C subsystem interface */ 569 static const struct i2c_device_id tea5764_id[] = { 570 { "radio-tea5764", 0 }, 571 { } /* Terminating entry */ 572 }; 573 MODULE_DEVICE_TABLE(i2c, tea5764_id); 574 575 static struct i2c_driver tea5764_i2c_driver = { 576 .driver = { 577 .name = "radio-tea5764", 578 .owner = THIS_MODULE, 579 }, 580 .probe = tea5764_i2c_probe, 581 .remove = __devexit_p(tea5764_i2c_remove), 582 .id_table = tea5764_id, 583 }; 584 585 module_i2c_driver(tea5764_i2c_driver); 586 587 MODULE_AUTHOR(DRIVER_AUTHOR); 588 MODULE_DESCRIPTION(DRIVER_DESC); 589 MODULE_LICENSE("GPL"); 590 MODULE_VERSION(DRIVER_VERSION); 591 592 module_param(use_xtal, int, 0); 593 MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); 594 module_param(radio_nr, int, 0); 595 MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); 596