1. /*
  2. * driver/char/at91_adc.c
  3. *
  4. * Copyright (C) 2007 Embedall Technology Co., Ltd.
  5. *
  6. * Analog-to-digital Converter(ADC) Driver.
  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 as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/types.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/version.h>
  18. #include <linux/spinlock.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/cdev.h>
  22. #include <linux/fs.h>
  23. #include <linux/ioctl.h>
  24. #include <linux/poll.h>
  25. #include <linux/at91_adc.h>
  26. #include <asm/arch/hardware.h>
  27. #include <asm/arch/gpio.h>
  28. #include <asm/arch/at91_adc.h>
  29. #include <asm/arch/at91_tc.h>
  30. #include <asm/arch/at91_pmc.h>
  31. #define DRV_NAME "at91_adc"
  32. #define DEV_NAME "adc0"
  33. #define adc_readl(adc,reg)     (__raw_readl((adc)->membase + (reg)))
  34. #define adc_writel(adc,reg,v)  (__raw_writel((v), (adc)->membase + (reg)))
  35. #define tc_readl(adc,reg)      (__raw_readl((adc)->tcxbase + (reg)))
  36. #define tc_writel(adc,reg,v)   (__raw_writel((v), (adc)->tcxbase + (reg)))
  37. #define ADC_MAX_CHANNEL CONFIG_AT91_ADC_CHANNELS
  38. #define BUF_SIZE        8
  39. //#define buf_cnt(channel) (((channel)->head - (channel)->tail) & ((BUF_SIZE)-1))
  40. //#define buf_space(channel) (((channel)->tail-((channel)->head+1))&(BUF_SIZE-1))
  41. struct adc;
  42. static int minor_num = 0;
  43. static int major_num = 0;
  44. struct adc_channel
  45. {
  46. struct cdev         cdev;
  47. struct device       *dev;
  48. struct class_device *class_dev;
  49. int id;
  50. int adc_data;
  51. int head;
  52. int tail;
  53. struct fasync_struct *fasync;
  54. struct adc *adc;
  55. };
  56. struct adc
  57. {
  58. dev_t           devt;
  59. struct class    *class;
  60. void __iomem    *membase;
  61. void __iomem    *tcbbase;
  62. void __iomem    *tcxbase;
  63. unsigned int    irq;
  64. struct adc_mode mode;
  65. spinlock_t      lock;
  66. struct adc_channel *channel[ADC_MAX_CHANNEL];
  67. };
  68. static struct adc *adc;
  69. static inline int buf_in(struct adc_channel *channel, int v)
  70. {
  71. channel->adc_data = v;
  72. //channel->head = (channel->head + 1) & (BUF_SIZE - 1);
  73. return channel->adc_data;
  74. }
  75. static int adc_init_tc(struct adc *adc)
  76. {
  77. unsigned int dummy = 0;
  78. spin_lock(&adc->lock);
  79. if (adc->mode.trigger != ADC_TRIGGER_TIMER) {
  80. at91_sys_write(AT91_PMC_PCDR, 1 << AT91SAM9260_ID_TC2);
  81. spin_unlock(&adc->lock);
  82. return 0;
  83. }
  84. tc_writel(adc, AT91_TC_CCR, AT91_TC_CLKDIS);
  85. dummy |= (AT91_TC_TIMER_CLOCK5 | AT91_TC_CPCTRG | AT91_TC_WAVE |
  86. AT91_TC_WAVESEL_UP_AUTO | AT91_TC_ACPA_SET |
  87. AT91_TC_ACPC_CLEAR );
  88. tc_writel(adc, AT91_TC_CMR, dummy);
  89. if (adc->mode.trigger_time) {
  90. dummy = (adc->mode.trigger_time*1000000)/(1000000000/32768);
  91. if (dummy > 0xffff) dummy = 0xffff;
  92. tc_writel(adc, AT91_TC_RC, dummy);
  93. tc_writel(adc, AT91_TC_RA, dummy * 3 / 5);
  94. } else {
  95. tc_writel(adc, AT91_TC_RC, 32768);
  96. tc_writel(adc, AT91_TC_RA, 32768 * 3 / 5);
  97. }
  98. at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_TC2);
  99. tc_writel(adc, AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
  100. spin_unlock(&adc->lock);
  101. return 0;
  102. }
  103. static int adc_hw_init(struct adc *adc)
  104. {
  105. adc_writel(adc, AT91_ADC_CR,  AT91_ADC_SWRST);
  106. adc_writel(adc, AT91_ADC_IER, AT91_ADC_DRDY);
  107. at91_sys_write(AT91_PMC_PCER, 1 << adc->irq);
  108. return 0;
  109. }
  110. static int adc_fasync(int fd, struct file *file, int mode)
  111. {
  112. struct adc_channel *channel = file->private_data;
  113. return fasync_helper(fd, file, mode, &channel->fasync);
  114. }
  115. static int adc_open(struct inode *inode, struct file *file)
  116. {
  117. struct adc *adc;
  118. struct adc_channel *channel;
  119. channel = container_of(inode->i_cdev, struct adc_channel, cdev);
  120. file->private_data = channel;
  121. adc = channel->adc;
  122. spin_lock(&adc->lock);
  123. at91_set_multi_drive(PIN_BASE + 0x40 + channel->id, 1);
  124. adc_writel(adc, AT91_ADC_IER,  (1 << channel->id));
  125. adc_writel(adc, AT91_ADC_CHER, (1 << channel->id));
  126. spin_unlock(&adc->lock);
  127. return nonseekable_open(inode, file);
  128. }
  129. static int adc_release(struct inode *inode, struct file *file)
  130. {
  131. struct adc *adc;
  132. struct adc_channel *channel;
  133. channel = container_of(inode->i_cdev, struct adc_channel, cdev);
  134. adc = channel->adc;
  135. //  adc_fasync(-1, file, 0);
  136. spin_lock(&adc->lock);
  137. adc_writel(adc, AT91_ADC_IDR,  1 << channel->id);
  138. adc_writel(adc, AT91_ADC_CHDR, 1 << channel->id);
  139. spin_unlock(&adc->lock);
  140. return 0;
  141. }
  142. static ssize_t adc_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
  143. {
  144. return 0;
  145. }
  146. static ssize_t adc_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
  147. {
  148. return 0;
  149. }
  150. /* static void adc_sigio(struct adc_channel *channel) */
  151. /* { */
  152. /*  if (channel->fasync) */
  153. /*      kill_fasync(&channel->fasync, SIGIO, POLL_IN); */
  154. /* } */
  155. static int adc_ioctl(struct inode *inode, struct file *file,
  156. unsigned int cmd, unsigned long arg)
  157. {
  158. struct adc *adc;
  159. struct adc_channel *channel;
  160. struct adc_mode *mode;
  161. int ret = 0;
  162. unsigned int dummy = 0;
  163. void __user *argp = (void __user *)arg;
  164. int __user *p = argp;
  165. channel = container_of(inode->i_cdev, struct adc_channel, cdev);
  166. adc = channel->adc;
  167. mode = &adc->mode;
  168. switch (cmd) {
  169. case ADCCTL_RESET:
  170. adc_writel(adc, AT91_ADC_CR, AT91_ADC_SWRST);
  171. return 0;
  172. case ADCCTL_START:
  173. adc_writel(adc, AT91_ADC_CR, AT91_ADC_START);
  174. return 0;
  175. case ADCCTL_SETMODE:
  176. ret = copy_from_user(mode, argp, sizeof(struct adc_mode));
  177. if (mode->trigger == ADC_TRIGGER_TIMER)
  178. dummy |= AT91_ADC_TRGEN | AT91_ADC_TRGSEL_TC2;
  179. else if (mode->trigger == ADC_TRIGGER_EXT)
  180. dummy |= AT91_ADC_TRGEN | AT91_ADC_TRGSEL_EXT;
  181. if (mode->resolution & ADC_M_8BIT)
  182. dummy |= AT91_ADC_LOWRES;
  183. if (mode->sleep_mode)
  184. dummy |= AT91_ADC_SLEEP;
  185. if (mode->adc_clock)
  186. dummy |= AT91_ADC_PRESCAL_(mode->adc_clock);
  187. if (mode->startup_time)
  188. dummy |= AT91_ADC_STARTUP_(mode->startup_time);
  189. if (mode->sample_time)
  190. dummy |= AT91_ADC_SHTIM_(mode->sample_time);
  191. adc_init_tc(adc);
  192. spin_lock(&adc->lock);
  193. adc_writel(adc, AT91_ADC_MR, dummy);
  194. spin_unlock(&adc->lock);
  195. return 0;
  196. case ADCCTL_GETMODE:
  197. ret = copy_to_user(argp, mode, sizeof(struct adc_mode));
  198. return 0;
  199. case ADCCTL_GETDATA:
  200. //      ret = buf_cnt(channel);
  201. //  if (ret > 0) {
  202. //  if (!put_user(channel->buf[channel->tail], p))
  203. //  channel->tail = (channel->tail + 1) & (BUF_SIZE -1);
  204. //return 0;
  205. //}
  206. put_user(channel->adc_data,p);
  207. return -EFAULT;
  208. //  case ADCCTL_GETCNT:
  209. //  return put_user(buf_cnt(channel), p);
  210. case ADCCTL_GETSTATUS:
  211. return put_user(adc_readl(adc, AT91_ADC_SR), p);
  212. default:
  213. return -EINVAL;
  214. }
  215. return -EINVAL;
  216. }
  217. static struct file_operations adc_fops = {
  218. .owner     = THIS_MODULE,
  219. .read      = adc_read,
  220. .write     = adc_write,
  221. .open      = adc_open,
  222. .release   = adc_release,
  223. .ioctl     = adc_ioctl,
  224. .fasync    = adc_fasync,
  225. };
  226. static irqreturn_t adc_interrupt(int irq, void *dev_id)
  227. {
  228. struct adc *adc = dev_id;
  229. struct adc_channel *channel;
  230. unsigned int status;
  231. status = adc_readl(adc, AT91_ADC_SR) & adc_readl(adc, AT91_ADC_IMR);
  232. while (status) {
  233. printk(KERN_DEBUG "at91_adc: interrupt status reg 0x%08x\n",
  234. status);
  235. if (status & AT91_ADC_EOC0){
  236. channel = adc->channel[0];
  237. buf_in(channel, adc_readl(adc, AT91_ADC_CDR0));
  238. printk(KERN_INFO "the adc_data is %d\n",channel->adc_data);
  239. //          adc_sigio(channel);
  240. }
  241. if (status & AT91_ADC_EOC1){
  242. channel = adc->channel[1];
  243. buf_in(channel, adc_readl(adc, AT91_ADC_CDR1));
  244. printk(KERN_INFO "the adc_data is %d\n",channel->adc_data);
  245. //          adc_sigio(channel);
  246. }
  247. if (status & AT91_ADC_EOC2){
  248. channel = adc->channel[2];
  249. buf_in(channel, adc_readl(adc, AT91_ADC_CDR2));
  250. printk(KERN_INFO "the adc_data is %d\n",channel->adc_data);
  251. //          adc_sigio(channel);
  252. }
  253. if (status & AT91_ADC_EOC3) {
  254. channel = adc->channel[3];
  255. buf_in(channel, adc_readl(adc, AT91_ADC_CDR3));
  256. printk(KERN_INFO "the adc_data is %d\n",channel->adc_data);
  257. //          adc_sigio(channel);
  258. }
  259. if (status & AT91_ADC_DRDY)
  260. adc_readl(adc, AT91_ADC_LCDR);
  261. status = adc_readl(adc, AT91_ADC_SR) & adc_readl(adc, AT91_ADC_IMR);
  262. }
  263. return IRQ_HANDLED;
  264. }
  265. static int __exit adc_remove(struct platform_device *pdev)
  266. {
  267. struct adc_channel *channel = platform_get_drvdata(pdev);
  268. class_device_unregister(channel->class_dev);
  269. cdev_del(&channel->cdev);
  270. kfree(channel);
  271. return 0;
  272. }
  273. static struct platform_device adc_channel_device[ADC_MAX_CHANNEL];
  274. /*
  275. static int __init adc_add_channel_device(void)
  276. {
  277. int i;
  278. for (i=0; i<ADC_MAX_CHANNEL; i++){
  279. adc_channel_device[i].name = DRV_NAME;
  280. adc_channel_device[i].id   = i;
  281. platform_device_register(&adc_channel_device[i]);
  282. }
  283. return 0;
  284. }
  285. */
  286. static int __init adc_init(void)
  287. {struct adc_channel *channel;
  288. int ret = 0;
  289. //struct adc_channel *channel;
  290. int ret1;
  291. adc = kmalloc(sizeof(struct adc), GFP_KERNEL);
  292. if (!adc)
  293. return -ENOMEM;
  294. if (!request_mem_region(AT91SAM9260_BASE_ADC, SZ_16K, DRV_NAME)){
  295. kfree(adc);
  296. return -EBUSY;
  297. }
  298. adc->membase = ioremap(AT91SAM9260_BASE_ADC, SZ_16K);
  299. if (adc->membase == NULL)
  300. goto adc_release_mem;
  301. if (!request_mem_region(AT91SAM9260_BASE_TC0, SZ_16K, DRV_NAME))
  302. goto adc_iounmap;
  303. adc->tcbbase = ioremap(AT91SAM9260_BASE_TC0, SZ_16K);
  304. if (adc->tcbbase == NULL)
  305. goto adc_release_mem_tc;
  306. adc->irq = AT91SAM9260_ID_ADC;
  307. adc->tcxbase = adc->tcbbase + 0x80;
  308. spin_lock_init(&adc->lock);
  309. adc->class = class_create(THIS_MODULE, DEV_NAME);
  310. if (IS_ERR(adc->class)){
  311. printk(KERN_ERR "at91_adc: faile to create device class\n");
  312. goto adc_iounmap_tc;
  313. }
  314. ret = alloc_chrdev_region(&adc->devt, 0, 1, DEV_NAME);
  315. if (ret < 0) {
  316. printk(KERN_ERR"%s: failed to allocate dev region\n", __FILE__);
  317. goto adc_destroy_class;
  318. }
  319. if (request_irq(adc->irq, adc_interrupt, IRQF_SHARED, DRV_NAME, adc)){
  320. printk(KERN_ERR"%s: request irq failed\n", __FILE__);
  321. goto adc_del_channel;
  322. }
  323. adc_hw_init(adc);
  324. printk(KERN_INFO "&&123456xx\n");
  325. //platform_driver_register(&adc_driver);
  326. printk(KERN_INFO "Analog-to-Digital Converter (irq %d)\n", adc->irq);
  327. //  adc_add_channel_device();
  328. printk(KERN_ERR "&&123456&&\n");
  329. channel = kmalloc(sizeof(struct adc_channel), GFP_KERNEL);
  330. if (!channel){
  331. printk(KERN_ERR "&&123456&&\n");
  332. //printk(KERN_ERR "at91_adc: failed to kmalloc channel %d\n", pdev->id);
  333. return -ENOMEM;
  334. }
  335. //  channel->fasync = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
  336. //  if (!channel->fasync) return -ENOMEM;
  337. channel->id  = 0;
  338. //channel->dev = &pdev->dev;
  339. channel->adc = adc;
  340. channel->head = 0;
  341. channel->tail = 0;
  342. cdev_init(&channel->cdev, &adc_fops);
  343. channel->cdev.owner = THIS_MODULE;
  344. ret1 = cdev_add(&channel->cdev, MKDEV(MAJOR(adc->devt), channel->id), 1);
  345. if (ret1) {
  346. //printk(KERN_ERR "at91_adc: failed to add channel %d device\n", pdev->id);
  347. kfree(channel);
  348. return ret1;
  349. }
  350. channel->class_dev = class_device_create(adc->class, NULL,
  351. MKDEV(MAJOR(adc->devt),
  352. channel->id),
  353. NULL,
  354. DEV_NAME);
  355. if (IS_ERR(channel->class_dev)) {
  356. cdev_del(&channel->cdev);
  357. kfree(channel);
  358. return PTR_ERR(channel->class_dev);
  359. }
  360. adc->channel[channel->id] = channel;
  361. //platform_set_drvdata(pdev, channel);
  362. printk(KERN_INFO "at91_adc. major  is %d\n",
  363. MAJOR(adc->devt));
  364. return 0;
  365. adc_del_channel:
  366. unregister_chrdev_region(adc->devt, 1);
  367. adc_destroy_class:
  368. class_destroy(adc->class);
  369. adc_iounmap_tc:
  370. iounmap(adc->tcbbase);
  371. adc_release_mem_tc:
  372. release_mem_region(AT91SAM9260_BASE_TC0, SZ_16K);
  373. adc_iounmap:
  374. iounmap(adc->membase);
  375. adc_release_mem:
  376. release_mem_region(AT91SAM9260_BASE_ADC, SZ_16K);
  377. kfree(adc);
  378. return ret;
  379. }
  380. static void __exit adc_exit(void)
  381. {
  382. //platform_driver_unregister(&adc_driver);
  383. unregister_chrdev_region(adc->devt, ADC_MAX_CHANNEL);
  384. class_destroy(adc->class);
  385. free_irq(adc->irq, adc);
  386. iounmap(adc->tcbbase);
  387. release_mem_region(AT91SAM9260_BASE_TC0, SZ_16K);
  388. iounmap(adc->membase);
  389. release_mem_region(AT91SAM9260_BASE_ADC, SZ_16K);
  390. kfree(adc);
  391. }
  392. module_init(adc_init);
  393. module_exit(adc_exit);
  394. MODULE_AUTHOR("jiang ming bo ");
  395. MODULE_LICENSE("GPL");
  396. MODULE_DESCRIPTION("AT91 Analog-to-Digital Converter Driver");
 

sam9260 adc module的更多相关文章

  1. sam9260 adc 测试

    /* * adc_test.c * * Copyright (C) 2007 Mengrz */ #include <stdio.h> #include <stdlib.h> ...

  2. sam9260 adc 头文件

    /* * driver/char/at91_adc.h * * Copyright (C) 2007 Embedall Technology Co., Ltd. * * Analog-to-digit ...

  3. mini2440驱动奇谭——ADC驱动与測试(动态挂载驱动)

    博客:http://blog.csdn.net/muyang_ren 实现功能:开发板动态载入adc驱动模块并能通过測试程序 系统:Ubuntu 14.04     驱动交叉编译内核:linux-2. ...

  4. NUC131演示如何通过PWM触发ADC。

    今天我来讲讲PWM触发ADC的例程 /**************************************************************************** * @f ...

  5. [转]A Guide To using IMU (Accelerometer and Gyroscope Devices) in Embedded Applications.

    原文地址http://www.starlino.com/imu_guide.html Introduction There’s now a FRENCH translation of this art ...

  6. Unused port adds a PWM/analog channel to a microcontroller

    Low-cost, 8-bit, single-chip microcontrollers are stingy when it comes to on-chip PWM (pulse-width-m ...

  7. [蓝牙] 5、Battery Service module

    Detailed Description This module implements the Battery Service with the Battery Level characteristi ...

  8. 驱动之路四------adc驱动(input设备)

    开发板:smdk6410 开发环境:Linux 突然想起一点,写这些驱动,内核需要配成支持抢占才行. 前面的博客已经将其它的基本知识都解释了,这里也就不过多的阐述了,咱就直接写代码吧 这次写的是adc ...

  9. STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数

    1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...

随机推荐

  1. 嵌入式Linux下MP4视频录制库MP4V2移植和简单介绍

    **************************************************************************************************** ...

  2. Python 爬虫 数据清洗 去掉 超链接

    有时候我们需要清洗数据,里面有超链接,怎么去掉他们,比如下面的问题 , - January , </p></li><li </p><div " ...

  3. 命令行运行python项目文件,报错:ModuleNotFoundError: No module named 'xxxx' 解决办法

    在pycharm中写好了自动化测试脚本,并能在pycharm中正常运行,由于要考虑到无人值守时能自动执行,执行时就需要脱离pycharm,直接能用命令执行.但是直接用命令执行用例文件:python3 ...

  4. iOS常用RGB颜色的色值表

    常用RGB颜色表  R G B 值 R G B 值 R G B 值 黑色 0 0 0 #000000 黄色 255 255 0 #FFFF00 浅灰蓝色 176 224 230 #B0E0E6 象牙黑 ...

  5. unity, ios skin crash

    https://issuetracker.unity3d.com/issues/ios-loading-models-with-tangents-set-to-calculate-legacy-fro ...

  6. MySql(二):MySql架构组成

    主要架构就是这张图展示的 具体细节看下面文章: MySql 物理文件组成 MySQL 自带工具使用介绍 Mysql Server系统架构介绍

  7. IOS开发之UIScrollVIew运用

    UIScrollView可以实现在一个界面看到所有内容,同时也不需要担心所显示的内容超出屏幕的大小,当超出之后可以翻阅至下一页浏览. #pragma mark - UIScrollViewDelega ...

  8. 台式机vim配置

    set autoread syntax on "set number " filetype ident on "set autoindent "set expa ...

  9. haproxy 配置https 同时技持443 80端口

    确定haproxy支持https [root@c01 sbin]# ldd haproxy |grep ssl libssl.so.10 => /usr/lib64/libssl.so.10 ( ...

  10. 数据库存储引擎 show engines 修改引擎

    mysql> show engines; +--------------------+---------+-------------------------------------------- ...