Commit 9bd8fdc9 authored by apapkovskiy's avatar apapkovskiy
Browse files

Added patch fom NXP ro resolve problem with I2C

parent 7e6b0c93
/**
* @file i2c_a7.c
* @author NXP Semiconductors
* @version 1.0
* @par License
* Copyright 2017 NXP
*
* This software is owned or controlled by NXP and may only be used
* strictly in accordance with the applicable license terms. By expressly
* accepting such terms or by downloading, installing, activating and/or
* otherwise using the software, you are agreeing that you have read, and
* that you agree to comply with and are bound by, such license terms. If
* you do not agree to be bound by the applicable license terms, then you
* may not retain, install, activate or otherwise use the software.
*
* @par Description
* i.MX6UL board specific i2c code
* @par History
*
**/
#include "i2c_a7.h"
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <time.h>
#include "nxLog_smCom.h"
static int axSmDevice;
static int axSmDevice_addr = 0x48; // 7-bit address
static char devName[] = "/dev/i2c-1"; // Change this when connecting to another host i2c master port
/**
* Opens the communication channel to I2C device
*/
i2c_error_t axI2CInit()
{
unsigned long funcs;
/*
* Open the file in /dev/i2c-1
*/
LOG_D("I2CInit: opening %s\n", devName);
if ((axSmDevice = open(devName, O_RDWR)) < 0)
{
LOG_E("opening failed...");
perror("Failed to open the i2c bus");
return I2C_FAILED;
}
if (ioctl(axSmDevice, I2C_SLAVE, axSmDevice_addr) < 0)
{
LOG_E("I2C driver failed setting address\n");
}
// clear PEC flag
if (ioctl(axSmDevice, I2C_PEC, 0) < 0)
{
LOG_E("I2C driver: PEC flag clear failed\n");
}
else
{
LOG_D("I2C driver: PEC flag cleared\n");
}
// Query functional capacity of I2C driver
if (ioctl(axSmDevice, I2C_FUNCS, &funcs) < 0)
{
LOG_E("Cannot get i2c adapter functionality\n");
return I2C_FAILED;
}
else
{
if (funcs & I2C_FUNC_I2C)
{
LOG_D("I2C driver supports plain i2c-level commands.\n");
if ( (funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA) == I2C_FUNC_SMBUS_READ_BLOCK_DATA )
{
LOG_D("I2C driver supports Read Block.\n");
}
else
{
LOG_E("I2C driver does not support Read Block!\n");
return I2C_FAILED;
}
}
else
{
LOG_E("I2C driver CANNOT support plain i2c-level commands!\n");
return I2C_FAILED;
}
}
return I2C_OK;
}
/**
* Closes the communication channel to I2C device (not implemented)
*/
void axI2CTerm(int mode)
{
AX_UNUSED_ARG(mode);
LOG_I("axI2CTerm: not implemented.\n");
return;
}
/**
* Write a single byte to the slave device.
* In the context of the SCI2C protocol, this command is only invoked
* to trigger a wake-up of the attached secure module. As such this
* wakeup command 'wakes' the device, but does not receive a valid response.
* \note \par bus is currently not used to distinguish between I2C masters.
*/
i2c_error_t axI2CWriteByte(unsigned char bus, unsigned char addr, unsigned char *pTx)
{
int nrWritten = -1;
i2c_error_t rv;
if (bus != I2C_BUS_0)
{
LOG_E("axI2CWriteByte on wrong bus %x (addr %x)\n", bus, addr);
}
nrWritten = write(axSmDevice, pTx, 1);
if (nrWritten < 0)
{
// I2C_LOG_PRINTF("Failed writing data (nrWritten=%d).\n", nrWritten);
rv = I2C_FAILED;
}
else
{
if (nrWritten == 1)
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
return rv;
}
i2c_error_t axI2CWrite(unsigned char bus, unsigned char addr, unsigned char * pTx, unsigned short txLen)
{
int nrWritten = -1;
i2c_error_t rv;
#ifdef LOG_I2C
int i = 0;
#endif
if (bus != I2C_BUS_0)
{
LOG_E("axI2CWrite on wrong bus %x (addr %x)\n", bus, addr);
}
LOG_MAU8_D("TX (axI2CWrite) > ",pTx,txLen);
nrWritten = write(axSmDevice, pTx, txLen);
if (nrWritten < 0)
{
LOG_E("Failed writing data (nrWritten=%d).\n", nrWritten);
rv = I2C_FAILED;
}
else
{
if (nrWritten == txLen) // okay
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
LOG_D("Done with rv = %02x ", rv);
return rv;
}
i2c_error_t axI2CWriteRead(unsigned char bus, unsigned char addr, unsigned char * pTx,
unsigned short txLen, unsigned char * pRx, unsigned short * pRxLen)
{
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
int r = 0;
int i = 0;
if (bus != I2C_BUS_0) // change if bus 0 is not the correct bus
{
LOG_E("axI2CWriteRead on wrong bus %x (addr %x)\n", bus, addr);
}
messages[0].addr = axSmDevice_addr;
messages[0].flags = 0;
messages[0].len = txLen;
messages[0].buf = pTx;
// NOTE:
// By setting the 'I2C_M_RECV_LEN' bit in 'messages[1].flags' one ensures
// the I2C Block Read feature is used.
messages[1].addr = axSmDevice_addr;
messages[1].flags = I2C_M_RD | I2C_M_RECV_LEN;
messages[1].len = 256;
messages[1].buf = pRx;
messages[1].buf[0] = 1;
// NOTE:
// By passing the two message structures via the packets structure as
// a parameter to the ioctl call one ensures a Repeated Start is triggered.
packets.msgs = messages;
packets.nmsgs = 2;
LOG_MAU8_D("TX (axI2CWriteRead ) > ",packets.msgs[0].buf[i], txLen);
// Send the request to the kernel and get the result back
r = ioctl(axSmDevice, I2C_RDWR, &packets);
// NOTE:
// The ioctl return value in case of a NACK on the write address is '-1'
// This impacts the error handling routine of the caller.
if (r < 0)
{
// LOG_E("axI2CWriteRead: ioctl cmd I2C_RDWR fails with value %d (hex: 0x%08X)\n", r, r);
// perror("Errorstring: ");
// I2C_LOG_PRINTF("axI2CWriteRead: ioctl value %d (hex: 0x%08X)\n", r, r);
return I2C_FAILED;
}
else
{
int rlen = packets.msgs[1].buf[0]+1;
//I2C_LOG_PRINTF("packets.msgs[1].len is %d \n", packets.msgs[1].len);
LOG_MAU8_D("RX (axI2CWriteRead) < ",packets.msgs[1].buf[i], rlen);
for (i = 0; i < rlen; i++)
{
pRx[i] = packets.msgs[1].buf[i];
}
*pRxLen = rlen;
}
return I2C_OK;
}
i2c_error_t axI2CRead(unsigned char bus, unsigned char addr, unsigned char * pRx, unsigned short rxLen)
{
int nrRead = -1;
i2c_error_t rv;
#ifdef LOG_I2C
int i = 0;
#endif
if (bus != I2C_BUS_0)
{
LOG_E("axI2CRead on wrong bus %x (addr %x)\n", bus, addr);
}
nrRead = read(axSmDevice, pRx, rxLen);
if (nrRead < 0)
{
//LOG_E("Failed Read data (nrRead=%d).\n", nrRead);
rv = I2C_FAILED;
}
else
{
if (nrRead == rxLen) // okay
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
LOG_D("Done with rv = %02x ", rv);
LOG_MAU8_D("TX (axI2CRead): ",pRx[i],rxLen);
return rv;
}
/**
* @file i2c_a7.c
* @author NXP Semiconductors
* @version 1.0
* @par License
* Copyright 2017 NXP
*
* This software is owned or controlled by NXP and may only be used
* strictly in accordance with the applicable license terms. By expressly
* accepting such terms or by downloading, installing, activating and/or
* otherwise using the software, you are agreeing that you have read, and
* that you agree to comply with and are bound by, such license terms. If
* you do not agree to be bound by the applicable license terms, then you
* may not retain, install, activate or otherwise use the software.
*
* @par Description
* i.MX6UL board specific i2c code
* @par History
*
**/
#include "i2c_a7.h"
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <time.h>
#include "nxLog_smCom.h"
static int axSmDevice;
static int axSmDevice_addr = 0x48; // 7-bit address
static char devName[] = "/dev/i2c-1"; // Change this when connecting to another host i2c master port
/**
* Opens the communication channel to I2C device
*/
i2c_error_t axI2CInit()
{
unsigned long funcs;
/*
* Open the file in /dev/i2c-1
*/
LOG_D("I2CInit: opening %s\n", devName);
if ((axSmDevice = open(devName, O_RDWR)) < 0)
{
LOG_E("opening failed...");
perror("Failed to open the i2c bus");
return I2C_FAILED;
}
if (ioctl(axSmDevice, I2C_SLAVE, axSmDevice_addr) < 0)
{
LOG_E("I2C driver failed setting address\n");
}
// clear PEC flag
if (ioctl(axSmDevice, I2C_PEC, 0) < 0)
{
LOG_E("I2C driver: PEC flag clear failed\n");
}
else
{
LOG_D("I2C driver: PEC flag cleared\n");
}
// Query functional capacity of I2C driver
if (ioctl(axSmDevice, I2C_FUNCS, &funcs) < 0)
{
LOG_E("Cannot get i2c adapter functionality\n");
return I2C_FAILED;
}
else
{
if (funcs & I2C_FUNC_I2C)
{
LOG_D("I2C driver supports plain i2c-level commands.\n");
if ( (funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA) == I2C_FUNC_SMBUS_READ_BLOCK_DATA )
{
LOG_D("I2C driver supports Read Block.\n");
}
else
{
LOG_E("I2C driver does not support Read Block!\n");
return I2C_FAILED;
}
}
else
{
LOG_E("I2C driver CANNOT support plain i2c-level commands!\n");
return I2C_FAILED;
}
}
return I2C_OK;
}
/**
* Closes the communication channel to I2C device (not implemented)
*/
void axI2CTerm(int mode)
{
AX_UNUSED_ARG(mode);
LOG_I("axI2CTerm: not implemented.\n");
return;
}
/**
* Write a single byte to the slave device.
* In the context of the SCI2C protocol, this command is only invoked
* to trigger a wake-up of the attached secure module. As such this
* wakeup command 'wakes' the device, but does not receive a valid response.
* \note \par bus is currently not used to distinguish between I2C masters.
*/
i2c_error_t axI2CWriteByte(unsigned char bus, unsigned char addr, unsigned char *pTx)
{
int nrWritten = -1;
i2c_error_t rv;
if (bus != I2C_BUS_0)
{
LOG_E("axI2CWriteByte on wrong bus %x (addr %x)\n", bus, addr);
}
nrWritten = write(axSmDevice, pTx, 1);
if (nrWritten < 0)
{
// I2C_LOG_PRINTF("Failed writing data (nrWritten=%d).\n", nrWritten);
rv = I2C_FAILED;
}
else
{
if (nrWritten == 1)
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
return rv;
}
i2c_error_t axI2CWrite(unsigned char bus, unsigned char addr, unsigned char * pTx, unsigned short txLen)
{
int nrWritten = -1;
i2c_error_t rv;
#ifdef LOG_I2C
int i = 0;
#endif
if (bus != I2C_BUS_0)
{
LOG_E("axI2CWrite on wrong bus %x (addr %x)\n", bus, addr);
}
LOG_MAU8_D("TX (axI2CWrite) > ",pTx,txLen);
nrWritten = write(axSmDevice, pTx, txLen);
if (nrWritten < 0)
{
LOG_E("Failed writing data (nrWritten=%d).\n", nrWritten);
rv = I2C_FAILED;
}
else
{
if (nrWritten == txLen) // okay
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
LOG_D("Done with rv = %02x ", rv);
return rv;
}
i2c_error_t axI2CWriteRead(unsigned char bus, unsigned char addr, unsigned char * pTx,
unsigned short txLen, unsigned char * pRx, unsigned short * pRxLen)
{
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
int r = 0;
int i = 0;
if (bus != I2C_BUS_0) // change if bus 0 is not the correct bus
{
LOG_E("axI2CWriteRead on wrong bus %x (addr %x)\n", bus, addr);
}
messages[0].addr = axSmDevice_addr;
messages[0].flags = 0;
messages[0].len = txLen;
messages[0].buf = pTx;
// NOTE:
// By setting the 'I2C_M_RECV_LEN' bit in 'messages[1].flags' one ensures
// the I2C Block Read feature is used.
messages[1].addr = axSmDevice_addr;
messages[1].flags = I2C_M_RD | I2C_M_RECV_LEN;
messages[1].len = 256;
messages[1].buf = pRx;
messages[1].buf[0] = 1;
// NOTE:
// By passing the two message structures via the packets structure as
// a parameter to the ioctl call one ensures a Repeated Start is triggered.
packets.msgs = messages;
packets.nmsgs = 2;
LOG_MAU8_D("TX (axI2CWriteRead ) > ",packets.msgs[0].buf[i], txLen);
// Send the request to the kernel and get the result back
r = ioctl(axSmDevice, I2C_RDWR, &packets);
// NOTE:
// The ioctl return value in case of a NACK on the write address is '-1'
// This impacts the error handling routine of the caller.
if (r < 0)
{
// LOG_E("axI2CWriteRead: ioctl cmd I2C_RDWR fails with value %d (hex: 0x%08X)\n", r, r);
// perror("Errorstring: ");
// I2C_LOG_PRINTF("axI2CWriteRead: ioctl value %d (hex: 0x%08X)\n", r, r);
return I2C_FAILED;
}
else
{
int rlen = packets.msgs[1].buf[0]+1;
//I2C_LOG_PRINTF("packets.msgs[1].len is %d \n", packets.msgs[1].len);
LOG_MAU8_D("RX (axI2CWriteRead) < ",packets.msgs[1].buf[i], rlen);
for (i = 0; i < rlen; i++)
{
pRx[i] = packets.msgs[1].buf[i];
}
*pRxLen = rlen;
}
return I2C_OK;
}
i2c_error_t axI2CRead(unsigned char bus, unsigned char addr, unsigned char * pRx, unsigned short rxLen)
{
int nrRead = -1;
i2c_error_t rv;
#ifdef LOG_I2C
int i = 0;
#endif
if (bus != I2C_BUS_0)
{
LOG_E("axI2CRead on wrong bus %x (addr %x)\n", bus, addr);
}
nrRead = read(axSmDevice, pRx, rxLen);
if (nrRead < 0)
{
//LOG_E("Failed Read data (nrRead=%d).\n", nrRead);
rv = I2C_FAILED;
}
else
{
if (nrRead == rxLen) // okay
{
rv = I2C_OK;
}
else
{
rv = I2C_FAILED;
}
}
LOG_D("Done with rv = %02x ", rv);
LOG_MAU8_D("TX (axI2CRead): ",pRx[i],rxLen);
return rv;
}
--- a/i2c_a7.c 2018-11-07 14:58:42.000000000 +0300
+++ b/i2c_a7.c 2018-12-26 18:14:53.768660501 +0300
@@ -32,8 +32,8 @@
#include "nxLog_smCom.h"
static int axSmDevice;
-static int axSmDevice_addr = 0x48; // 7-bit address
-static char devName[] = "/dev/i2c-1"; // Change this when connecting to another host i2c master port
+static int axSmDevice_addr = 0x49; // 7-bit address
+static char devName[] = "/dev/i2c-3"; // Change this when connecting to another host i2c master port
/**
* Opens the communication channel to I2C device
#include "nxLog_smCom.h"
static int axSmDevice;
-static int axSmDevice_addr = 0x48; // 7-bit address
-static char devName[] = "/dev/i2c-1"; // Change this when connecting to another host i2c master port
+static int axSmDevice_addr = 0x49; // 7-bit address
+static char devName[] = "/dev/i2c-3"; // Change this when connecting to another host i2c master port
/**
* Opens the communication channel to I2C device
diff --git a/hostLib/platform/imx/i2c_a7.c b/hostLib/platform/imx/i2c_a7.c
index 6eb8912..1943b40 100755
--- a/hostLib/platform/imx/i2c_a7.c
+++ b/hostLib/platform/imx/i2c_a7.c
@@ -31,6 +31,8 @@
#include <time.h>
#include "nxLog_smCom.h"
+#include <sm_timer.h>
+
static int axSmDevice;
static int axSmDevice_addr = 0x49; // 7-bit address
static char devName[] = "/dev/i2c-3"; // Change this when connecting to another host i2c master port