本文记录阅读linux ad7606驱动的笔记。

主要文件

drivers/staging/iio/adc/ad7606_spi.c

drivers/staging/iio/adc/ad7606_core.c

drivers/staging/iio/adc/ad7606_ring.c

  1. drivers/staging/iio/adc/ad7606_spi.c
  2. static int __init ad7606_spi_init(void)
  3. {
  4. return spi_register_driver(&ad7606_driver);
  5. }
  6. module_init(ad7606_spi_init);
  7. static struct spi_driver ad7606_driver = {
  8. .driver = {
  9. .name = "ad7606",
  10. .bus = &spi_bus_type,
  11. .owner = THIS_MODULE,
  12. .pm = AD7606_SPI_PM_OPS,
  13. },
  14. .probe = ad7606_spi_probe,
  15. .remove = __devexit_p(ad7606_spi_remove),
  16. .id_table = ad7606_id,
  17. };
  18. static int __devinit ad7606_spi_probe(struct spi_device *spi)
  19. {
  20. struct iio_dev *indio_dev;
  21. indio_dev = ad7606_probe(&spi->dev, spi->irq, NULL, ------+
  22. spi_get_device_id(spi)->driver_data, |
  23. &ad7606_spi_bops); ---------+ |
  24. | |
  25. if (IS_ERR(indio_dev)) | |
  26. return PTR_ERR(indio_dev); | |
  27. | |
  28. | |
  29. spi_set_drvdata(spi, indio_dev); | |
  30. | |
  31. return 0; | |
  32. } | |
  33. V |
  34. static const struct ad7606_bus_ops ad7606_spi_bops = { |
  35. .read_block = ad7606_spi_read_block, |
  36. }; |
  37. |
  38. drivers/staging/iio/adc/ad7606_core.c |
  39. struct iio_dev *ad7606_probe(struct device *dev, int irq, <---+
  40. void __iomem *base_address,
  41. unsigned id,
  42. const struct ad7606_bus_ops *bops)
  43. {
  44. struct ad7606_platform_data *pdata = dev->platform_data;
  45. struct ad7606_state *st;
  46. int ret, regdone = 0;
  47. struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
  48. if (indio_dev == NULL) {
  49. ret = -ENOMEM;
  50. goto error_ret;
  51. }
  52. st = iio_priv(indio_dev);
  53. st->dev = dev;
  54. st->id = id;
  55. st->irq = irq;
  56. st->bops = bops;
  57. st->base_address = base_address;
  58. // 默认的模拟通道输入电压范围, 10V/5V
  59. st->range = pdata->default_range == 10000 ? 10000 : 5000;
  60. // 过采样率
  61. ret = ad7606_oversampling_get_index(pdata->default_os);
  62. if (ret < 0) {
  63. dev_warn(dev, "oversampling %d is not supported\n",
  64. pdata->default_os);
  65. st->oversampling = 0;
  66. } else {
  67. st->oversampling = pdata->default_os;
  68. }
  69. st->reg = regulator_get(dev, "vcc");
  70. if (!IS_ERR(st->reg)) {
  71. ret = regulator_enable(st->reg);
  72. if (ret)
  73. goto error_put_reg;
  74. }
  75. st->pdata = pdata;
  76. st->chip_info = &ad7606_chip_info_tbl[id]; -----------------------------+
  77. |
  78. indio_dev->dev.parent = dev; |
  79. indio_dev->info = &ad7606_info; |
  80. indio_dev->modes = INDIO_DIRECT_MODE; |
  81. indio_dev->name = st->chip_info->name; |
  82. indio_dev->channels = st->chip_info->channels; |
  83. indio_dev->num_channels = st->chip_info->num_channels; |
  84. |
  85. init_waitqueue_head(&st->wq_data_avail); |
  86. |
  87. ret = ad7606_request_gpios(st); -------------------------------+ |
  88. if (ret) | |
  89. goto error_disable_reg; | |
  90. | |
  91. | |
  92. ret = ad7606_reset(st); | |
  93. if (ret) | |
  94. dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); | |
  95. // ad7606中断,我使用的是busy引脚作为中断输入。 | |
  96. ret = request_irq(st->irq, ad7606_interrupt, -------+ | |
  97. IRQF_TRIGGER_FALLING, st->chip_info->name, indio_dev); | | |
  98. if (ret) | | |
  99. goto error_free_gpios; | | |
  100. | | |
  101. ret = ad7606_register_ring_funcs_and_init(indio_dev); | | |
  102. if (ret) | | |
  103. goto error_free_irq; | | |
  104. | | |
  105. ret = iio_device_register(indio_dev); | | |
  106. if (ret) | | |
  107. goto error_free_irq; | | |
  108. regdone = 1; | | |
  109. | | |
  110. ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | | |
  111. indio_dev->channels, | | |
  112. indio_dev->num_channels); | | |
  113. if (ret) | | |
  114. goto error_cleanup_ring; | | |
  115. | | |
  116. return indio_dev; | | |
  117. | | |
  118. error_cleanup_ring: | | |
  119. ad7606_ring_cleanup(indio_dev); | | |
  120. | | |
  121. error_free_irq: | | |
  122. free_irq(st->irq, indio_dev); | | |
  123. | | |
  124. error_free_gpios: | | |
  125. ad7606_free_gpios(st); | | |
  126. | | |
  127. error_disable_reg: | | |
  128. if (!IS_ERR(st->reg)) | | |
  129. regulator_disable(st->reg); | | |
  130. error_put_reg: | | |
  131. if (!IS_ERR(st->reg)) | | |
  132. regulator_put(st->reg); | | |
  133. if (regdone) | | |
  134. iio_device_unregister(indio_dev); | | |
  135. else | | |
  136. iio_free_device(indio_dev); | | |
  137. error_ret: | | |
  138. return ERR_PTR(ret); | | |
  139. } | | |
  140. | | |
  141. // 中断处理函数 | | |
  142. static irqreturn_t ad7606_interrupt(int irq, void *dev_id) <---+ | |
  143. { | |
  144. struct iio_dev *indio_dev = dev_id; | |
  145. struct ad7606_state *st = iio_priv(indio_dev); | |
  146. | |
  147. if (iio_ring_enabled(indio_dev)) { | |
  148. if (!work_pending(&st->poll_work)) | |
  149. schedule_work(&st->poll_work); | |
  150. } else { | |
  151. st->done = true; | |
  152. // 唤醒中断 | |
  153. wake_up_interruptible(&st->wq_data_avail); | |
  154. } | |
  155. | |
  156. return IRQ_HANDLED; | |
  157. }; | |
  158. static int ad7606_request_gpios(struct ad7606_state *st) <----------+ |
  159. { |
  160. struct gpio gpio_array[3] = { |
  161. [0] = { |
  162. .gpio = st->pdata->gpio_os0, |
  163. .flags = GPIOF_DIR_OUT | ((st->oversampling & 1) ? |
  164. GPIOF_INIT_HIGH : GPIOF_INIT_LOW), |
  165. .label = "AD7606_OS0", |
  166. }, |
  167. [1] = { |
  168. .gpio = st->pdata->gpio_os1, |
  169. .flags = GPIOF_DIR_OUT | ((st->oversampling & 2) ? |
  170. GPIOF_INIT_HIGH : GPIOF_INIT_LOW), |
  171. .label = "AD7606_OS1", |
  172. }, |
  173. [2] = { |
  174. .gpio = st->pdata->gpio_os2, |
  175. .flags = GPIOF_DIR_OUT | ((st->oversampling & 4) ? |
  176. GPIOF_INIT_HIGH : GPIOF_INIT_LOW), |
  177. .label = "AD7606_OS2", |
  178. }, |
  179. }; |
  180. int ret; |
  181. |
  182. ret = gpio_request_one(st->pdata->gpio_convst, GPIOF_OUT_INIT_LOW, |
  183. "AD7606_CONVST"); |
  184. if (ret) { |
  185. dev_err(st->dev, "failed to request GPIO CONVST\n"); |
  186. return ret; |
  187. } |
  188. |
  189. ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array)); |
  190. if (!ret) { |
  191. st->have_os = true; |
  192. } |
  193. |
  194. ret = gpio_request_one(st->pdata->gpio_reset, GPIOF_OUT_INIT_LOW, |
  195. "AD7606_RESET"); |
  196. if (!ret) |
  197. st->have_reset = true; |
  198. |
  199. ret = gpio_request_one(st->pdata->gpio_range, GPIOF_DIR_OUT | |
  200. ((st->range == 10000) ? GPIOF_INIT_HIGH : |
  201. GPIOF_INIT_LOW), "AD7606_RANGE"); |
  202. if (!ret) |
  203. st->have_range = true; |
  204. |
  205. ret = gpio_request_one(st->pdata->gpio_stby, GPIOF_OUT_INIT_HIGH, |
  206. "AD7606_STBY"); |
  207. if (!ret) |
  208. st->have_stby = true; |
  209. // 是否定义了gpio_frstdata,没有定义就是-1. |
  210. // 我调试的时候这个信号有问题,所以就设置成-1.st->have_frstdata=false |
  211. if (gpio_is_valid(st->pdata->gpio_frstdata)) { |
  212. ret = gpio_request_one(st->pdata->gpio_frstdata, GPIOF_IN, |
  213. "AD7606_FRSTDATA"); |
  214. if (!ret) |
  215. st->have_frstdata = true; |
  216. } |
  217. |
  218. return 0; |
  219. } |
  220. |
  221. static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { <------+
  222. /*
  223. * More devices added in future
  224. */
  225. [ID_AD7606_8] = {
  226. .name = "ad7606",
  227. .int_vref_mv = 2500,
  228. .channels = ad7606_8_channels,
  229. .num_channels = 8,
  230. },
  231. [ID_AD7606_6] = {
  232. .name = "ad7606-6",
  233. .int_vref_mv = 2500,
  234. .channels = ad7606_6_channels,
  235. .num_channels = 6,
  236. },
  237. [ID_AD7606_4] = {
  238. .name = "ad7606-4",
  239. .int_vref_mv = 2500,
  240. .channels = ad7606_4_channels,
  241. .num_channels = 4,
  242. },
  243. };
  244. static int ad7606_oversampling_get_index(unsigned val)
  245. {
  246. unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64};
  247. int i;
  248. for (i = 0; i < ARRAY_SIZE(supported); i++)
  249. if (val == supported[i])
  250. return i;
  251. return -EINVAL;
  252. }
  253. //应用层读取的时候会调用这个函数。
  254. static int ad7606_read_raw(struct iio_dev *indio_dev,
  255. struct iio_chan_spec const *chan,
  256. int *val,
  257. int *val2,
  258. long m)
  259. {
  260. int ret;
  261. struct ad7606_state *st = iio_priv(indio_dev);
  262. unsigned int scale_uv;
  263. switch (m) {
  264. case 0:
  265. mutex_lock(&indio_dev->mlock);
  266. if (iio_ring_enabled(indio_dev))
  267. ret = ad7606_scan_from_ring(indio_dev, chan->address);
  268. else
  269. ret = ad7606_scan_direct(indio_dev, chan->address); ------+
  270. mutex_unlock(&indio_dev->mlock); |
  271. |
  272. if (ret < 0) |
  273. return ret; |
  274. *val = (short) ret; |
  275. return IIO_VAL_INT; |
  276. case (1 << IIO_CHAN_INFO_SCALE_SHARED): |
  277. scale_uv = (st->range * 1000 * 2) |
  278. >> st->chip_info->channels[0].scan_type.realbits; |
  279. *val = scale_uv / 1000; |
  280. *val2 = (scale_uv % 1000) * 1000; |
  281. return IIO_VAL_INT_PLUS_MICRO; |
  282. } |
  283. return -EINVAL; |
  284. } |
  285. |
  286. static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned ch) <----+
  287. {
  288. struct ad7606_state *st = iio_priv(indio_dev);
  289. int ret;
  290. st->done = false;
  291. gpio_set_value(st->pdata->gpio_convst, 1);
  292. // 此处中断, 等待中断调用ad7606_interrupt函数唤醒中断。
  293. ret = wait_event_interruptible(st->wq_data_avail, st->done);
  294. if (ret)
  295. goto error_ret;
  296. // 判断have_frstdata是否为true
  297. if (st->have_frstdata) {
  298. ret = st->bops->read_block(st->dev, 1, st->data);
  299. if (ret)
  300. goto error_ret;
  301. if (!gpio_get_value(st->pdata->gpio_frstdata)) {
  302. /* This should never happen */
  303. ad7606_reset(st);
  304. ret = -EIO;
  305. goto error_ret;
  306. }
  307. ret = st->bops->read_block(st->dev,
  308. st->chip_info->num_channels - 1, &st->data[1]);
  309. if (ret){
  310. goto error_ret;
  311. } else {
  312. ret = st->bops->read_block(st->dev,
  313. st->chip_info->num_channels, st->data);
  314. if (ret)
  315. goto error_ret;
  316. }
  317. ret = st->data[ch];
  318. error_ret:
  319. gpio_set_value(st->pdata->gpio_convst, 0);
  320. return ret;
  321. }
  322. static int ad7606_spi_read_block(struct device *dev,
  323. int count, void *buf)
  324. {
  325. struct spi_device *spi = to_spi_device(dev);
  326. int i, ret;
  327. unsigned short *data = buf;
  328. ret = spi_read(spi, (u8 *)buf, count * 2);
  329. if (ret < 0) {
  330. dev_err(&spi->dev, "SPI read error\n");
  331. return ret;
  332. }
  333. for (i = 0; i < count; i++) {
  334. data[i] = be16_to_cpu(data[i]);
  335. }
  336. return 0;
  337. }
  338. include/linux/spi/spi.h
  339. static inline int
  340. spi_read(struct spi_device *spi, void *buf, size_t len)
  341. {
  342. struct spi_transfer t = {
  343. .rx_buf = buf,
  344. .len = len,
  345. };
  346. struct spi_message m;
  347. spi_message_init(&m);
  348. spi_message_add_tail(&t, &m);
  349. return spi_sync(spi, &m);
  350. }

Tony Liu

2017-1-13, Shenzhen

linux ad7606 驱动解读的更多相关文章

  1. Linux ad7606 驱动

    Linux中已经移植好了ad7606,位于driver/staging/iio/adc/目录中.只要在板级文件中添加device中即可. 移植参考文档: https://wiki.analog.com ...

  2. Linux网络驱动--snull

    snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...

  3. 浅谈Android系统移植、Linux设备驱动

    一.Android系统架构 第一层:Linux内核 包括驱动程序,管理内存.进程.电源等资源的程序 第二层:C/C++代码库 包括Linux的.so文件以及嵌入到APK程序中的NDK代码 第三层:An ...

  4. Linux设备驱动模型之I2C总线

    一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...

  5. linux设备驱动概述,王明学learn

    linux设备驱动学习-1 本章节主要学习有操作系统的设备驱动和无操作系统设备驱动的区别,以及对操作系统和设备驱动关系的认识. 一.设备驱动的作用 对设备驱动最通俗的解释就是“驱使硬件设备行动” .设 ...

  6. Smart210学习记录------linux串口驱动

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...

  7. linux网卡驱动移植

    这里重要的是物理层PHY receiver,MAC(media access control)层,这里与软件中的协议栈不同,在硬件上MAC是PHY的下一层.DM9000A将MAC和PHY做到一起,也可 ...

  8. Linux USB驱动

    linux usb 驱动详解 一 http://blog.163.com/cl2006ky@126/blog/static/87195173201131245557340/ USB设备驱动开发-USB ...

  9. 我就是认真:Linux SWAP 深度解读(必须收藏)

    我就是认真:Linux SWAP 深度解读(必须收藏) http://mp.weixin.qq.com/s?__biz=MzA4Nzg5Nzc5OA==&mid=2651660097& ...

随机推荐

  1. 安装R语言的包的方法

    安装R语言的包的方法: 1. 在线安装 在R的控制台,输入类似install.packages("TSA")  # 安装 TSA install.packages("TS ...

  2. 两种方式— 在hive SQL中传入参数

    第一种: sql = sql.format(dt=dt) 第二种: item_third_cate_cd_list = " 发发发 " ...... ""&qu ...

  3. python标准库介绍——20 cStringIO 模块详解

    ==cStringIO 模块== ``cStringIO`` 是一个可选的模块, 是 ``StringIO`` 的更快速实现. 它的工作方式和 ``StringIO`` 基本相同, 但是它不可以被继承 ...

  4. Google大牛分享的面试秘籍

    我憋了很长时间想写点关于去Google面试的秘籍.不过我总是推迟,因为写出来的东西会让你抓狂.很可能是这样.如果按统计规律来定义“你”的话,这文章很可能让你不爽. 为啥呢?因为啊……好吧,对此我写首小 ...

  5. cocos2dx当节点存在缩放时要注意的问题

    cocos2dx(所有引擎也均如此),如果一个节点存在缩放,一定不要忘了其局部空间里的单位长度也会发生变化.其子节点位移,局部空间转世界空间结果等都会受影响. 有时候我们想将父节点的缩放转移到子节点中 ...

  6. rabbitmq增加vhost

    查看当前rabbitmq上的vhost列表: # rabbitmqctl list_vhosts Listing vhosts ... / vhost2 添加名为demo的vhost虚似主机: rab ...

  7. C++ 11 auto关键字

    熟悉脚本语言的人都知道,很多脚本语言都引入了“类型自动推断”技术:比如Python,可以直接声明变量,在运行时进行类型检查.随着C++11标准的发布,C++语言也引入了类型自动推断的功能,这就是我们今 ...

  8. 理解 Linux 配置文件

    介绍 每个 Linux 程序都是一个可执行文件,它含有操作码列表,CPU 将执行这些操作码来完成特定的操作.例如,ls 命令是由 /bin/ls 文件提供的,该文件含有机器指令的列表,在屏幕上显示当前 ...

  9. iOS自定义组与组之间的距离以及视图

    iOS自定义组与组之间的距离以及视图 //头视图高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(N ...

  10. Java – Convert IP address to Decimal Number

    In this tutorial, we show you how to convert an IP address to its decimal equivalent in Java, and vi ...