1.Linux主机驱动和外设驱动分离思想(I2C驱动里有)
SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√)。前面两个设备驱动搞明白了可以去看
2.教程中介绍:SPI函数接口(API):
简单介绍SPI协议,硬件原理(4412datasheet)
3.教程中介绍:SPI函数接口(API):
简单介绍SPI协议,硬件原理(4412datasheet)
- SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)
- SPI(rfid模块)的硬件基础知识(增加reset)
- SPI CLK管脚复用:Android4.0(wifi不能用)
- rfid的驱动配置:
- Device Drivers
- →SPI support
- →SPI_RC522
- can的驱动配置:
- Networking support
- →CAN bus subsystem support
- →CAN Device Drivers
- Platform CAN drivers with Netlink support(默认配置,不用动)
- CAN_MCP251X
设备注册:spi_board_info,spi_register_board_info
驱动注册函数和结构体:spi_register_driver/spi_unregister_driver,spi_driver
读写函数和结构体:spi_transfer和spi_message结构体,spi_async
1.驱动“设备注册,驱动注册,probe,数据下传,数据上传”的小结
虚拟平台:
①因为LED,蜂鸣器等等,因为这些驱动本身不是总线。所以都注册在虚拟平台总线上(platform_device)。
②然后platfrom_driver_register就是在驱动程序中使用了,注册时的platfrom_driver结构体中有name成员对应platform_device的名字。此结构当然还有probe,remove,suspend,resume等配套的功能接口。
③然后对LED来说,GPIO的操作基本是在probe中初始化。
④然后应用层如果需要调用,那么在probe里就需要注册杂项设备、字符设备等。
I2C:
①I2C的设备注册和平台注册类似,都是在arc/arm/mach-exynos/mach-itop4412.c中完成的
②和平台设备类似,I2C使用的函数不一样罢了,而且结构体也是i2c_driver了
③I2C对硬件的传输,使用i2c_transfer结合i2c_msg
④然后应用层如果需要调用,那么需要注册杂项设备,和虚拟平台类似。
SPI:
基本和I2C类似不同的是操作硬件的函数,spi_transfer要配置一下,然后传输用spi_sync。SPI让应用层调用使用字符设备。
2.设备-SPI设备注册一级设备注册之后的查询方法
配置SPI的内核之后可以用,查询到
[root@iTOP-4412]# cat sys/bus/spi/devices/spi2.0/modalias rc522
SPI_board_info参数
spi_board_info参数 .modalias = "rc522", //初始化设备的名称 .platform_data = NULL, .max_speed_hz = 10*1000*1000, //初始化传输速率 .bus_num = 2, //控制器编号 .chip_select = 0, //控制器片选的编号 .mode = SPI_MODE_0, //spi的模式 .controller_data = &spi2_csi[0], //片选IO的信息
spi2_board_info设备描述结构体,设备注册函数spi_register_board_info
增加一个spi设备my_rc522,然后去掉rfid和can驱动
/* add by cym 20141222 for RC522 RFID */ #ifdef CONFIG_SPI_RC522 { .modalias = "rc522", .platform_data = NULL, .max_speed_hz = 10*1000*1000, .bus_num = 2, .chip_select = 0, .mode = SPI_MODE_0, .controller_data = &spi2_csi[0], } #endif /* end add */ /* add by ct 2018825 */ { .modalias = "my_rc522", .platform_data = NULL, .max_speed_hz = 10*1000*1000, .bus_num = 2, .chip_select = 0, .mode = SPI_MODE_0, .controller_data = &spi2_csi[0], } /* end add */
cat sys/bus/spi/devices/spi2.0/modalias
rfid的设备名称my_rc522
3.驱动-spi驱动注册和卸载。I2C设备初始化完成-进入probe函数。(不能加载wifi驱动)
#include <linux/init.h> #include <linux/module.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/list.h> #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/compat.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> #include <asm/uaccess.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/delay.h> static int __devinit my_rc522_probe(struct spi_device *spi) { /* reset */ printk(KERN_EMERG "my_rc522_probe! "); return 0; } static int __devexit my_rc522_remove(struct spi_device *spi) { printk(KERN_EMERG "my_rc522_remove! "); return 0; } static struct spi_driver my_rc522_spi_driver = { .driver = { .name = "my_rc522", .owner = THIS_MODULE, }, .probe = my_rc522_probe, .remove = __devexit_p(my_rc522_remove), }; static int __init my_rc522_init(void) { spi_register_driver(&my_rc522_spi_driver); return 0; } static void __exit my_rc522_exit(void) { spi_unregister_driver(&my_rc522_spi_driver); } module_init(my_rc522_init); module_exit(my_rc522_exit); MODULE_AUTHOR("topeet: ct"); MODULE_LICENSE("GPL");
4.驱动-spi数据的传输(rfid模块,不能加载wifi驱动)
- 1.本节实验需要RFID的硬件模块
- 2.1平台文件中RC522的设备名称直接改为my_rc522
- 2.2需要配置rfid对应的menuconfig
- 2.3 drivers/spi/Makefile中注释掉rc522.c文件的编译
- 3.从rc522驱动中提取spi传输的核心代码
- 4.直接在probe中做复位,读,写测试
- 写:rc522_write→rc522_sync_write→rc522_sync→spi_async
- 读:rc522_read→rc522_sync_read→rc522_sync→spi_async
my_rc522
#include <linux/init.h> #include <linux/module.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/list.h> #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/compat.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> #include <asm/uaccess.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/delay.h> #include "spidev_test.h" #include "spidev.h" struct spi_device *my_spi; #define RC522_RESET_PIN EXYNOS4_GPK1(0) void my_rc522_reset() { //printk("************************ %s ", __FUNCTION__); if(gpio_request_one(RC522_RESET_PIN, GPIOF_OUT_INIT_HIGH, "RC522_RESET")) pr_err("failed to request GPK1_0 for RC522 reset control "); s3c_gpio_setpull(RC522_RESET_PIN, S3C_GPIO_PULL_UP); gpio_set_value(RC522_RESET_PIN, 0); mdelay(5); gpio_set_value(RC522_RESET_PIN, 1); gpio_free(RC522_RESET_PIN); } static int write_test(unsigned char *buffer, int len) { int status; struct spi_transfer t = { .tx_buf = buffer, .len = len, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); DECLARE_COMPLETION_ONSTACK(done); m.complete = complete; m.context = &done; printk("spi_async send begin! "); status = spi_async(my_spi,&m); if(status == 0){ wait_for_completion(&done); status = m.status; if (status == 0) status = m.actual_length; } return status; } static int read_test(unsigned char *buffer, int len) { int status; struct spi_transfer t = { .rx_buf = buffer, .len = len, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); DECLARE_COMPLETION_ONSTACK(done); m.complete = complete; m.context = &done; printk("spi_async read begin! "); status = spi_async(my_spi,&m); if(status == 0){ wait_for_completion(&done); status = m.status; if (status == 0) status = m.actual_length; } return status; } static unsigned char ReadRawRC(int addr) { int ret; unsigned char ReData; unsigned char Address; Address = (unsigned char)addr << 1; Address |= (1 << 7); Address &= ~(1 << 0); ret = write_test(&Address, 1); if (ret < 0) printk("spi:SPI Write error "); udelay(100); ret = read_test(&ReData, 1); if (ret < 0) printk("spi:SPI Read error "); return ReData; } static int WriteRawRC(int addr, int data) { int ret; unsigned char TxBuf[2]; //bit7:MSB=0,bit6~1:addr,bit0:RFU=0 TxBuf[0] = ((unsigned char)addr << 1)&0x7E; //TxBuf[0] &= 0x7E; TxBuf[1] = (unsigned char)data; ret = write_test(TxBuf, 2); if (ret < 0) printk("spi:SPI Write error "); udelay(10); return ret; } static int rc522_init() { int ret; char version = 0; //reset WriteRawRC(CommandReg, PCD_RESETPHASE); udelay(10); WriteRawRC(ModeReg, 0x3D); WriteRawRC(TReloadRegL, 30); WriteRawRC(TReloadRegH, 0); WriteRawRC(TModeReg, 0x8D); WriteRawRC(TPrescalerReg, 0x3E); version = ReadRawRC(VersionReg); printk("Chip Version: 0x%x ", version); return 0; } static int __devinit my_rc522_probe(struct spi_device *spi) { printk("my_rc522_probe! "); /* reset */ my_rc522_reset(); my_spi = spi; rc522_init(); return 0; } static int __devexit my_rc522_remove(struct spi_device *spi) { printk("my_rc522_remove! "); return 0; } static struct spi_driver my_rc522_spi_driver = { .driver = { .name = "my_rc522", .owner = THIS_MODULE, }, .probe = my_rc522_probe, .remove = __devexit_p(my_rc522_remove), /* NOTE: suspend/resume methods are not necessary here. * We don't do anything except pass the requests to/from * the underlying controller. The refrigerator handles * most issues; the controller driver handles the rest. */ }; static int __init my_rc522_init(void) { spi_register_driver(&my_rc522_spi_driver); return 0; } static void __exit my_rc522_exit(void) { spi_unregister_driver(&my_rc522_spi_driver); } module_exit(my_rc522_exit); module_init(my_rc522_init); MODULE_AUTHOR("topeet: rty"); MODULE_LICENSE("GPL");
spidev.h
/* * include/linux/spi/spidev.h * * Copyright (C) 2006 SWAPP * Andrea Paterniani <a.paterniani@swapp-eng.it> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef SPIDEV_H #define SPIDEV_H #include <linux/types.h> /* User space versions of kernel symbols for SPI clocking modes, * matching <linux/spi/spi.h> */ #define SPI_CPHA 0x01 #define SPI_CPOL 0x02 #define SPI_MODE_0 (0|0) #define SPI_MODE_1 (0|SPI_CPHA) #define SPI_MODE_2 (SPI_CPOL|0) #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) #define SPI_CS_HIGH 0x04 #define SPI_LSB_FIRST 0x08 #define SPI_3WIRE 0x10 #define SPI_LOOP 0x20 #define SPI_NO_CS 0x40 #define SPI_READY 0x80 /*---------------------------------------------------------------------------*/ /* IOCTL commands */ #define SPI_IOC_MAGIC 'k' /** * struct spi_ioc_transfer - describes a single SPI transfer * @tx_buf: Holds pointer to userspace buffer with transmit data, or null. * If no data is provided, zeroes are shifted out. * @rx_buf: Holds pointer to userspace buffer for receive data, or null. * @len: Length of tx and rx buffers, in bytes. * @speed_hz: Temporary override of the device's bitrate. * @bits_per_word: Temporary override of the device's wordsize. * @delay_usecs: If nonzero, how long to delay after the last bit transfer * before optionally deselecting the device before the next transfer. * @cs_change: True to deselect device before starting the next transfer. * * This structure is mapped directly to the kernel spi_transfer structure; * the fields have the same meanings, except of course that the pointers * are in a different address space (and may be of different sizes in some * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel). * Zero-initialize the structure, including currently unused fields, to * accommodate potential future updates. * * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync(). * Pass it an array of related transfers, they'll execute together. * Each transfer may be half duplex (either direction) or full duplex. * * struct spi_ioc_transfer mesg[4]; * ... * status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg); * * So for example one transfer might send a nine bit command (right aligned * in a 16-bit word), the next could read a block of 8-bit data before * terminating that command by temporarily deselecting the chip; the next * could send a different nine bit command (re-selecting the chip), and the * last transfer might write some register values. */ struct spi_ioc_transfer { __u64 tx_buf; __u64 rx_buf; __u32 len; __u32 speed_hz; __u16 delay_usecs; __u8 bits_per_word; __u8 cs_change; __u32 pad; /* If the contents of 'struct spi_ioc_transfer' ever change * incompatibly, then the ioctl number (currently 0) must change; * ioctls with constant size fields get a bit more in the way of * error checking than ones (like this) where that field varies. * * NOTE: struct layout is the same in 64bit and 32bit userspace. */ }; /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */ #define SPI_MSGSIZE(N) ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) /* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) /* Read / Write SPI bit justification */ #define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8) #define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8) /* Read / Write SPI device word length (1..N) */ #define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8) #define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8) /* Read / Write SPI device default max speed hz */ #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) #endif /* SPIDEV_H */
spidev_test.h
#define MAXRLEN 18 #define MIN_STRENGTH 228 //******************************************************************/ // RC522 FIFO���ȶ��� / //******************************************************************/ #define DEF_FIFO_LENGTH 64 //FIFO size=64byte //******************************************************************/ // RC522������ / //******************************************************************/ #define PCD_IDLE 0x00 //ȡ����ǰ���� #define PCD_AUTHENT 0x0E //��֤��Կ #define PCD_RECEIVE 0x08 //�������� #define PCD_TRANSMIT 0x04 //�������� #define PCD_TRANSCEIVE 0x0C //���Ͳ��������� #define PCD_RESETPHASE 0x0F //��λ #define PCD_CALCCRC 0x03 //CRC���� //******************************************************************/ // Mifare_One��Ƭ������ */ //******************************************************************/ #define PICC_REQIDL 0x26 //Ѱ��������δ��������״̬ #define PICC_REQALL 0x52 //Ѱ��������ȫ���� #define PICC_ANTICOLL1 0x93 //����ײ #define PICC_ANTICOLL2 0x95 //����ײ #define PICC_AUTHENT1A 0x60 //��֤A��Կ #define PICC_AUTHENT1B 0x61 //��֤B��Կ #define PICC_READ 0x30 //���� #define PICC_WRITE 0xA0 //д�� #define PICC_DECREMENT 0xC0 //�ۿ� #define PICC_INCREMENT 0xC1 //��ֵ #define PICC_RESTORE 0xC2 //�������ݵ������� #define PICC_TRANSFER 0xB0 //���滺���������� #define PICC_HALT 0x50 //���� //******************************************************************/ // MF522�Ĵ������� / //******************************************************************/ // PAGE 0 #define RFU00 0x00 #define CommandReg 0x01 #define ComIEnReg 0x02 #define DivlEnReg 0x03 #define ComIrqReg 0x04 #define DivIrqReg 0x05 #define ErrorReg 0x06 #define Status1Reg 0x07 #define Status2Reg 0x08 #define FIFODataReg 0x09 #define FIFOLevelReg 0x0A #define WaterLevelReg 0x0B #define ControlReg 0x0C #define BitFramingReg 0x0D #define CollReg 0x0E #define RFU0F 0x0F // PAGE 1 #define RFU10 0x10 #define ModeReg 0x11 #define TxModeReg 0x12 #define RxModeReg 0x13 #define TxControlReg 0x14 #define TxASKReg 0x15 #define TxSelReg 0x16 #define RxSelReg 0x17 #define RxThresholdReg 0x18 #define DemodReg 0x19 #define RFU1A 0x1A #define RFU1B 0x1B #define MifareReg 0x1C #define RFU1D 0x1D #define RFU1E 0x1E #define SerialSpeedReg 0x1F // PAGE 2 #define RFU20 0x20 #define CRCResultRegM 0x21 #define CRCResultRegL 0x22 #define RFU23 0x23 #define ModWidthReg 0x24 #define RFU25 0x25 #define RFCfgReg 0x26 #define GsNReg 0x27 #define CWGsCfgReg 0x28 #define ModGsCfgReg 0x29 #define TModeReg 0x2A #define TPrescalerReg 0x2B #define TReloadRegH 0x2C #define TReloadRegL 0x2D #define TCounterValueRegH 0x2E #define TCounterValueRegL 0x2F // PAGE 3 #define RFU30 0x30 #define TestSel1Reg 0x31 #define TestSel2Reg 0x32 #define TestPinEnReg 0x33 #define TestPinValueReg 0x34 #define TestBusReg 0x35 #define AutoTestReg 0x36 #define VersionReg 0x37 #define AnalogTestReg 0x38 #define TestDAC1Reg 0x39 #define TestDAC2Reg 0x3A #define TestADCReg 0x3B #define RFU3C 0x3C #define RFU3D 0x3D #define RFU3E 0x3E #define RFU3F 0x3F //******************************************************************/ // RC522ͨѶ���ش������ / //******************************************************************/ #define MI_ERR 0xFE //#define MI_ERR //(-2) // Mifare Error Codes // Each function returns a status value, which corresponds to the // mifare error codes. #define MI_OK 0 #define MI_CHK_OK 0 #define MI_CRC_ZERO 0 #define MI_CRC_NOTZERO 1 #define MI_NOTAGERR 0xFF #define MI_CHK_FAILED 0xFF #define MI_CRCERR 0xFE #define MI_CHK_COMPERR 0xFE #define MI_EMPTY 0xFD #define MI_AUTHERR 0xFC #define MI_PARITYERR 0xFB #define MI_CODEERR 0xFA #define MI_SERNRERR 0xF8 #define MI_KEYERR 0xF7 #define MI_NOTAUTHERR 0xF6 #define MI_BITCOUNTERR 0xF5 #define MI_BYTECOUNTERR 0xF4 #define MI_IDLE 0xF3 #define MI_TRANSERR 0xF2 #define MI_WRITEERR 0xF1 #define MI_INCRERR 0xF0 #define MI_DECRERR 0xEF #define MI_READERR 0xEE #define MI_OVFLERR 0xED #define MI_POLLING 0xEC #define MI_FRAMINGERR 0xEB #define MI_ACCESSERR 0xEA #define MI_UNKNOWN_COMMAND 0xE9 #define MI_COLLERR 0xE8 #define MI_RESETERR 0xE7 #define MI_INITERR 0xE7 #define MI_INTERFACEERR 0xE7 #define MI_ACCESSTIMEOUT 0xE5 #define MI_NOBITWISEANTICOLL 0xE4 #define MI_QUIT 0xE2 #define MI_RECBUF_OVERFLOW 0xCF #define MI_SENDBYTENR 0xCE #define MI_SENDBUF_OVERFLOW 0xCC #define MI_BAUDRATE_NOT_SUPPORTED 0xCB #define MI_SAME_BAUDRATE_REQUIRED 0xCA #define MI_WRONG_PARAMETER_VALUE 0xC5 #define MI_BREAK 0x9E #define MI_NY_IMPLEMENTED 0x9D #define MI_NO_MFRC 0x9C #define MI_MFRC_NOTAUTH 0x9B #define MI_WRONG_DES_MODE 0x9A #define MI_HOST_AUTH_FAILED 0x99 #define MI_WRONG_LOAD_MODE 0x97 #define MI_WRONG_DESKEY 0x96 #define MI_MKLOAD_FAILED 0x95 #define MI_FIFOERR 0x94 #define MI_WRONG_ADDR 0x93 #define MI_DESKEYLOAD_FAILED 0x92 #define MI_WRONG_SEL_CNT 0x8F #define MI_RC531_WRONG_READVALUE 0x8E //LI ADDED 09-4-24 #define MI_WRONG_TEST_MODE 0x8C #define MI_TEST_FAILED 0x8B #define MI_TOC_ERROR 0x8A #define MI_COMM_ABORT 0x89 #define MI_INVALID_BASE 0x88 #define MI_MFRC_RESET 0x87 #define MI_WRONG_VALUE 0x86 #define MI_VALERR 0x85
5.Linux-spi利用字符驱动完成应用层对spi的读和写
驱动:
#include <linux/init.h> #include <linux/module.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/list.h> #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/compat.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> #include <asm/uaccess.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/delay.h> #include <linux/miscdevice.h> struct spi_device *my_spi; #define RC522_RESET_PIN EXYNOS4_GPK1(0) void my_rc522_reset() { //printk("************************ %s ", __FUNCTION__); if(gpio_request_one(RC522_RESET_PIN, GPIOF_OUT_INIT_HIGH, "RC522_RESET")) pr_err("failed to request GPK1_0 for RC522 reset control "); s3c_gpio_setpull(RC522_RESET_PIN, S3C_GPIO_PULL_UP); gpio_set_value(RC522_RESET_PIN, 0); mdelay(5); gpio_set_value(RC522_RESET_PIN, 1); gpio_free(RC522_RESET_PIN); } //static ssize_t rc522_write(unsigned char *buffer, int len) static ssize_t rc522_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int status; unsigned char tx_buf[2]; status = copy_from_user(tx_buf,buf,count); struct spi_transfer t = { .tx_buf = tx_buf, .len = count, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); DECLARE_COMPLETION_ONSTACK(done); m.complete = complete; m.context = &done; printk("spi_async send begin! "); status = spi_async(my_spi,&m); if(status == 0){ wait_for_completion(&done); status = m.status; if (status == 0) status = m.actual_length; } return status; } //static ssize_t rc522_read(unsigned char *buffer, int len) static ssize_t rc522_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int status; unsigned char *rx_buf; struct spi_transfer t = { .rx_buf = &rx_buf, .len = count, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); DECLARE_COMPLETION_ONSTACK(done); m.complete = complete; m.context = &done; printk("spi_async read begin! "); status = spi_async(my_spi,&m); if(status == 0){ wait_for_completion(&done); status = m.status; if (status == 0) status = m.actual_length; } status = copy_to_user(buf,&rx_buf,status); return status; } int rc522_open(struct inode *inode,struct file *filp) { return 0; } static struct file_operations rc522_ops = { .owner = THIS_MODULE, .open = rc522_open, .read = rc522_read, .write = rc522_write, }; static struct miscdevice rc522_dev = { .minor = MISC_DYNAMIC_MINOR, .fops = &rc522_ops, .name = "rc522", }; static int __devinit my_rc522_probe(struct spi_device *spi) { printk("my_rc522_probe! "); /* reset */ my_rc522_reset(); my_spi = spi; misc_register(&rc522_dev); return 0; } static int __devexit my_rc522_remove(struct spi_device *spi) { printk("my_rc522_remove! "); misc_deregister(&rc522_dev); return 0; } static struct spi_driver my_rc522_spi_driver = { .driver = { .name = "my_rc522", .owner = THIS_MODULE, }, .probe = my_rc522_probe, .remove = __devexit_p(my_rc522_remove), /* NOTE: suspend/resume methods are not necessary here. * We don't do anything except pass the requests to/from * the underlying controller. The refrigerator handles * most issues; the controller driver handles the rest. */ }; static int __init my_rc522_init(void) { spi_register_driver(&my_rc522_spi_driver); return 0; } static void __exit my_rc522_exit(void) { spi_unregister_driver(&my_rc522_spi_driver); } module_exit(my_rc522_exit); module_init(my_rc522_init); MODULE_AUTHOR("topeet: rty"); MODULE_LICENSE("GPL");
app:
/* * SPI testing utility (using spidev driver) * * Copyright (c) 2007 MontaVista Software, Inc. * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * Cross-compile with cross-gcc -I/path/to/cross-kernel/include */ #include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/types.h> #include "spidev.h" #include "spidev_test.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static void pabort(const char *s) { perror(s); abort(); } static const char *device = "/dev/rc522"; static uint8_t mode; static uint8_t bits = 8; static uint32_t speed = 400 * 1000;//500000; static uint16_t delay; int g_SPI_Fd = 0; unsigned char UID[5], Temp[4]; /******************************************* �������ƣ�tochar �� �ܣ�����16���ƺ��� �� ����id ����ֵ ���� ********************************************/ #if 0 void tochar(unsigned char id) { switch(id) { case 0x00:printf("00");break; case 0x01:printf("01");break; case 0x02:printf("02");break; case 0x03:printf("03");break; case 0x04:printf("04");break; case 0x05:printf("05");break; case 0x06:printf("06");break; case 0x07:printf("07");break; case 0x08:printf("08");break; case 0x09:printf("09");break; case 0x0a:printf("0a");break; case 0x0b:printf("0b");break; case 0x0c:printf("0c");break; case 0x0d:printf("0d");break; case 0x0e:printf("0e");break; case 0x0f:printf("0f");break; case 0x10:printf("10");break; case 0x11:printf("11");break; case 0x12:printf("12");break; case 0x13:printf("13");break; case 0x14:printf("14");break; case 0x15:printf("15");break; case 0x16:printf("16");break; case 0x17:printf("17");break; case 0x18:printf("18");break; case 0x19:printf("19");break; case 0x1a:printf("1a");break; case 0x1b:printf("1b");break; case 0x1c:printf("1c");break; case 0x1d:printf("1d");break; case 0x1e:printf("1e");break; case 0x1f:printf("1f");break; case 0x20:printf("20");break; case 0x21:printf("21");break; case 0x22:printf("22");break; case 0x23:printf("23");break; case 0x24:printf("24");break; case 0x25:printf("25");break; case 0x26:printf("26");break; case 0x27:printf("27");break; case 0x28:printf("28");break; case 0x29:printf("29");break; case 0x2a:printf("2a");break; case 0x2b:printf("2b");break; case 0x2c:printf("2c");break; case 0x2d:printf("2d");break; case 0x2e:printf("2e");break; case 0x2f:printf("2f");break; case 0x30:printf("30");break; case 0x31:printf("31");break; case 0x32:printf("32");break; case 0x33:printf("33");break; case 0x34:printf("34");break; case 0x35:printf("35");break; case 0x36:printf("36");break; case 0x37:printf("37");break; case 0x38:printf("38");break; case 0x39:printf("39");break; case 0x3a:printf("3a");break; case 0x3b:printf("3b");break; case 0x3c:printf("3c");break; case 0x3d:printf("3d");break; case 0x3e:printf("3e");break; case 0x3f:printf("3f");break; case 0x40:printf("40");break; case 0x41:printf("41");break; case 0x42:printf("42");break; case 0x43:printf("43");break; case 0x44:printf("44");break; case 0x45:printf("45");break; case 0x46:printf("46");break; case 0x47:printf("47");break; case 0x48:printf("48");break; case 0x49:printf("49");break; case 0x4a:printf("4a");break; case 0x4b:printf("4b");break; case 0x4c:printf("4c");break; case 0x4d:printf("4d");break; case 0x4e:printf("4e");break; case 0x4f:printf("4f");break; case 0x50:printf("50");break; case 0x51:printf("51");break; case 0x52:printf("52");break; case 0x53:printf("53");break; case 0x54:printf("54");break; case 0x55:printf("55");break; case 0x56:printf("56");break; case 0x57:printf("57");break; case 0x58:printf("58");break; case 0x59:printf("59");break; case 0x5a:printf("5a");break; case 0x5b:printf("5b");break; case 0x5c:printf("5c");break; case 0x5d:printf("5d");break; case 0x5e:printf("5e");break; case 0x5f:printf("5f");break; case 0x60:printf("60");break; case 0x61:printf("61");break; case 0x62:printf("62");break; case 0x63:printf("63");break; case 0x64:printf("64");break; case 0x65:printf("65");break; case 0x66:printf("66");break; case 0x67:printf("67");break; case 0x68:printf("68");break; case 0x69:printf("69");break; case 0x6a:printf("6a");break; case 0x6b:printf("6b");break; case 0x6c:printf("6c");break; case 0x6d:printf("6d");break; case 0x6e:printf("6e");break; case 0x6f:printf("6f");break; case 0x70:printf("70");break; case 0x71:printf("71");break; case 0x72:printf("72");break; case 0x73:printf("73");break; case 0x74:printf("74");break; case 0x75:printf("75");break; case 0x76:printf("76");break; case 0x77:printf("77");break; case 0x78:printf("78");break; case 0x79:printf("79");break; case 0x7a:printf("7a");break; case 0x7b:printf("7b");break; case 0x7c:printf("7c");break; case 0x7d:printf("7d");break; case 0x7e:printf("7e");break; case 0x7f:printf("7f");break; case 0x80:printf("80");break; case 0x81:printf("81");break; case 0x82:printf("82");break; case 0x83:printf("83");break; case 0x84:printf("84");break; case 0x85:printf("85");break; case 0x86:printf("86");break; case 0x87:printf("87");break; case 0x88:printf("88");break; case 0x89:printf("89");break; case 0x8a:printf("8a");break; case 0x8b:printf("8b");break; case 0x8c:printf("8c");break; case 0x8d:printf("8d");break; case 0x8e:printf("8e");break; case 0x8f:printf("8f");break; case 0x90:printf("90");break; case 0x91:printf("91");break; case 0x92:printf("92");break; case 0x93:printf("93");break; case 0x94:printf("94");break; case 0x95:printf("95");break; case 0x96:printf("96");break; case 0x97:printf("97");break; case 0x98:printf("98");break; case 0x99:printf("99");break; case 0x9a:printf("9a");break; case 0x9b:printf("9b");break; case 0x9c:printf("9c");break; case 0x9d:printf("9d");break; case 0x9e:printf("9e");break; case 0x9f:printf("9f");break; case 0xa0:printf("a0");break; case 0xa1:printf("a1");break; case 0xa2:printf("a2");break; case 0xa3:printf("a3");break; case 0xa4:printf("a4");break; case 0xa5:printf("a5");break; case 0xa6:printf("a6");break; case 0xa7:printf("a7");break; case 0xa8:printf("a8");break; case 0xa9:printf("a9");break; case 0xaa:printf("aa");break; case 0xab:printf("ab");break; case 0xac:printf("ac");break; case 0xad:printf("ad");break; case 0xae:printf("ae");break; case 0xaf:printf("af");break; case 0xb0:printf("b0");break; case 0xb1:printf("b1");break; case 0xb2:printf("b2");break; case 0xb3:printf("b3");break; case 0xb4:printf("b4");break; case 0xb5:printf("b5");break; case 0xb6:printf("b6");break; case 0xb7:printf("b7");break; case 0xb8:printf("b8");break; case 0xb9:printf("b9");break; case 0xba:printf("ba");break; case 0xbb:printf("bb");break; case 0xbc:printf("bc");break; case 0xbd:printf("bd");break; case 0xbe:printf("be");break; case 0xbf:printf("bf");break; case 0xc0:printf("c0");break; case 0xc1:printf("c1");break; case 0xc2:printf("c2");break; case 0xc3:printf("c3");break; case 0xc4:printf("c4");break; case 0xc5:printf("c5");break; case 0xc6:printf("c6");break; case 0xc7:printf("c7");break; case 0xc8:printf("c8");break; case 0xc9:printf("c9");break; case 0xca:printf("ca");break; case 0xcb:printf("cb");break; case 0xcc:printf("cc");break; case 0xcd:printf("cd");break; case 0xce:printf("ce");break; case 0xcf:printf("cf");break; case 0xd0:printf("d0");break; case 0xd1:printf("d1");break; case 0xd2:printf("d2");break; case 0xd3:printf("d3");break; case 0xd4:printf("d4");break; case 0xd5:printf("d5");break; case 0xd6:printf("d6");break; case 0xd7:printf("d7");break; case 0xd8:printf("d8");break; case 0xd9:printf("d9");break; case 0xda:printf("da");break; case 0xdb:printf("db");break; case 0xdc:printf("dc");break; case 0xdd:printf("dd");break; case 0xde:printf("de");break; case 0xdf:printf("df");break; case 0xe0:printf("e0");break; case 0xe1:printf("e1");break; case 0xe2:printf("e2");break; case 0xe3:printf("e3");break; case 0xe4:printf("e4");break; case 0xe5:printf("e5");break; case 0xe6:printf("e6");break; case 0xe7:printf("e7");break; case 0xe8:printf("e8");break; case 0xe9:printf("e9");break; case 0xea:printf("ea");break; case 0xeb:printf("eb");break; case 0xec:printf("ec");break; case 0xed:printf("ed");break; case 0xee:printf("ee");break; case 0xef:printf("ef");break; case 0xf0:printf("f0");break; case 0xf1:printf("f1");break; case 0xf2:printf("f2");break; case 0xf3:printf("f3");break; case 0xf4:printf("f4");break; case 0xf5:printf("f5");break; case 0xf6:printf("f6");break; case 0xf7:printf("f7");break; case 0xf8:printf("f8");break; case 0xf9:printf("f9");break; case 0xfa:printf("fa");break; case 0xfb:printf("fb");break; case 0xfc:printf("fc");break; case 0xfd:printf("fd");break; case 0xfe:printf("fe");break; case 0xff:printf("ff");break; default: ; } } #endif int WriteRawRC(int addr, int data) { int ret; int fd = g_SPI_Fd; unsigned char TxBuf[2]; //bit7:MSB=0,bit6~1:addr,bit0:RFU=0 TxBuf[0] = ((unsigned char)addr << 1)&0x7E; //TxBuf[0] &= 0x7E; TxBuf[1] = (unsigned char)data; ret = write(fd, TxBuf, 2); if (ret < 0) printf("spi:SPI Write error "); usleep(10); return ret; } unsigned char ReadRawRC(int addr) { int ret; int fd = g_SPI_Fd; unsigned char ReData; unsigned char Address; Address = (unsigned char)addr << 1; Address |= (1 << 7); Address &= ~(1 << 0); ret = write(fd, &Address, 1); if (ret < 0) printf("spi:SPI Write error "); usleep(100); ret = read(fd, &ReData, 1); if (ret < 0) printf("spi:SPI Read error "); return ReData; } void SetBitMask(unsigned char reg,unsigned char mask) { char tmp = 0x0; tmp = ReadRawRC(reg) | mask; WriteRawRC(reg,tmp | mask); } //******************************************************************/ //�� �ܣ���RC522�Ĵ���λ //����˵����reg[IN]:�Ĵ�����ַ // mask[IN]:��λֵ //******************************************************************/ void ClearBitMask(unsigned char reg, unsigned char mask) { char tmp = 0x0; tmp = ReadRawRC(reg)&(~mask); WriteRawRC(reg, tmp); // clear bit mask } int rc522_init() { int ret; char version = 0; //reset WriteRawRC(CommandReg, PCD_RESETPHASE); usleep(10); WriteRawRC(ModeReg, 0x3D); WriteRawRC(TReloadRegL, 30); WriteRawRC(TReloadRegH, 0); WriteRawRC(TModeReg, 0x8D); WriteRawRC(TPrescalerReg, 0x3E); version = ReadRawRC(VersionReg); printf("Chip Version: 0x%x ", version); usleep(50000); return 0; } void PcdAntennaOn() { unsigned char i; WriteRawRC(TxASKReg, 0x40); usleep(20); i = ReadRawRC(TxControlReg); if(!(i&0x03)) SetBitMask(TxControlReg, 0x03); i = ReadRawRC(TxASKReg); } static void print_usage(const char *prog) { printf("Usage: %s [-DsbdlHOLC3] ", prog); puts(" -D --device device to use (default /dev/spidev1.1) " " -s --speed max speed (Hz) " " -d --delay delay (usec) " " -b --bpw bits per word " " -l --loop loopback " " -H --cpha clock phase " " -O --cpol clock polarity " " -L --lsb least significant bit first " " -C --cs-high chip select active high " " -3 --3wire SI/SO signals shared "); exit(1); } static void parse_opts(int argc, char *argv[]) { while (1) { static const struct option lopts[] = { { "device", 1, 0, 'D' }, { "speed", 1, 0, 's' }, { "delay", 1, 0, 'd' }, { "bpw", 1, 0, 'b' }, { "loop", 0, 0, 'l' }, { "cpha", 0, 0, 'H' }, { "cpol", 0, 0, 'O' }, { "lsb", 0, 0, 'L' }, { "cs-high", 0, 0, 'C' }, { "3wire", 0, 0, '3' }, { "no-cs", 0, 0, 'N' }, { "ready", 0, 0, 'R' }, { NULL, 0, 0, 0 }, }; int c; c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); if (c == -1) break; switch (c) { case 'D': device = optarg; break; case 's': speed = atoi(optarg); break; case 'd': delay = atoi(optarg); break; case 'b': bits = atoi(optarg); break; case 'l': mode |= SPI_LOOP; break; case 'H': mode |= SPI_CPHA; break; case 'O': mode |= SPI_CPOL; break; case 'L': mode |= SPI_LSB_FIRST; break; case 'C': mode |= SPI_CS_HIGH; break; case '3': mode |= SPI_3WIRE; break; case 'N': mode |= SPI_NO_CS; break; case 'R': mode |= SPI_READY; break; default: print_usage(argv[0]); break; } } } //******************************************************************/ //�� �ܣ�ͨ��RC522��ISO14443��ͨѶ //����˵����Command[IN]:RC522������ // pInData[IN]:ͨ��RC522���͵���Ƭ������ // InLenByte[IN]:�������ݵ��ֽڳ��� // pOutData[OUT]:���յ��Ŀ�Ƭ�������� // *pOutLenBit[OUT]:�������ݵ�λ���� //******************************************************************/ char PcdComMF522(unsigned char Command, unsigned char *pInData, unsigned char InLenByte, unsigned char *pOutData, unsigned int *pOutLenBit) { char status = MI_ERR; unsigned char irqEn = 0x00; unsigned char waitFor = 0x00; unsigned char lastBits; unsigned char n; unsigned int i; switch (Command) { case PCD_AUTHENT: irqEn = 0x12; waitFor = 0x10; break; case PCD_TRANSCEIVE: irqEn = 0x77; waitFor = 0x30; break; default: break; } WriteRawRC(ComIEnReg, irqEn|0x80); ClearBitMask(ComIrqReg, 0x80); WriteRawRC(CommandReg, PCD_IDLE); SetBitMask(FIFOLevelReg, 0x80); // ���FIFO for(i=0; i<InLenByte; i++) WriteRawRC(FIFODataReg, pInData[i]); // ����д��FIFO WriteRawRC(CommandReg, Command); // ����д������Ĵ��� if(Command == PCD_TRANSCEIVE) SetBitMask(BitFramingReg,0x80); // ��ʼ���� i = 6000; //����ʱ��Ƶ�ʵ���������M1�����ȴ�ʱ��25ms do { n = ReadRawRC(ComIrqReg); i--; } while((i!=0)&&!(n&0x01)&&!(n&waitFor)); ClearBitMask(BitFramingReg, 0x80); if(i!=0) { if(!(ReadRawRC(ErrorReg) & 0x1B)) { status = MI_OK; if (n&irqEn&0x01) status = MI_NOTAGERR; if(Command == PCD_TRANSCEIVE) { n = ReadRawRC(FIFOLevelReg); lastBits = ReadRawRC(ControlReg) & 0x07; if(lastBits) *pOutLenBit = (n-1)*8 + lastBits; else *pOutLenBit = n*8; if(n == 0) n = 1; if(n>MAXRLEN) n = MAXRLEN; for (i=0; i<n; i++) pOutData[i] = ReadRawRC(FIFODataReg); } } else { status = MI_ERR; } } SetBitMask(ControlReg, 0x80);// stop timer now WriteRawRC(CommandReg, PCD_IDLE); return status; } char PcdRequest(unsigned char req_code, unsigned char *pTagType) { char status; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg, 0x08); WriteRawRC(BitFramingReg, 0x07); SetBitMask(TxControlReg, 0x03); ucComMF522Buf[0] = req_code; status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, &unLen); if ((status == MI_OK) && (unLen == 0x10)) { *pTagType = ucComMF522Buf[0]; *(pTagType+1) = ucComMF522Buf[1]; } else { status = MI_ERR; } return status; } //******************************************************************/ //�� �ܣ�����ײ / //����˵��: pSnr[OUT]:��Ƭ���кţ�4�ֽ� / //�� ��: �ɹ�����MI_OK / //******************************************************************/ char PcdAnticoll(unsigned char *pSnr) { char status; unsigned char i, snr_check = 0; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg, 0x08); WriteRawRC(BitFramingReg, 0x00); ClearBitMask(CollReg, 0x80); ucComMF522Buf[0] = PICC_ANTICOLL1; ucComMF522Buf[1] = 0x20; status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, &unLen); if(status == MI_OK) { for (i=0; i<4; i++) { *(pSnr+i) = ucComMF522Buf[i]; snr_check ^= ucComMF522Buf[i]; } if (snr_check != ucComMF522Buf[i]) { status = MI_ERR; } } SetBitMask(CollReg,0x80); return status; } void Find_Card(void) { if(PcdRequest(0x52, Temp) == MI_OK) { if(Temp[0]==0x04 && Temp[1]==0x00) printf("MFOne-S50 "); else if(Temp[0]==0x02 && Temp[1] == 0x00) printf("MFOne-S70 "); else if(Temp[0]==0x44 && Temp[1]==0x00) printf("MF-UltraLight "); else if(Temp[0]==0x08 && Temp[1]==0x00) printf("MF-Pro "); else if(Temp[0]==0x44 && Temp[1]==0x03) printf("MF Desire "); else printf("Unknown "); printf("SUCCESS! "); } else { printf("No card! "); } } void Auto_Reader(void) { int i = 0; unsigned long num = 0; // while(1) //{ if(PcdRequest(0x52,Temp) == MI_OK) { if(Temp[0]==0x04 && Temp[1]==0x00) printf("MFOne-S50 "); else if(Temp[0]==0x02 && Temp[1]==0x00) printf("MFOne-S70 "); else if(Temp[0]==0x44 && Temp[1]==0x00) printf("MF-UltraLight "); else if(Temp[0]==0x08 && Temp[1]==0x00) printf("MF-Pro "); else if(Temp[0]==0x44 && Temp[1]==0x03) printf("MF Desire "); else printf("Unknown "); if(PcdAnticoll(UID) == MI_OK) { printf("Card Id is(%d):", num++); #if 1 for(i=0; i<4; i++) printf("%x", UID[i]); #else tochar(UID[0]); tochar(UID[1]); tochar(UID[2]); tochar(UID[3]); #endif printf(" "); PcdRequest(0x52,Temp);//clear } else { printf("no serial num read "); } } else { printf("No Card! "); } usleep(300000); // } } void HandleConfigMenu(unsigned char inputvalue) { #if 0 switch(toupper(inputvalue)) { case 'A': Auto_Reader(); break; case 'F': Find_Card(); break; default: DisplayConfigMenu(); } #endif //Find_Card(); Auto_Reader(); } int main(int argc, char *argv[]) { unsigned char i; int ret = 0; int fd; parse_opts(argc, argv); fd = open(device, O_RDWR); if (fd < 0) pabort("can't open device"); g_SPI_Fd = fd; #if 0 /* * spi mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) pabort("can't set spi mode"); ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) pabort("can't get spi mode"); /* * bits per word */ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't set bits per word"); ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't get bits per word"); /* * max speed hz */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't set max speed hz"); ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't get max speed hz"); printf("spi mode: %d ", mode); printf("bits per word: %d ", bits); printf("max speed: %d Hz (%d KHz) ", speed, speed/1000); #endif rc522_init(); PcdAntennaOn(); HandleConfigMenu(i); close(fd); return ret; }