linux設備驅動 spi詳解6-spi驅動實例


linux內核給了一個spi驅動的實例。

driver/spi/spidev.c 

1 spi_driver.c

  1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/ioctl.h>
  4 #include <linux/fs.h>
  5 #include <linux/device.h>
  6 #include <linux/err.h>
  7 #include <linux/list.h>
  8 #include <linux/errno.h>
  9 #include <linux/mutex.h>
 10 #include <linux/slab.h>
 11 #include <linux/compat.h>
 12 #include <linux/of.h>
 13 #include <linux/of_device.h>
 14 
 15 #include <linux/spi/spi.h>
 16 #include <linux/spi/spidev.h>
 17 
 18 #include <asm/uaccess.h>  
 19   
 20 #define SPIDEV_MAJOR            153 //spidev主設備號  
 21 #define N_SPI_MINORS            32  /* ... up to 256 */  
 22 static DECLARE_BITMAP(minors, N_SPI_MINORS);    //聲明次設備位圖  
 23 #define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY)  
 24   
 25 struct spidev_data {  
 26     dev_t   devt;               //設備號  
 27     spinlock_t  spi_lock;       //自旋鎖  
 28     struct spi_device   *spi;   //spi設備結構體  
 29     struct list_head    device_entry;  
 30     struct mutex    buf_lock;   //互斥鎖  
 31     unsigned        users;      //使用者計數  
 32     u8          *buffer;        //緩沖區  
 33 };  
 34   
 35 static LIST_HEAD(device_list);  //聲明spi設備鏈表  
 36 static DEFINE_MUTEX(device_list_lock);  //定義互斥鎖  
 37 static unsigned bufsiz = 4096;  //最大傳輸緩沖區大小  
 38 module_param(bufsiz, uint, S_IRUGO);  
 39 MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");  
 40   
 41 static void spidev_complete(void *arg)  
 42 {  
 43     complete(arg);  //調用complete  
 44 }  
 45   
 46 static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)  
 47 {  
 48     DECLARE_COMPLETION_ONSTACK(done);  
 49     int status;  
 50   
 51     message->complete = spidev_complete; //設置spi消息的complete方法 回調函數  
 52     message->context = &done;  
 53   
 54     spin_lock_irq(&spidev->spi_lock);  
 55     if (spidev->spi == NULL) //判斷是否有指定對應的spi設備  
 56         status = -ESHUTDOWN;  
 57     else  
 58         status = spi_async(spidev->spi, message);    //spi異步同步  
 59     spin_unlock_irq(&spidev->spi_lock);  
 60   
 61     if (status == 0) {  
 62         wait_for_completion(&done); //等待傳輸完成  
 63         status = message->status;    //獲取spi消息傳輸事務狀態  
 64         if (status == 0)  
 65             status = message->actual_length; //status等於傳輸的實際長度  
 66     }  
 67     return status;  //返回實際傳輸長度  
 68 }  
 69   
 70 static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len)  
 71 {  
 72     struct spi_transfer t = {  
 73             .tx_buf     = spidev->buffer,    //發送緩沖區  
 74             .len        = len,  //發送數據長度  
 75         };  
 76     struct spi_message  m;  
 77   
 78     spi_message_init(&m);   //初始化spi消息(初始化spi傳遞事務隊列)  
 79     spi_message_add_tail(&t, &m);   //添加spr傳遞到該隊列  
 80     return spidev_sync(spidev, &m); //同步讀寫  
 81 }  
 82   
 83 static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len)  
 84 {  
 85     struct spi_transfer t = {  
 86             .rx_buf     = spidev->buffer,    //接收緩沖區  
 87             .len        = len,  //接收數據長度  
 88         };  
 89     struct spi_message  m;  
 90   
 91     spi_message_init(&m);   //初始化spi消息(初始化spi傳遞事務隊列)  
 92     spi_message_add_tail(&t, &m);   //添加spr傳遞到該隊列  
 93     return spidev_sync(spidev, &m); //同步讀寫  
 94 }  
 95   
 96 static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)  
 97 {  
 98     struct spidev_data  *spidev;  
 99     ssize_t status = 0;  
100   
101     if (count > bufsiz)  //傳輸數據大於緩沖區容量  
102         return -EMSGSIZE;  
103     spidev = filp->private_data; //從文件私有數據指針獲取spidev_data  
104     mutex_lock(&spidev->buf_lock);   //上互斥鎖  
105     status = spidev_sync_read(spidev, count);   //同步讀,返回傳輸數據長度  
106     if (status > 0) {  
107         unsigned long   missing;    //丟失的數據個數  
108         missing = copy_to_user(buf, spidev->buffer, status); //內核空間復制到用戶空間  
109         if (missing == status)      //丟失的數據個數等於要傳輸的數據個數  
110             status = -EFAULT;  
111         else  
112             status = status - missing;  //傳輸成功的數據個數  
113     }  
114     mutex_unlock(&spidev->buf_lock);//解互斥鎖  
115     return status;  //返回讀取成功的數據個數  
116 }  
117   
118 static ssize_t spidev_write(struct file *filp, const char __user *buf,size_t count, loff_t *f_pos)  
119 {  
120     struct spidev_data  *spidev;  
121     ssize_t         status = 0;  
122     unsigned long       missing;  
123   
124     if (count > bufsiz)  //傳輸數據大於緩沖區容量  
125         return -EMSGSIZE;  
126     spidev = filp->private_data; //從文件私有數據指針獲取spidev_data  
127     mutex_lock(&spidev->buf_lock);   //上互斥鎖  
128     missing = copy_from_user(spidev->buffer, buf, count);    //用戶空間復制到內核空間  
129     if (missing == 0) { //傳輸失敗個數為0  
130         status = spidev_sync_write(spidev, count);  //同步寫,返回傳輸數據長度  
131     }   
132     else  
133         status = -EFAULT;  
134     mutex_unlock(&spidev->buf_lock);//解互斥鎖  
135     return status;  //返回寫數據的實際個數  
136 }  
137   
138 static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers)  
139 {  
140     struct spi_message  msg;  
141     struct spi_transfer *k_xfers;  
142     struct spi_transfer *k_tmp;  
143     struct spi_ioc_transfer *u_tmp;  
144     unsigned    n, total;  
145     u8  *buf;  
146     int status = -EFAULT;  
147   
148     spi_message_init(&msg); //初始化spi消息(初始化spi傳遞事務隊列)  
149     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); //分配spi傳輸指針內存  
150     if (k_xfers == NULL)  
151         return -ENOMEM;  
152     buf = spidev->buffer;    //獲取spidev_data的緩沖區  
153     total = 0;  
154     //n=xfers為spi_ioc_transfer個數,u_tmp = u_xfers為要處理的spi_ioc_transfer指針  
155     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n;n--, k_tmp++, u_tmp++) {  
156         k_tmp->len = u_tmp->len;  //設置傳輸信息的長度  
157         total += k_tmp->len; //累加傳輸信息的總長度  
158         if (total > bufsiz) {    //信息量超過bufsiz緩沖區最大容量  
159             status = -EMSGSIZE;  
160             goto done;  
161         }  
162         if (u_tmp->rx_buf) { //接收緩沖區指針不為空  
163             k_tmp->rx_buf = buf; //緩沖區指向buf  
164             if (!access_ok(VERIFY_WRITE, (u8 __user *)(uintptr_t) u_tmp->rx_buf,u_tmp->len))  
165                 goto done;  
166         }  
167         if (u_tmp->tx_buf) { //發送緩沖區指針不為空  
168             k_tmp->tx_buf = buf; //緩沖區指針指向buf  
169             if (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len)) //用戶空間復制數據到buf  
170                 goto done;  
171         }  
172         buf += k_tmp->len;   //緩沖區指針移動一個傳輸信息的長度  
173         k_tmp->cs_change = !!u_tmp->cs_change;    //設置cs_change  
174         k_tmp->bits_per_word = u_tmp->bits_per_word;  //設置bits_per_word 一個字多少位  
175         k_tmp->delay_usecs = u_tmp->delay_usecs;  //設置delay_usecs 毫秒級延時  
176         k_tmp->speed_hz = u_tmp->speed_hz;    //設置speed_hz 速率  
177 #ifdef VERBOSE  
178         dev_dbg(&spidev->spi->dev,"  xfer len %zd %s%s%s%dbits %u usec %uHz\n",  
179             u_tmp->len,u_tmp->rx_buf ? "rx " : "",u_tmp->tx_buf ? "tx " : "",u_tmp->cs_change ? "cs " : "",  
180             u_tmp->bits_per_word ? : spidev->spi->bits_per_word,u_tmp->delay_usecs,u_tmp->speed_hz ? : spidev->spi->max_speed_hz);  
181 #endif  
182         spi_message_add_tail(k_tmp, &msg);  //添加spr傳遞到該隊列  
183     }  
184     //for循環的作用是將spi_ioc_transfer批量轉換為spi傳遞結構體spi_transfer,然后添加進spi傳遞事務隊列  
185     status = spidev_sync(spidev, &msg);     //同步讀寫  
186     if (status < 0)  
187         goto done;  
188     buf = spidev->buffer;    //獲取spidev_data緩沖區指針  
189     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {   //批量從內核空間復制spi_ioc_transfer到用戶空間  
190         if (u_tmp->rx_buf) { //判斷是否存在接收緩沖區  
191             if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) {  
192                 status = -EFAULT;  
193                 goto done;  
194             }  
195         }  
196         buf += u_tmp->len;   //buf指針位置調整指向下一個spi_ioc_transfer  
197     }  
198     status = total; //status等於實際傳輸的數據長度  
199 done:  
200     kfree(k_xfers); //釋放k_xfers  
201     return status;  //返回實際傳輸的數據長度  
202 }  
203   
204 static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
205 {  
206     int err = 0;  
207     int retval = 0;  
208     struct spidev_data  *spidev;  
209     struct spi_device   *spi;  
210     u32 tmp;  
211     unsigned    n_ioc;  
212     struct spi_ioc_transfer *ioc;  
213   
214     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)    //判斷控制命令的類型  
215         return -ENOTTY;  
216     if (_IOC_DIR(cmd) & _IOC_READ)  //判斷控制命令的方向是否為讀read  
217         err = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd));  //判斷傳輸數據大小  
218     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) //判斷控制命令的方向是否為寫write  
219         err = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd));   //判斷傳輸數據大小  
220     if (err)  
221         return -EFAULT;  
222   
223     spidev = filp->private_data; //從文件私有數據中獲取spidev_data  
224     spin_lock_irq(&spidev->spi_lock);    //上自旋鎖  
225     spi = spi_dev_get(spidev->spi);          //獲取spi設備  
226     spin_unlock_irq(&spidev->spi_lock);  //解自旋鎖  
227     if (spi == NULL)    //獲取spi設備失敗  
228         return -ESHUTDOWN;  //則返回錯誤  
229     mutex_lock(&spidev->buf_lock);   //上互斥鎖  
230       
231     switch (cmd) {  
232     case SPI_IOC_RD_MODE:   //設置spi讀模式  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
233         retval = __put_user(spi->mode & SPI_MODE_MASK,(__u8 __user *)arg);  
234         break;  
235     case SPI_IOC_RD_LSB_FIRST:  //設置spi讀最低有效位  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
236         retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,(__u8 __user *)arg);  
237         break;  
238     case SPI_IOC_RD_BITS_PER_WORD:  //設置spi讀每個字含多個個位  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
239         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);  
240         break;  
241     case SPI_IOC_RD_MAX_SPEED_HZ:   //設置spi讀最大速率  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
242         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);  
243         break;  
244     case SPI_IOC_WR_MODE:   //設置spi寫模式  
245         retval = __get_user(tmp, (u8 __user *)arg);  
246         if (retval == 0) {  
247             u8  save = spi->mode;    //獲取spi設備模式  
248   
249             if (tmp & ~SPI_MODE_MASK) {  
250                 retval = -EINVAL;  
251                 break;  
252             }  
253   
254             tmp |= spi->mode & ~SPI_MODE_MASK;  
255             spi->mode = (u8)tmp;  
256             retval = spi_setup(spi);    //配置spi設備  
257             if (retval < 0)  
258                 spi->mode = save;  
259             else  
260                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp);  
261         }  
262         break;  
263     case SPI_IOC_WR_LSB_FIRST:  //設置spi寫最低有效位  
264         retval = __get_user(tmp, (__u8 __user *)arg);  
265         if (retval == 0) {  
266             u8  save = spi->mode;    //獲取spi設備模式  
267   
268             if (tmp)  
269                 spi->mode |= SPI_LSB_FIRST;  
270             else  
271                 spi->mode &= ~SPI_LSB_FIRST;  
272             retval = spi_setup(spi);    //配置spi設備  
273             if (retval < 0)  
274                 spi->mode = save;  
275             else  
276                 dev_dbg(&spi->dev, "%csb first\n",tmp ? 'l' : 'm');  
277         }  
278         break;  
279     case SPI_IOC_WR_BITS_PER_WORD:  //設置spi寫每個字含多個個位  
280         retval = __get_user(tmp, (__u8 __user *)arg);   //用戶空間獲取數據  
281         if (retval == 0) {  
282             u8  save = spi->bits_per_word;   //獲取spi設備 每個字含多少位  
283   
284             spi->bits_per_word = tmp;    //更新新的spi設備 每個字含多少位  
285             retval = spi_setup(spi);    //配置spi設備  
286             if (retval < 0)  //配置失敗  
287                 spi->bits_per_word = save;   //還原spi設備 每個字含多少位  
288             else  
289                 dev_dbg(&spi->dev, "%d bits per word\n", tmp);  
290         }  
291         break;  
292     case SPI_IOC_WR_MAX_SPEED_HZ:       //設置spi寫最大速率  
293         retval = __get_user(tmp, (__u32 __user *)arg);  //用戶空間獲取數據  
294         if (retval == 0) {  
295             u32 save = spi->max_speed_hz;    //獲取spi設備最大速率  
296   
297             spi->max_speed_hz = tmp; //更新新的spi設備最大速率  
298             retval = spi_setup(spi);    //配置spi設備  
299             if (retval < 0)  //配置失敗  
300                 spi->max_speed_hz = save;    //還原spi設備最大速率  
301             else  
302                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);  
303         }  
304         break;  
305   
306     default:  
307         //命令必須為寫方向的命令,且傳輸數據必須是SPI_IOC_MESSAGE()修飾的命令  
308         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))|| _IOC_DIR(cmd) != _IOC_WRITE) {  
309             retval = -ENOTTY;  
310             break;  
311         }  
312   
313         tmp = _IOC_SIZE(cmd);   //計算傳輸數據大小  
314         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { //判斷是否為spi_ioc_transfer對齊  
315             retval = -EINVAL;  
316             break;  
317         }  
318         n_ioc = tmp / sizeof(struct spi_ioc_transfer);  //計算出spi_ioc_transfer數據的個數  
319         if (n_ioc == 0)  
320             break;  
321   
322         ioc = kmalloc(tmp, GFP_KERNEL); //分配spi_ioc_transfer指針ioc內存  
323         if (!ioc) {  
324             retval = -ENOMEM;  
325             break;  
326         }  
327         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {   //從用戶空間復制到內核空間  
328             kfree(ioc); //復制失敗則釋放ioc內存  
329             retval = -EFAULT;  
330             break;  
331         }  
332   
333         retval = spidev_message(spidev, ioc, n_ioc);    //spidev消息處理  
334         kfree(ioc); //釋放ioc內存  
335         break;  
336     }  
337   
338     mutex_unlock(&spidev->buf_lock); //解互斥鎖  
339     spi_dev_put(spi);   //增加spi設備的引用計數  
340     return retval;  
341 }  
342   
343 static int spidev_open(struct inode *inode, struct file *filp)  
344 {  
345     struct spidev_data  *spidev;  
346     int status = -ENXIO;  
347   
348     mutex_lock(&device_list_lock);  //上互斥鎖  
349     list_for_each_entry(spidev, &device_list, device_entry) {   //遍歷device_list  
350         if (spidev->devt == inode->i_rdev) {  //判斷設備號找到對應的設備  
351             status = 0; //設置狀態為0  
352             break;  
353         }  
354     }  
355     if (status == 0) {  //找得到對應的設備  
356         if (!spidev->buffer) {   //spidev_data緩沖區為空  
357             spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);    //則分配內存  
358             if (!spidev->buffer) {   //還空  
359                 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");  //申請內存失敗  
360                 status = -ENOMEM;  
361             }  
362         }  
363         if (status == 0) {  //找得到對應的設備  
364             spidev->users++; //spidev_data使用者計數++  
365             filp->private_data = spidev; //spidev_data放在文件的私有數據里  
366             nonseekable_open(inode, filp);  //設置文件的打開模式(文件讀寫指針不會跟隨讀寫操作移動)  
367         }  
368     }   
369     else  
370         pr_debug("spidev: nothing for minor %d\n", iminor(inode));  
371     mutex_unlock(&device_list_lock);    //接互斥鎖  
372     return status;  
373 }  
374   
375 static int spidev_release(struct inode *inode, struct file *filp)  
376 {  
377     struct spidev_data  *spidev;  
378     int status = 0;  
379   
380     mutex_lock(&device_list_lock);  
381     spidev = filp->private_data; //獲取spidev_data  
382     filp->private_data = NULL;       //清除文件的私有數據指針  
383     spidev->users--;             //使用者個數--  
384     if (!spidev->users) {    //如果使用者個數為0  
385         int     dofree;  
386         kfree(spidev->buffer);   //釋放spidev_data的緩沖區內存  
387         spidev->buffer = NULL;   //清除spidev_data緩沖區指針  
388         spin_lock_irq(&spidev->spi_lock);    //上自旋鎖  
389         dofree = (spidev->spi == NULL);  //判斷spi設備是否與spidev_data解綁了  
390         spin_unlock_irq(&spidev->spi_lock);  //解自旋鎖  
391         if (dofree)         //沒有捆綁的spi設備  
392             kfree(spidev);  //則是否spidev_data內存  
393     }  
394     mutex_unlock(&device_list_lock);  
395     return status;  
396 }  
397   
398 static const struct file_operations spidev_fops = {     //文件操作函數集  
399     .owner =    THIS_MODULE,  
400     .write =    spidev_write,       //寫write  
401     .read =     spidev_read,        //讀read  
402     .unlocked_ioctl = spidev_ioctl, //控制ioctl  
403     .open =     spidev_open,        //打開open  
404     .release =  spidev_release,     //釋放release  
405     .llseek =   no_llseek,          //文件指針移動 no_llseek表示沒有移動  
406 };  
407   
408 static struct class *spidev_class;  
409   
410 static int __devinit spidev_probe(struct spi_device *spi)  
411 {  
412     struct spidev_data  *spidev;  
413     int status;  
414     unsigned long   minor;  
415   
416     spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);  //分配spidev_data內存  
417     if (!spidev)  
418         return -ENOMEM;  
419     spidev->spi = spi;   //設置spidev_data->spi(spi設備)  
420     spin_lock_init(&spidev->spi_lock);  
421     mutex_init(&spidev->buf_lock);  
422     INIT_LIST_HEAD(&spidev->device_entry);   //初始化spidev_data入口鏈表  
423     mutex_lock(&device_list_lock);  
424     minor = find_first_zero_bit(minors, N_SPI_MINORS);  //查找次設備位圖分配次設備號  
425     if (minor < N_SPI_MINORS) {  
426         struct device *dev;  
427         spidev->devt = MKDEV(SPIDEV_MAJOR, minor);   //計算出設備號  
428         //創建設備/dev/spidev%d.%d(spidev總線號.片選號)  
429         dev = device_create(spidev_class, &spi->dev, spidev->devt,spidev, "spidev%d.%d",spi->master->bus_num, spi->chip_select);  
430         status = IS_ERR(dev) ? PTR_ERR(dev) : 0;  
431     }   
432     else {  
433         dev_dbg(&spi->dev, "no minor number available!\n");  
434         status = -ENODEV;  
435     }  
436     if (status == 0) {  //分配設備號成功  
437         set_bit(minor, minors); //更新次設備位圖  
438         list_add(&spidev->device_entry, &device_list);   //添加進設備鏈表  
439     }  
440     mutex_unlock(&device_list_lock);  
441   
442     if (status == 0)  
443         spi_set_drvdata(spi, spidev);   //spi->dev->p->driver_data=spidev   
444     else  
445         kfree(spidev);  
446   
447     return status;  
448 }  
449   
450 static int __devexit spidev_remove(struct spi_device *spi)  
451 {  
452     struct spidev_data  *spidev = spi_get_drvdata(spi);     //根據spi設備獲取spidev_data  
453     spin_lock_irq(&spidev->spi_lock);            //上自旋鎖  
454     spidev->spi = NULL;                              //清空spidev_data->spi指針  
455     spi_set_drvdata(spi, NULL);                     //spi->dev->p->driver_data=NULL  
456     spin_unlock_irq(&spidev->spi_lock);          //解自旋鎖  
457     mutex_lock(&device_list_lock);              //上互斥鎖  
458     list_del(&spidev->device_entry);             //刪除spidev_data入口鏈表  
459     device_destroy(spidev_class, spidev->devt);      //銷毀/dev/spidev%d.%d  
460     clear_bit(MINOR(spidev->devt), minors);          //清除次設備位圖對應位  
461     if (spidev->users == 0)                          //使用者個數為0  
462         kfree(spidev);                              //釋放spidev_data內存  
463     mutex_unlock(&device_list_lock);            //解互斥鎖  
464     return 0;  
465 }  
466   
467 static struct spi_driver spidev_spi_driver = {  //spi設備驅動  
468     .driver = {  
469         .name =     "spidev",  
470         .owner =    THIS_MODULE,  
471     },  
472     .probe =    spidev_probe,   //spidev的probe方法(當注冊了modalias域為"spidev"的spi設備或板級設備,則會調用probe方法)  
473     .remove =   __devexit_p(spidev_remove), //spidev的remove方法  
474 };  
475   
476 static int __init spidev_init(void)     //spidev接口初始化  
477 {  
478     int status;  
479     BUILD_BUG_ON(N_SPI_MINORS > 256);  
480     //注冊字符設備,主設備號SPIDEV_MAJOR=153,捆綁的設備操作函數集為spidev_fops  
481     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);  
482     if (status < 0)  
483         return status;  
484     spidev_class = class_create(THIS_MODULE, "spidev"); //創建設備類spidev_class  
485     if (IS_ERR(spidev_class)) {  
486         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);  
487         return PTR_ERR(spidev_class);  
488     }  
489     status = spi_register_driver(&spidev_spi_driver);   //注冊spi設備驅動spidev_spi_driver  
490     if (status < 0) {  
491         class_destroy(spidev_class);  
492         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);  
493     }  
494     return status;  
495 }  
496 module_init(spidev_init);   //聲明初始化入口  
497   
498 static void __exit spidev_exit(void)            //spidev接口銷毀  
499 {  
500     spi_unregister_driver(&spidev_spi_driver);  //注銷spi設備驅動spidev_spi_driver  
501     class_destroy(spidev_class);                //注銷設備類spidev_class  
502     unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); //注銷字符設備  
503 }  
504 module_exit(spidev_exit);   //聲明初始化出口  
505   
506 MODULE_AUTHOR("Andrea Paterniani, ");  
507 MODULE_DESCRIPTION("User mode SPI device interface");  
508 MODULE_LICENSE("GPL");  
509 MODULE_ALIAS("spi:spidev");

 2 spi_test.c

  1 #include   
  2 #include   
  3 #include   
  4 #include   
  5 #include   
  6 #include   
  7 #include   
  8 #include   
  9 #include   
 10   
 11 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))  
 12   
 13 static void pabort(const char *s)  
 14 {  
 15     perror(s);  
 16     abort();  
 17 }  
 18   
 19 static const char *device = "/dev/spidev1.1";  
 20 static uint8_t mode;  
 21 static uint8_t bits = 8;  
 22 static uint32_t speed = 500000;  
 23 static uint16_t delay;  
 24   
 25 static void transfer(int fd)  
 26 {  
 27     int ret;  
 28     uint8_t tx[] = {    //要發送的數據數組  
 29         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  
 30         0x40, 0x00, 0x00, 0x00, 0x00, 0x95,  
 31         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  
 32         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  
 33         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  
 34         0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,  
 35         0xF0, 0x0D,  
 36     };  
 37     uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的數據數據  
 38     struct spi_ioc_transfer tr = {  //聲明並初始化spi_ioc_transfer結構體  
 39         .tx_buf = (unsigned long)tx,  
 40         .rx_buf = (unsigned long)rx,  
 41         .len = ARRAY_SIZE(tx),  
 42         .delay_usecs = delay,  
 43         .speed_hz = speed,  
 44         .bits_per_word = bits,  
 45     };  
 46     //SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的數量  
 47     ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   //ioctl默認操作,傳輸數據  
 48     if (ret < 1)  
 49         pabort("can't send spi message");  
 50   
 51     for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收緩沖區  
 52         if (!(ret % 6))     //6個數據為一簇打印  
 53             puts("");  
 54         printf("%.2X ", rx[ret]);  
 55     }  
 56     puts("");  
 57 }  
 58   
 59 static void print_usage(const char *prog)   //參數錯誤則打印幫助信息  
 60 {  
 61     printf("Usage: %s [-DsbdlHOLC3]\n", prog);  
 62     puts("  -D --device   device to use (default /dev/spidev1.1)\n"  
 63          "  -s --speed    max speed (Hz)\n"  
 64          "  -d --delay    delay (usec)\n"  
 65          "  -b --bpw      bits per word \n"  
 66          "  -l --loop     loopback\n"  
 67          "  -H --cpha     clock phase\n"  
 68          "  -O --cpol     clock polarity\n"  
 69          "  -L --lsb      least significant bit first\n"  
 70          "  -C --cs-high  chip select active high\n"  
 71          "  -3 --3wire    SI/SO signals shared\n");  
 72     exit(1);  
 73 }  
 74   
 75 static void parse_opts(int argc, char *argv[])  
 76 {  
 77     while (1) {  
 78         static const struct option lopts[] = {  //參數命令表  
 79             { "device",  1, 0, 'D' },  
 80             { "speed",   1, 0, 's' },  
 81             { "delay",   1, 0, 'd' },  
 82             { "bpw",     1, 0, 'b' },  
 83             { "loop",    0, 0, 'l' },  
 84             { "cpha",    0, 0, 'H' },  
 85             { "cpol",    0, 0, 'O' },  
 86             { "lsb",     0, 0, 'L' },  
 87             { "cs-high", 0, 0, 'C' },  
 88             { "3wire",   0, 0, '3' },  
 89             { "no-cs",   0, 0, 'N' },  
 90             { "ready",   0, 0, 'R' },  
 91             { NULL, 0, 0, 0 },  
 92         };  
 93         int c;  
 94   
 95         c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);  
 96   
 97         if (c == -1)  
 98             break;  
 99   
100         switch (c) {  
101         case 'D':   //設備名  
102             device = optarg;  
103             break;  
104         case 's':   //速率  
105             speed = atoi(optarg);  
106             break;  
107         case 'd':   //延時時間  
108             delay = atoi(optarg);  
109             break;  
110         case 'b':   //每字含多少位  
111             bits = atoi(optarg);  
112             break;  
113         case 'l':   //回送模式  
114             mode |= SPI_LOOP;  
115             break;  
116         case 'H':   //時鍾相位  
117             mode |= SPI_CPHA;  
118             break;  
119         case 'O':   //時鍾極性  
120             mode |= SPI_CPOL;  
121             break;  
122         case 'L':   //lsb 最低有效位  
123             mode |= SPI_LSB_FIRST;  
124             break;  
125         case 'C':   //片選高電平  
126             mode |= SPI_CS_HIGH;  
127             break;  
128         case '3':   //3線傳輸模式  
129             mode |= SPI_3WIRE;  
130             break;  
131         case 'N':   //沒片選  
132             mode |= SPI_NO_CS;  
133             break;  
134         case 'R':   //從機拉低電平停止數據傳輸  
135             mode |= SPI_READY;  
136             break;  
137         default:    //錯誤的參數  
138             print_usage(argv[0]);  
139             break;  
140         }  
141     }  
142 }  
143   
144 int main(int argc, char *argv[])  
145 {  
146     int ret = 0;  
147     int fd;  
148   
149     parse_opts(argc, argv); //解析傳遞進來的參數  
150   
151     fd = open(device, O_RDWR);  //打開設備文件  
152     if (fd < 0)  
153         pabort("can't open device");  
154   
155     /* 
156      * spi mode //設置spi設備模式 
157      */  
158     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);    //寫模式  
159     if (ret == -1)  
160         pabort("can't set spi mode");  
161   
162     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);    //讀模式  
163     if (ret == -1)  
164         pabort("can't get spi mode");  
165   
166     /* 
167      * bits per word    //設置每個字含多少位 
168      */  
169     ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);   //寫 每個字含多少位  
170     if (ret == -1)  
171         pabort("can't set bits per word");  
172   
173     ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);   //讀 每個字含多少位  
174     if (ret == -1)  
175         pabort("can't get bits per word");  
176   
177     /* 
178      * max speed hz     //設置速率 
179      */  
180     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);   //寫速率  
181     if (ret == -1)  
182         pabort("can't set max speed hz");  
183   
184     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);   //讀速率  
185     if (ret == -1)  
186         pabort("can't get max speed hz");  
187     //打印模式,每字多少位和速率信息  
188     printf("spi mode: %d\n", mode);  
189     printf("bits per word: %d\n", bits);  
190     printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);  
191   
192     transfer(fd);   //傳輸測試  
193   
194     close(fd);  //關閉設備  
195   
196     return ret;  
197 }  

 3  ioctl的命令:

SPI_IOC_RD_MODE     //讀 模式  
SPI_IOC_RD_LSB_FIRST    //讀 LSB  
SPI_IOC_RD_BITS_PER_WORD    //讀 每字多少位  
SPI_IOC_RD_MAX_SPEED_HZ //讀 最大速率  
SPI_IOC_WR_MODE     //寫 模式  
SPI_IOC_WR_LSB_FIRST    //寫 LSB  
SPI_IOC_WR_BITS_PER_WORD    //寫 每字多少位  
SPI_IOC_WR_MAX_SPEED_HZ //寫 最大速率  
SPI_IOC_MESSAGE(n)      //傳輸n個數據包

 參考博文:http://dainh.blog.chinaunix.net/uid-26765074-id-3510490.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM