radio-si4703.c
上传用户:ledjyj
上传日期:2014-08-27
资源大小:2639k
文件大小:13k
源码类别:

驱动编程

开发平台:

Unix_Linux

  1. /* SI4703 Radio Card driver for radio support
  2.  *Author: Beck.He@quantcn.com
  3.  *2007.9.1
  4.  * Card manufacturer:
  5.  * Quanta
  6.  *
  7.  /*
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License version 2 as
  10.  * published by the Free Software Foundation.
  11.  */
  12. #include <linux/module.h> /* Modules                        */
  13. #include <linux/init.h> /* Initdata                       */
  14. #include <linux/ioport.h> /* request_region   */
  15. #include <linux/proc_fs.h> /* radio card status report   */
  16. #include <asm/io.h> /* outb, outb_p                   */
  17. #include <asm/uaccess.h> /* copy to/from user              */
  18. #include <linux/videodev.h> /* kernel radio structs           */
  19. #include <linux/config.h> /* CONFIG_RADIO_SI4703_*         */
  20. #include <linux/types.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/workqueue.h>
  23. #include <asm/arch/gpio.h>
  24. #include "SI4703API.h"
  25. #define BANNER "SI4703 Radio Card driver v0.1n"
  26. #ifndef CONFIG_RADIO_SI4703_MUTEFREQ
  27. #define CONFIG_RADIO_SI4703_MUTEFREQ 0
  28. #endif
  29. #ifndef CONFIG_PROC_FS
  30. #undef CONFIG_RADIO_SI4703_PROC_FS
  31. #endif
  32. #ifndef TRUE
  33. #define TRUE 1
  34. #endif
  35. #ifndef FALSE
  36. #define FALSE 0
  37. #endif
  38. struct SI4703_device {
  39. int users;
  40. int curvol;
  41. int muted;
  42. unsigned long curfreq;
  43. unsigned long mutefreq;
  44. // struct mutex lock;
  45.     __u32 audmode;
  46.     struct RDS_DATA irq_data;
  47. spinlock_t irq_lock;
  48. wait_queue_head_t irq_queue;
  49. // wait_queue_head_t fm_wait;
  50.     struct workqueue_struct *radio_irq_workq;
  51. struct work_struct fm_event_work;
  52. struct fasync_struct *async_queue;
  53. };
  54. static struct SI4703_device SI4703_unit =
  55. {
  56. .curfreq = CONFIG_RADIO_SI4703_MUTEFREQ,
  57. .mutefreq = CONFIG_RADIO_SI4703_MUTEFREQ,
  58. };
  59. static int SI4703_ioctl(struct inode *inode, struct file *file,
  60.  unsigned int cmd, unsigned long arg);
  61. static int SI4703_Read(struct file *file, char __user *arg, size_t count, loff_t *offset);
  62. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  63. static int SI4703_get_info(char *buf, char **start, off_t offset, int len);
  64. #endif
  65. static void query_radio_ctrl(struct v4l2_queryctrl *param);
  66. static void get_radio_ctrl(struct v4l2_control *param);
  67. static void set_radio_ctrl(struct v4l2_control *param);
  68. static int  SI4703_init_irq(void);
  69. static DECLARE_WAIT_QUEUE_HEAD(fm_wait);
  70. static int SI4703_do_ioctl(struct inode *inode, struct file *file,
  71.     unsigned int cmd, void *arg)
  72. {
  73. struct video_device *dev = video_devdata(file);
  74. struct SI4703_device *SI4703 = dev->priv;
  75. switch (cmd) {
  76. case VIDIOC_QUERYCAP:
  77. {
  78. struct v4l2_capability *v = arg;
  79. memset(v,0,sizeof(*v));
  80. v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
  81. strcpy(v->driver, "SI4703");
  82. return 0;
  83. }
  84.     case VIDIOC_RADIO_ON:
  85. {
  86.             printk(KERN_ERR "radio-SI4703: ioctl radio onn");
  87.             FM_SI47XX_PowerUp();
  88. return 0;
  89. }
  90. case VIDIOC_RADIO_OFF:
  91. {
  92.             printk(KERN_ERR "radio-SI4703: ioctl radio offn");
  93.             FM_SI47XX_PowerDown();
  94. return 0;
  95. }
  96. case VIDIOC_G_TUNER:
  97. {
  98. struct v4l2_tuner *v = arg;
  99. // if (v->tuner) /* Only 1 tuner */
  100. // return -EINVAL;
  101.           printk(KERN_ERR "radio-SI4703: ioctl get tunern");
  102. v->rangelow = 875;
  103. v->rangehigh = 1080;
  104. v->type = V4L2_TUNER_RADIO;
  105. v->capability = V4L2_TUNER_CAP_STEREO;
  106. v->signal = FM_SI47XX_ReadRSSI(); /*  get the signal strength */
  107. strcpy(v->name, "SI4703");
  108. return 0;
  109. }
  110. case VIDIOC_S_TUNER:
  111. {
  112. struct v4l2_tuner *v = arg;
  113. // if (v->tuner != 0)
  114. // return -EINVAL;
  115. /* Only 1 tuner so no setting needed ! */
  116.             printk(KERN_ERR "radio-SI4703: ioctl set tunern");
  117.            SI4703->audmode = v->audmode;
  118. return 0;
  119. }
  120. case VIDIOC_G_FREQUENCY:
  121. {
  122. struct v4l2_frequency *freq = arg;
  123.         printk(KERN_ERR "radio-SI4703: ioctl get freqn");
  124. freq->frequency = SI4703->curfreq;
  125.         freq->type = V4L2_TUNER_RADIO;
  126. return 0;
  127. }
  128. case VIDIOC_S_FREQUENCY:
  129. {
  130. struct v4l2_frequency *freq = arg;
  131.          printk(KERN_ERR "radio-SI4703: ioctl set freqn");
  132. SI4703->curfreq = freq->frequency;
  133. FM_SI47XX_Tune(SI4703->curfreq);
  134. return 0;
  135. }
  136.     case VIDIOC_QUERYCTRL:
  137.     {
  138.         struct v4l2_queryctrl *v = arg;
  139.         query_radio_ctrl(v);
  140.         return 0;
  141.     }
  142.     case VIDIOC_G_CTRL:
  143.     {
  144.         struct v4l2_control * v = arg;
  145.         get_radio_ctrl(v);
  146.         return 0;
  147.     }
  148.     case VIDIOC_S_CTRL:
  149.     {
  150.         struct v4l2_control * v = arg;
  151.           printk(KERN_ERR "radio-SI4703: ioctl set ctrln");
  152.         set_radio_ctrl(v);
  153.         return 0;
  154.     }
  155.     case RADIO_SCAN_NEXT:
  156.     {
  157.         struct radio_scan *v = arg;
  158.         if(SEEKUP == v->direction) {
  159.            printk(KERN_ERR "radio-SI4703: ioctl seek upn");
  160.             FM_SI47XX_Seek(SEEKUP,&v->channel, &v->scanok);
  161.         }
  162.         if(SEEKDOWN == v->direction) {
  163.             printk(KERN_ERR "radio-SI4703: ioctl seek downn");
  164.             FM_SI47XX_Seek(SEEKDOWN, &v->channel,&v->scanok);
  165.         }
  166.        return 0;
  167.     }
  168.         
  169. default:
  170. return -ENOIOCTLCMD;
  171. }
  172. }
  173. static void query_radio_ctrl(struct v4l2_queryctrl *param)
  174. {
  175.    struct  v4l2_queryctrl *v = param;
  176.     switch (v->id) {
  177.     case V4L2_CID_AUDIO_VOLUME:
  178.     {
  179.         v->type = V4L2_CTRL_TYPE_INTEGER;
  180.         v->minimum = 0;
  181.         v->maximum = 100;
  182.         v->step =20;
  183.         return;
  184.     }
  185.     case V4L2_CID_AUDIO_MUTE:
  186.     {
  187.        v->type = V4L2_CTRL_TYPE_BOOLEAN;
  188.        return;
  189.     }
  190.     default:
  191.     {
  192.         v->flags = V4L2_CTRL_FLAG_DISABLED;
  193.         return;
  194.     }
  195.     }
  196. }
  197. static void get_radio_ctrl(struct v4l2_control *param)
  198. {
  199.    struct v4l2_control *v = param;
  200.     switch (v->id) {
  201.     case V4L2_CID_AUDIO_VOLUME:
  202.     {
  203.         v->value = SI4703_unit.curvol;
  204.         return;
  205.    
  206.     }
  207.     case V4L2_CID_AUDIO_MUTE:
  208.     {
  209.        v->value = SI4703_unit.muted ;
  210.        return;
  211.     }
  212.     default:
  213.     {
  214.         v->value = -1;
  215.         return;
  216.     }
  217.     }
  218. }
  219. static void set_radio_ctrl(struct v4l2_control *param)
  220. {
  221.     struct v4l2_control *v = param;
  222.     switch (v->id) {
  223.     case V4L2_CID_AUDIO_VOLUME:
  224.     {
  225.      FM_SI47XX_Volume(v->value);
  226.      SI4703_unit.curvol = v->value;
  227.      return;
  228.     }
  229.     case V4L2_CID_AUDIO_MUTE:
  230.     {
  231.         if (1 == v->value) {
  232.             FM_SI47XX_MuteVolume();
  233.             SI4703_unit.muted =1;
  234.         }
  235.         else {
  236.             FM_SI47XX_DMuteVolume();
  237.             SI4703_unit.muted =0;
  238.         }
  239.             
  240.       return;
  241.     }
  242.     default:
  243.     {
  244.         printk(KERN_ERR "radio-SI4703: error controln");
  245.         return;
  246.     }
  247.        
  248.     }
  249. }
  250. static int SI4703_ioctl(struct inode *inode, struct file *file,
  251.  unsigned int cmd, unsigned long arg)
  252. {
  253.     printk(KERN_ERR "radio-SI4703: enter ioctln");
  254.     return video_usercopy(inode, file, cmd, arg, SI4703_do_ioctl);
  255. }
  256. static irqreturn_t si4703_radio_interrupt(int irq, void *dev_id,
  257. struct pt_regs *regs)
  258. {
  259.     int i;
  260.     char buf[24];
  261.     struct SI4703_device *radio = &SI4703_unit;
  262.      printk(KERN_ERR "radio-SI4703: interruptn");
  263.          //beck test
  264.     SI4703_I2C_Read( buf,  24);
  265.     for(i=0;i<24;i++)
  266.    printk("I2C: SI4703 register contents=%xn", buf[i]);
  267.   wake_up_interruptible(&fm_wait);
  268.     
  269. if (ReadRDSR() ==1) {
  270.    
  271.     //spin_lock(&radio->irq_lock)
  272.     //radio->irq_data.RDSA = ReadRDS_BLOCK(RDSA);
  273.    // radio->irq_data.RDSB = ReadRDS_BLOCK(RDSB);
  274.    // radio->irq_data.RDSC = ReadRDS_BLOCK(RDSC);
  275.    // radio->irq_data.RDSD= ReadRDS_BLOCK(RDSD);
  276.    // radio->irq_data.RDSA = 100;
  277.    //spin_unlock(&radio->irq_lock);
  278.     disable_irq(IRQ_GPIO(MFP2GPIO(MFP_PIN_GPIO122)));
  279. queue_work(radio->radio_irq_workq, &radio->fm_event_work);
  280. }
  281. return IRQ_HANDLED;
  282. }
  283. static int SI4703_Read(struct file *file, char __user *arg, size_t count, loff_t *offset)
  284. {
  285.     struct SI4703_device *radio = &SI4703_unit;
  286.     DECLARE_WAITQUEUE(wait, current);
  287. struct RDS_DATA data;
  288. ssize_t ret;
  289. //if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
  290. //return -EINVAL;
  291. add_wait_queue(&radio->irq_queue, &wait);
  292. do {
  293. __set_current_state(TASK_INTERRUPTIBLE);
  294. spin_lock_irq(&radio->irq_lock);
  295. data = radio->irq_data;
  296. radio->irq_data.RDSA = 0;
  297. spin_unlock_irq(&radio->irq_lock);
  298. if (data.RDSA != 0) {
  299. ret = 0;
  300. break;
  301. }
  302. if (file->f_flags & O_NONBLOCK) {
  303. ret = -EAGAIN;
  304. break;
  305. }
  306. if (signal_pending(current)) {
  307. ret = -ERESTARTSYS;
  308. break;
  309. }
  310. schedule();
  311. } while (1);
  312. set_current_state(TASK_RUNNING);
  313. remove_wait_queue(&radio->irq_queue, &wait);
  314. /*if (ret == 0) {
  315. if (radio->read_callback)
  316. data = radio->read_callback(rtc->class_dev.dev,
  317.        data);}*/
  318.          
  319.     return  copy_to_user(arg,&data,sizeof(data))? -EFAULT : sizeof(data);
  320.  } 
  321. static unsigned int SI4703_dev_poll(struct file *file, poll_table *wait)
  322. {
  323.  struct SI4703_device *radio = &SI4703_unit;
  324.  struct RDS_DATA data;
  325. poll_wait(file, &radio->irq_queue, wait);
  326. data = radio->irq_data;
  327. return (data.RDSA != 0) ? (POLLIN | POLLRDNORM) : 0;
  328. }
  329. static int SI4703_dev_fasync(int fd, struct file *file, int on)
  330. {
  331. struct SI4703_device *radio = &SI4703_unit;
  332. return fasync_helper(fd, file, on, &radio->async_queue);
  333. }
  334. static void radio_fm_irq_worker(void *ptr) 
  335. {
  336. //spin_lock(&radio->irq_lock);
  337.     struct SI4703_device *radio = ptr;
  338. radio->irq_data.RDSA = ReadRDS_BLOCK(RDSA);
  339.     radio->irq_data.RDSB = ReadRDS_BLOCK(RDSB);
  340.     radio->irq_data.RDSC = ReadRDS_BLOCK(RDSC);
  341.     radio->irq_data.RDSD= ReadRDS_BLOCK(RDSD);
  342.     radio->irq_data.RDSA = 100;
  343.   //printk(KERN_ERR "RDSA=%d,RDSB=%d,RDSC=%d,RDSD=%d,RSSI=%dn",
  344.          //radio->irq_data.RDSA ,radio->irq_data.RDSB ,radio->irq_data.RDSC ,radio->irq_data.RDSD,FM_SI47XX_ReadRSSI);
  345.     wake_up_interruptible(&radio->irq_queue);
  346. kill_fasync(&radio->async_queue, SIGIO, POLL_IN);
  347.     enable_irq(IRQ_GPIO(MFP2GPIO(MFP_PIN_GPIO122)));
  348. //spin_unlock(&radio->irq_lock);
  349. }
  350. static int SI4703_init_irq(void)
  351. {
  352.     struct SI4703_device *radio = &SI4703_unit;
  353.    INIT_WORK(&radio->fm_event_work, radio_fm_irq_worker, radio);
  354. if ((radio->radio_irq_workq = 
  355. create_singlethread_workqueue("si4703radio")) == NULL) {
  356. printk(KERN_ERR"could not create radio irq work queuen"); 
  357. return -EINVAL; 
  358. }
  359.     if(request_irq (IRQ_GPIO(MFP2GPIO(MFP_PIN_GPIO122)), si4703_radio_interrupt, SA_INTERRUPT, "si4703_radio", NULL))
  360.     {
  361.         printk(KERN_ERR "radio-SI4703: error request irqn");
  362.         destroy_workqueue(radio->radio_irq_workq);
  363.         free_irq(IRQ_GPIO(MFP2GPIO(MFP_PIN_GPIO122)),NULL);
  364.         return -EINVAL; 
  365.     }
  366. return 0; 
  367. }
  368. static struct file_operations SI4703_fops = {
  369. .owner = THIS_MODULE,
  370. .open           = video_exclusive_open,
  371.     .read           = SI4703_Read,
  372. .release        = video_exclusive_release,
  373. .ioctl = SI4703_ioctl,
  374.     .poll       = SI4703_dev_poll,
  375.     .fasync = SI4703_dev_fasync,
  376. //.compat_ioctl = v4l_compat_ioctl32,
  377. .llseek         = no_llseek,
  378. };
  379. static struct video_device SI4703_radio =
  380. {
  381. .owner = THIS_MODULE,
  382. .name = "SI4703 Radio",
  383. .type = VID_TYPE_TUNER,
  384. .hardware = VID_HARDWARE_SI4703,
  385. .fops           = &SI4703_fops,
  386. };
  387. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  388. static int SI4703_get_info(char *buf, char **start, off_t offset, int len)
  389. {
  390. char *out = buf;
  391. #ifdef MODULE
  392.     #define MODULEPROCSTRING "Driver loaded as a module"
  393. #else
  394.     #define MODULEPROCSTRING "Driver compiled into kernel"
  395. #endif
  396. /* output must be kept under PAGE_SIZE */
  397. out += sprintf(out, BANNER);
  398. out += sprintf(out, "Load type: " MODULEPROCSTRING "nn");
  399. out += sprintf(out, "frequency = %lu kHzn",
  400. SI4703_unit.curfreq >> 4);
  401. out += sprintf(out, "volume = %dn", SI4703_unit.curvol);
  402. out += sprintf(out, "mute = %sn", SI4703_unit.muted ?
  403. "on" : "off");
  404. out += sprintf(out, "mute frequency = %lu kHzn",
  405. SI4703_unit.mutefreq >> 4);
  406. return out - buf;
  407. }
  408. #endif /* CONFIG_RADIO_SI4703_PROC_FS */
  409. MODULE_AUTHOR("Beck He");
  410. MODULE_DESCRIPTION("A driver for the SI4703 radio card .");
  411. MODULE_LICENSE("GPL");
  412. static int radio_nr = -1;
  413. module_param(radio_nr, int, 0);
  414. #ifdef MODULE
  415. static unsigned long mutefreq = 0;
  416. module_param(mutefreq, ulong, 0);
  417. MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
  418. #endif
  419. void si4703_fm_wait_timeout()
  420. {
  421.      wait_event_timeout(fm_wait, ReadSTC() ==1, msecs_to_jiffies(4000));
  422. }
  423. static int __init SI4703_init(void)
  424. {
  425.      struct SI4703_device *radio = &SI4703_unit;
  426. #ifdef MODULE
  427. if (mutefreq < 87000 || mutefreq > 108500) {
  428. printk(KERN_ERR "radio-SI4703: You must set a frequency (in kHz) used when muting the card,n");
  429. printk(KERN_ERR "radio-SI4703: e.g. with "mutefreq=87500" (87000 <= mutefreq <= 108500)n");
  430. return -EINVAL;
  431. }
  432. SI4703_unit.mutefreq = mutefreq;
  433. #endif /* MODULE */
  434. printk(KERN_INFO BANNER);
  435. // mutex_init(&radio->lock);
  436.     spin_lock_init(&radio->irq_lock);
  437.     init_waitqueue_head(&radio->irq_queue);
  438.     SI4703_radio.priv = &SI4703_unit;
  439. if (video_register_device(&SI4703_radio, VFL_TYPE_RADIO, radio_nr) == -1)
  440. {
  441. return -EINVAL;
  442. }
  443.     FM_SI47XX_Init();
  444.     SI4703_init_irq();
  445. //printk(KERN_INFO "radio-SI4703: mute frequency is %lu kHz.n",
  446. //       SI4703_unit.mutefreq);
  447. //SI4703_unit.mutefreq <<= 4;
  448. /* mute card - prevents noisy bootups */
  449. // SI4703_mute(&SI4703_unit);
  450. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  451. if (!create_proc_info_entry("driver/radio-SI4703", 0, NULL,
  452.     SI4703_get_info)) 
  453.      printk(KERN_ERR "radio-SI4703: registering /proc/driver/radio-SI4703 failedn");
  454. #endif
  455. return 0;
  456. }
  457. static void __exit SI4703_cleanup_module(void)
  458. {
  459. #ifdef CONFIG_RADIO_SI4703_PROC_FS
  460. remove_proc_entry("driver/radio-SI4703", NULL);
  461. #endif
  462.     free_irq(IRQ_GPIO(MFP2GPIO(MFP_PIN_GPIO122)),NULL);
  463. video_unregister_device(&SI4703_radio);
  464. }
  465. module_init(SI4703_init);
  466. module_exit(SI4703_cleanup_module);
  467. EXPORT_SYMBOL(si4703_fm_wait_timeout);