TDA8029模块工作之I2C修改支持ALPAR协议

TDA8029是一个完全单芯片、低成本、低功耗、功能强大的智能读卡器。它具有多种用来减少功耗的模式以及宽的电源电压范围,使之非常适合使用在便携式 设备中。由于具有特殊的多用途硬件,小嵌入式软件程序能够控制市场上的大部份卡。

由于我们产品的串口都已经被占用,TDA8029支持非标准I2C方式访问数据,所以我们改用I2C方式。CPUI2C有标准I2CGPIO I2C两种方式。由于TDA8029I2C协议不是标准I2C,需要进行修改。所以我们选择从GPIO I2C方式中进行简单修改以支持ALPAR协议访问格式。

下面是ALPAR协议格式:

TDA8029模块工作之I2C修改支持ALPAR协议

由上图可知,协议发送或接收的数据长度在数据的第二第三字节定义。因此,我们只需要在读取数据过程中先得出数据长度即可。

以下部分是修改的代码, +为添加部分:

 P { margin-bottom: 5.25px; }Index: include/linux/i2c.h 
=================================================================== 
--- include/linux/i2c.h (版本 986) 
+++ include/linux/i2c.h (版本 988) 
@@ -90,6 +90,12 @@ 
     u8 command, u8 *values); 
extern s32 i2c_smbus_write_block_data(struct i2c_client *client, 
      u8 command, u8 length, const u8 *values); 
+/* 
+* iUnin add for tda8029 ALPAR protocol. by yang.yuanming.  
+* data: ACK(1) + length(2) + code(1) + data(n) +LRC(1) = n+5  n=0~506 
+*/ 
+extern s32 i2c_smbus_read_alpar_data(struct i2c_client *client, u8 *values); 
+extern s32 i2c_smbus_write_alpar_data(struct i2c_client *client, u8 length, const u8 *values); 
/* Returns the number of read bytes */ 
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, 
 u8 command, u8 length, u8 *values); 
@@ -511,6 +517,7 @@ 
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ 
+#define I2C_M_ALPAR_RECV_LEN 0x0200 /* length will be n2&0xFF+n3+5 received byte */ 
 __u16 len; /* msg length */ 
 __u8 *buf; /* pointer to msg data */ 
}; 
@@ -566,6 +573,18 @@ 
       /* and one more for user-space compatibility */ 
}; 
 
+/* 
+* iUnin add for tda8029 ALPAR protocol. by yang.yuanming.  
+* data: ACK(1) + length(2) + code(1) + data(n) +LRC(1) = n+5  n=0~506 
+*/ 
+#define I2C_SMBUS_ALPAR_MAX 512 /* As specified in SMBus standard */ 
+union i2c_alpar_data { 
+ __u8 byte; 
+ __u16 word; 
+ __u8 block[I2C_SMBUS_ALPAR_MAX]; /* block[0] is used for length */ 
+       /* and one more for user-space compatibility */ 
+}; 
+ 
/* i2c_smbus_xfer read or write markers */ 
#define I2C_SMBUS_READ 1 
#define I2C_SMBUS_WRITE 0 
@@ -581,5 +600,5 @@ 
#define I2C_SMBUS_I2C_BLOCK_BROKEN  6 
#define I2C_SMBUS_BLOCK_PROC_CALL   7 /* SMBus 2.0 */ 
#define I2C_SMBUS_I2C_BLOCK_DATA    8 
- 
+#define I2C_SMBUS_ALPAR_DATA    9 
#endif /* _LINUX_I2C_H */ 
Index: drivers/i2c/i2c-core.c 
=================================================================== 
--- drivers/i2c/i2c-core.c (版本 986) 
+++ drivers/i2c/i2c-core.c (版本 988) 
@@ -1803,6 +1803,70 @@ 
} 
EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); 
 
