OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 911|回复: 1

ICM26080 中断支持

[复制链接]

5

主题

123

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1827
金钱
1827
注册时间
2019-7-23
在线时间
282 小时
发表于 2021-6-25 15:27:50 | 显示全部楼层 |阅读模式
设备树节点如下:                       其中 CS片选引脚配置为GPIO功能。 且ICM26080工作在spi mode3模式。

  1. &ecspi3 {
  2.         fsl,spi-num-chipselects = <1>;
  3.         cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
  4.         pinctrl-names = "default";
  5.         pinctrl-0 = <&pinctrl_ecspi3>;
  6.         status = "okay";

  7.         icm20608@0 {
  8.                 compatible = "InvenSense,icm26080";
  9.                 pinctrl-names = "default";
  10.                 pinctrl-0 = <&pinctrl_icmInt>;       
  11.                
  12.                 interrupt-parent = <&gpio1>;
  13.                 interrupts = <1 0>;               
  14.         spi-max-frequency = <8000000>; icm20608.zip (5.69 KB, 下载次数: 0)


  15.         
复制代码
若spi3设备节点下大于4个节点的话,即fsl,spi-num-chipselects大于4,设备spi驱动程序可能会出问题。其原因如下

  1. spi_imx_setupxfer
复制代码

驱动如下
  1. #include <linux/module.h>
  2. #include <linux/ratelimit.h>
  3. #include <linux/interrupt.h>
  4. #include <linux/uaccess.h>
  5. #include <linux/delay.h>
  6. #include <linux/debugfs.h>
  7. #include <linux/slab.h>
  8. #include <linux/gpio.h>
  9. #include <linux/of_gpio.h>
  10. #include <linux/spi/spi.h>
  11. #include <linux/types.h>
  12. #include <linux/of.h>
  13. #include <linux/of_device.h>
  14. #include <linux/device.h>
  15. #include <linux/miscdevice.h>
  16. #include <linux/wait.h>
  17. #include <linux/sched.h>
  18. #include <linux/poll.h>
  19. #include <linux/fcntl.h>

  20. #define WHO_AM_I        0x75
  21. #define PWR1                0x6B

  22. #define SMPLRT_DIV                0x19
  23. #define CONFIG                        0x1A
  24. #define GYRO_CONFIG                0x1B
  25. #define ACCEL_CONFIG        0x1C
  26. #define ACCEL_CONFIG_2        0x1D
  27. #define LP_MODE_CFG                0x1E

  28. #define FIFO_EN                        0x23

  29. #define INT_PIN_CFG                0x37
  30. #define        INT_ENABLLE                0x38
  31. #define INT_STATUS                0x3A

  32. #define ACCEL_XOUT_H        0x3B                                        // 3B -- 48


  33. struct sensor_data {

  34.         float        accel_scal;
  35.         float        gyro_scal;

  36.         short accel_xad;
  37.         short accel_yad;
  38.         short accel_zad;

  39.         short tempad;

  40.         short gyro_Xad;
  41.         short gyro_yad;
  42.         short gyro_zad;

  43. };

  44. struct icm26080_data {

  45.         struct spi_device *spi;
  46.         u8 whoami;


  47.         struct sensor_data sd;

  48.         struct miscdevice misc;

  49.         atomic_t lock;
  50.         wait_queue_head_t r_wait;
  51.         struct fasync_struct *async_queue;
  52. };



  53. struct ICM_names {

  54.         int index;
  55.         const char * const name;

  56. };


  57. struct ICM_InfoNames {
  58.         u8 count;
  59.         struct ICM_names icm_name[2];
  60. };


  61. struct ICM_InfoNames ICM_InfoName = {

  62.         .count = 2,
  63.         .icm_name = {

  64.                 {.index         = 0XAF,        .name        = "ICM-20608G",},

  65.                 {.index         = 0XAE,        .name        = "ICM-20608D",},
  66.         },

  67. };



  68. static const struct of_device_id icm26080_dt_ids[] = {
  69.         { .compatible = "InvenSense,icm26080",.data = &ICM_InfoName},
  70.         {},
  71. };

  72. static int icm26080_write_reg(struct icm26080_data *icmdata,u8 addr, u8 *buf, u32 size)
  73. {
  74.         int ret = 0;
  75.         u8 *localbuf = kzalloc(size + 1, GFP_KERNEL);
  76.         struct spi_transfer        t = {
  77.                         .tx_buf                = localbuf,
  78.                         .len                = size + 1,
  79.                        
  80.                 };
  81.         struct spi_message        m;
  82.         localbuf[0] = addr;       
  83.         memcpy(&localbuf[1],buf,size);

  84.         spi_message_init(&m);
  85.         spi_message_add_tail(&t, &m);
  86.        
  87.         ret = spi_sync(icmdata->spi, &m);
  88.         kfree(localbuf);
  89.        
  90.         return ret;
  91. }




  92. static int icm26080_read_reg(struct icm26080_data *icmdata,u8 addr, u8 *buf, u32 size)
  93. {

  94.         int ret = 0;
  95.         u8 localaddr = addr | 0x80;
  96.         struct spi_transfer        t[2] = {
  97.                         {
  98.                                 .tx_buf                = &localaddr,
  99.                                 .len                = 1,
  100.                         },
  101.                        
  102.                         {
  103.                                 .rx_buf                = buf,
  104.                                 .len                = size,
  105.                         },
  106.                        
  107.                 };
  108.         struct spi_message        m;

  109.         spi_message_init(&m);
  110.         spi_message_add_tail(&t[0], &m);
  111.         spi_message_add_tail(&t[1], &m);
  112.        
  113.         ret =  spi_sync(icmdata->spi, &m);

  114.         return ret;

  115. }



  116. //#define INT_STATUS                0x3A
  117. static int icm26080_setup(struct icm26080_data *icmdata)
  118. {
  119.         u8 reg = 0;
  120.         icm26080_write_reg(icmdata,SMPLRT_DIV,"\x09",1);        // 100hz samp
  121.         icm26080_write_reg(icmdata,GYRO_CONFIG,"\x18",1);        // +- 2000dps
  122.         icm26080_write_reg(icmdata,ACCEL_CONFIG,"\x18",1);        // +- 16G

  123.         icm26080_write_reg(icmdata,CONFIG,"\x04",1);                // BW 20HZ
  124.         icm26080_write_reg(icmdata,ACCEL_CONFIG_2,"\x04",1);       
  125.        

  126.         icm26080_write_reg(icmdata,INT_PIN_CFG,"\xa0",1);       
  127.         icm26080_write_reg(icmdata,INT_ENABLLE,"\x01",1);       

  128.         icm26080_read_reg(icmdata, GYRO_CONFIG, &#174;, 1);
  129.         switch((reg >> 3)&0x03)
  130.         {
  131.                 case 0:
  132.                         icmdata->sd.gyro_scal = 131.0f;
  133.                         break;

  134.                 case 1:
  135.                         icmdata->sd.gyro_scal = 62.5f;
  136.                         break;

  137.                 case 2:
  138.                         icmdata->sd.gyro_scal = 32.8f;
  139.                         break;

  140.                 case 3:
  141.                         icmdata->sd.gyro_scal = 16.4f;
  142.                         break;

  143.         }
  144.                
  145.         icm26080_read_reg(icmdata, ACCEL_CONFIG, &#174;, 1);
  146.         switch((reg >> 3)&0x03)
  147.         {
  148.                 case 0:
  149.                         icmdata->sd.accel_scal = 16384;
  150.                         break;

  151.                 case 1:
  152.                         icmdata->sd.accel_scal = 8192;
  153.                         break;

  154.                 case 2:
  155.                         icmdata->sd.accel_scal = 4096;
  156.                         break;

  157.                 case 3:
  158.                         icmdata->sd.accel_scal = 2048;
  159.                         break;

  160.         }
  161.                
  162.         return 0;
  163. }



  164. static int icm26080_open(struct inode *inode, struct file *filp)
  165. {
  166.         struct icm26080_data *icmdata = container_of(filp->private_data,struct icm26080_data,misc);

  167.         filp->private_data = icmdata;

  168.         return 0;
  169. }


  170. static ssize_t icm26080_read(struct file *filp, char __user *buf, size_t count, loff_t *offt)
  171. {
  172.         struct icm26080_data *icmdata = filp->private_data;

  173.         if(filp->f_flags & O_NONBLOCK)
  174.         {
  175.                 if(!atomic_dec_and_test(&icmdata->lock))
  176.                 {
  177.                         atomic_inc(&icmdata->lock);
  178.                         return -EAGAIN;
  179.                 }

  180.         }else {

  181.                 wait_event_interruptible(icmdata->r_wait, atomic_read(&icmdata->lock));
  182.         }

  183.         if(count != sizeof(struct sensor_data))
  184.                 return -EINVAL;

  185.         if(copy_to_user(buf, &icmdata->sd, count))
  186.                 return -EINVAL;
  187.        
  188.        
  189.         return count;
  190. }

  191. static unsigned int icm26080_poll(struct file *file, poll_table * wait)
  192. {
  193.     struct icm26080_data *icmdata = file->private_data;   
  194.         unsigned int mask = 0;

  195.         poll_wait(file, &icmdata->r_wait, wait);

  196.         if(atomic_read(&icmdata->lock))
  197.                  mask = POLLIN | POLLRDNORM;
  198.        
  199.         return mask;
  200. }




  201. static int
  202. icm26080_fasync(int fd, struct file *file, int on)
  203. {

  204.         struct icm26080_data *icmdata = file->private_data;

  205.         return fasync_helper(fd, file, on, &icmdata->async_queue);
  206. }

  207. static int icm26080_release(struct inode *inode, struct file *file)
  208. {
  209.         struct icm26080_data *icmdata = file->private_data;
  210.         return fasync_helper(-1, file, 0,&icmdata->async_queue);
  211. }



  212. static struct file_operations icm_fops = {

  213.         .owner        = THIS_MODULE,
  214.         .open        = icm26080_open,
  215.         .read        = icm26080_read,
  216.         .poll        = icm26080_poll,
  217.         .fasync = icm26080_fasync,
  218.         .release = icm26080_release,
  219. };



  220. static irqreturn_t icm26080_isr(int irq, void *dev_id)
  221. {
  222.         u8 int_status = 0;
  223.         u8 buf[14];
  224.         struct icm26080_data *icmdata = (struct icm26080_data *)dev_id;
  225.        
  226.         icm26080_read_reg(icmdata,INT_STATUS, &int_status, 1);

  227.        
  228.         if(int_status & 0x01)
  229.         {
  230.                 icm26080_read_reg(icmdata,ACCEL_XOUT_H, buf, 14);
  231.                
  232.                 icmdata->sd.accel_xad = (signed short)(buf[0] << 8 | buf[1]);
  233.                 icmdata->sd.accel_yad = (signed short)(buf[2] << 8 | buf[3]);
  234.                 icmdata->sd.accel_zad = (signed short)(buf[4] << 8 | buf[5]);

  235.                 icmdata->sd.tempad = (signed short)(buf[6] << 8 | buf[7]);

  236.                 icmdata->sd.gyro_Xad  = (signed short)(buf[8] << 8 | buf[9]) ;
  237.                 icmdata->sd.gyro_yad  = (signed short)(buf[10] << 8 | buf[11]) ;
  238.                 icmdata->sd.gyro_zad  = (signed short)(buf[12] << 8 | buf[13]);

  239.                 atomic_set(&icmdata->lock, 1);
  240.                 wake_up_interruptible(&icmdata->r_wait);
  241.                 kill_fasync(&icmdata->async_queue, SIGIO, POLL_IN);
  242.         }

  243.         icm26080_write_reg(icmdata,INT_STATUS,"\x00",1);       
  244.        
  245.         return IRQ_HANDLED;
  246. }






  247. static int icm26080_probe(struct spi_device *spi)
  248. {

  249.         int ret = 0;
  250.         int i = 0;

  251.         struct icm26080_data *icmdata;
  252.         const struct of_device_id *of_id =
  253.                         of_match_device(icm26080_dt_ids, &spi->dev);
  254.         const struct ICM_InfoNames *name = (struct ICM_InfoNames *)of_id ->data;
  255.        
  256.         icmdata = devm_kzalloc(&spi->dev, sizeof(*icmdata), GFP_KERNEL);
  257.         if (!icmdata) {
  258.                 dev_err(&spi->dev, "failed to allocate driver data.\n");
  259.                 return -ENOMEM;
  260.         }

  261.         icmdata->spi = spi;
  262.         spi_set_drvdata(spi, icmdata);

  263.         icm26080_write_reg(icmdata,PWR1,"\x80",1);
  264.         msleep(50);
  265.         icm26080_write_reg(icmdata,PWR1,"\x01",1);
  266.         msleep(50);
  267.        
  268.         ret = icm26080_read_reg(icmdata,WHO_AM_I,&(icmdata->whoami),1);
  269.         if(!ret)
  270.         {
  271.                 for(i=0; i<name->count; i++)
  272.                 {
  273.                         if(icmdata->whoami == name->icm_name[i].index)
  274.                         {
  275.                                 dev_info(&spi->dev,"%s probed\n",name->icm_name[i].name);
  276.                                 break;
  277.                         }               
  278.                 }

  279.                 if(i >= name->count)
  280.                 {
  281.                         dev_info(&spi->dev,"No device probed!\n");
  282.                         goto failed;
  283.                 }
  284.         }else {

  285.                 goto failed;
  286.         }
  287.        
  288.         icm26080_setup(icmdata);

  289.         atomic_set(&icmdata->lock, 0);
  290.         init_waitqueue_head(&icmdata->r_wait);
  291.        
  292.         ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
  293.                                 icm26080_isr,
  294.                                 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
  295.                                 spi->modalias, icmdata);

  296.         icmdata->misc.minor = MISC_DYNAMIC_MINOR;
  297.         icmdata->misc.name        = spi->modalias;
  298.         icmdata->misc.parent = &spi->dev;
  299.         icmdata->misc.fops        = &icm_fops;
  300.         ret = misc_register(&icmdata->misc);

  301. failed:       
  302.         return ret;
  303. }


  304. static int icm26080_remove(struct spi_device *spi)
  305. {
  306.         struct icm26080_data *icmdata = spi_get_drvdata(spi);

  307.         misc_deregister(&icmdata->misc);
  308.         dev_info(&spi->dev,"removed\n");
  309.         return 0;
  310. }




  311. static struct spi_driver spidev_spi_driver = {
  312.         .driver = {
  313.                 .name =                "icm26080",
  314.                 .owner =        THIS_MODULE,
  315.                 .of_match_table = of_match_ptr(icm26080_dt_ids),
  316.         },
  317.         .probe =        icm26080_probe,
  318.         .remove =        icm26080_remove,

  319. };



  320. module_spi_driver(spidev_spi_driver);

  321. MODULE_LICENSE("GPL");


复制代码



享受技术
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

123

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1827
金钱
1827
注册时间
2019-7-23
在线时间
282 小时
 楼主| 发表于 2021-6-25 15:33:29 | 显示全部楼层
设备树
  1. &ecspi3 {
  2.         fsl,spi-num-chipselects = <1>;
  3.         cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
  4.         pinctrl-names = "default";
  5.         pinctrl-0 = <&pinctrl_ecspi3>;
  6.         status = "okay";

  7.         icm20608@0 {
  8.                 compatible = "InvenSense,icm26080";
  9.                 pinctrl-names = "default";
  10.                 pinctrl-0 = <&pinctrl_icmInt>;       
  11.                
  12.                 interrupt-parent = <&gpio1>;
  13.                 interrupts = <1 0>;               
  14.         spi-max-frequency = <8000000>;
  15.         reg = <0>;
  16.                 spi-cpol;
  17.                 spi-cpha;
  18.     };
  19. };
复制代码
原因如下
  1. spi_imx_setupxfer
复制代码
mx51_ecspi_config
  ->   
        if (config->mode & SPI_CPHA)
                cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
        if (config->mode & SPI_CPOL) {
                cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
                cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
        }
#define MX51_ECSPI_CONFIG_SCLKPHA(cs)        (1 << ((cs) +  0))


上方排版没做好,重新发一下

享受技术
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-24 12:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表