TDA8029是一个完全单芯片、低成本、低功耗、功能强大的智能读卡器。它具有多种用来减少功耗的模式以及宽的电源电压范围,使之非常适合使用在便携式 设备中。由于具有特殊的多用途硬件,小嵌入式软件程序能够控制市场上的大部份卡。
由于我们产品的串口都已经被占用,TDA8029支持非标准I2C方式访问数据,所以我们改用I2C方式。CPU的I2C有标准I2C和GPIO I2C两种方式。由于TDA8029的I2C协议不是标准I2C,需要进行修改。所以我们选择从GPIO I2C方式中进行简单修改以支持ALPAR协议访问格式。
下面是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)) {