+ 
+/* 
+* iUnin add for tda8029 ALPAR protocol. by yang.yuanming.  
+* data: ACK(1) + length(2) + code(1) + data(n) +LRC(1) = n+5 
+*/ 
+s32 i2c_smbus_read_alpar_data(struct i2c_client *client, u8 *values) 
+{ 
+ union i2c_alpar_data data; 
+ int status; 
+ unsigned char msgbuf0[I2C_SMBUS_ALPAR_MAX]; 
+ int num = 1; 
+ struct i2c_msg msg[1] = {{ client->addr, client->flags | I2C_M_RD, 0, msgbuf0 } 
+                        }; 
+ 
+ int i, alpar_len; 
+ u8 partial_pec = 0; 
+ 
+ msg[0].flags |= I2C_M_ALPAR_RECV_LEN; 
+ msg[0].len = 5; /* block length will be added by the underlying bus driver */ 
+ 
+ status = i2c_transfer(client->adapter, msg, num); 
+ if (status < 0) 
+ return status; 
+ 
+ /* Check PEC if last message is a read */ 
+ if (i && (msg[num-1].flags & I2C_M_RD)) { 
+ status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); 
+ if (status < 0) 
+ return status; 
+ } 
+ 
+ alpar_len = (msgbuf0[1]*256 +msgbuf0[2] + 5); 
+ for (i = 0; i < alpar_len; i++) 
+ data.block[i] = msgbuf0[i]; 
+ 
+ memcpy(values, &data.block[0], alpar_len); 
+ 
+ return alpar_len; 
+} 
+EXPORT_SYMBOL(i2c_smbus_read_alpar_data); 
+ 
+/* 
+* iUnin add for tda8029 ALPAR protocol. by yang.yuanming.  
+* data: ACK(1) + length(2) + code(1) + data(n) +LRC(1) = n+5 
+*/ 
+s32 i2c_smbus_write_alpar_data(struct i2c_client *client, u8 length, const u8 *values) 
+{ 
+ int status; 
+ 
+ if (length > I2C_SMBUS_ALPAR_MAX) 
+ length = I2C_SMBUS_ALPAR_MAX; 
+ 
+ struct i2c_msg msg[1] = {{ client->addr, 0, length, values } 
+                        }; 
+ 
+ status = i2c_transfer(client->adapter, msg, 1); 
+ if (status < 0) 
+ return status; 
+ 
+ return 0; 
+} 
+EXPORT_SYMBOL(i2c_smbus_write_alpar_data); 
+ 
+ 
/* Simulate a SMBus command using the i2c protocol 
No checking of parameters is done!  */ 
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, 
Index: drivers/i2c/algos/i2c-algo-bit.c 
=================================================================== 
--- drivers/i2c/algos/i2c-algo-bit.c (版本 986) 
+++ drivers/i2c/algos/i2c-algo-bit.c (版本 988) 
@@ -417,6 +417,25 @@ 
 temp++; 
 count--; 
 
+ /* 
+ * iUnin add for tda8029 ALPAR protocol. by yang.yuanming.  
+ * data: ACK(1) + length(2) + code(1) + data(n) +LRC(1) = n+5 
+ */ 
+ if ((rdcount == 2 || rdcount == 3) && (flags & I2C_M_ALPAR_RECV_LEN)) { 
+ /* The original count value accounts for the extra 
+   bytes, that is, either 1 for a regular transaction, 
+   or 2 for a PEC transaction. */ 
+   if(rdcount == 2){ 
+ count += (inval*256); 
+ msg->len += (inval*256); 
+   } 
+   if(rdcount == 3){ 
+ count += inval; 
+ msg->len += inval; 
+   }     
+    
+ } 
+ 
 /* Some SMBus transactions require that we receive the 
   transaction length as the first read byte. */ 
 if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {


在完成协议小小修改部分后, TDA8029驱动则相对简单了。真正的工作在上层的各种 IC卡的协议访问过程。这就是下部分的事情了。。。


你可能感兴趣的:(TDA8029模块工作之I2C修改支持ALPAR协议)