blob: 2446e63f14a760f2960ae941f719e9ca5b3b18d8 [file] [log] [blame]
/****************************************************************************/
/* Copyright 2019 Novatek. All rights reserved. */
/* Use of this source code is governed by a BSD-style license that can be */
/* found in the LICENSE file. */
/****************************************************************************/
#include "NVTAuxCtrl.h"
#include <err.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "NVTSettingProc.h"
int fpNativeAux, fpI2CoverAux;
struct NvtAuxConfig auxConfig;
NVTAUX_STATUS NVTAUX_Open() {
// search target DP interface
FILE *fp;
char auxPath[1024], i2cPath[1024], path[256], pollingPath[512];
int openStat;
char *chrret;
if (gConfig.m_DpInterface == 2) {
// assume there is only one eDP interface and fine eDP path
fp = popen(
"find /sys/class/drm/*eDP*/drm_dp_aux* -maxdepth 0 | sed 's/.*\\///'",
"r");
if (fp == NULL) {
warnx("Fail to get eDP interface - DpInt==2 drm_dp_aux* popen() failed");
return AUX_STATUS_FAIL;
}
chrret = fgets(path, sizeof(path) - 1, fp);
pclose(fp);
if (!chrret) {
warnx("Fail to get eDP interface - DpInt==2 drm_dp_aux* fgets() failed");
return AUX_STATUS_FAIL;
}
sprintf(auxPath, "/dev/%s", path);
strtok(auxPath, "\n");
#if DEBUG_LOG
printf("eDP aux device path: %s\n", auxPath);
#endif // DEBUG_LOG
fp = popen("find /sys/class/drm/*eDP*/i2c-* -maxdepth 0 | sed 's/.*\\///'",
"r");
if (fp == NULL) {
warnx("Fail to get eDP interface - DpInt==2 i2c-* popen() failed");
return AUX_STATUS_FAIL;
}
chrret = fgets(path, sizeof(path) - 1, fp);
pclose(fp);
if (!chrret) {
warnx("Fail to get eDP interface - DpInt==2 i2c-* fgets() failed");
return AUX_STATUS_FAIL;
}
sprintf(i2cPath, "/dev/%s", path);
strtok(i2cPath, "\n");
#if DEBUG_LOG
printf("eDP i2c device path: %s\n", i2cPath);
#endif // DEBUG_LOG
} else if (gConfig.m_DpInterface == 3) {
// assume there is only 1 DP device connected and connect to card0 1st port
int portNo = 0;
for (portNo = 0; portNo < 8; portNo++) {
sprintf(path, "/sys/class/drm/card0-DP-%d", portNo);
openStat = open(path, O_RDONLY);
if (openStat < 0) continue;
if (close(openStat) < 0) {
warn("failed when attempting to close %s", path);
return AUX_STATUS_FAIL;
}
sprintf(pollingPath, "find %s/drm_dp_aux* -maxdepth 0 | sed 's/.*\\///'",
path);
fp = popen(pollingPath, "r");
if (fp == NULL) {
warnx("Fail to get eDP interface - DpInt==3 portNo==%d drm_dp_aux* "
"popen() failed", portNo);
return AUX_STATUS_FAIL;
}
chrret = fgets(pollingPath, sizeof(pollingPath) - 1, fp);
pclose(fp);
if (!chrret) {
warnx("Fail to get eDP interface - DpInt==3 portNo==%d drm_dp_aux* "
"fgets() failed", portNo);
return AUX_STATUS_FAIL;
}
sprintf(auxPath, "/dev/%s", pollingPath);
strtok(auxPath, "\n");
#if DEBUG_LOG
printf("eDP aux device path: %s\n", auxPath);
#endif // DEBUG_LOG
sprintf(pollingPath, "find %s/i2c* -maxdepth 0 | sed 's/.*\\///'", path);
fp = popen(pollingPath, "r");
if (fp == NULL) {
warnx("Fail to get eDP interface - DpInt==3 portNo==%d i2c-* popen() "
"failed", portNo);
return AUX_STATUS_FAIL;
}
chrret = fgets(pollingPath, sizeof(pollingPath) - 1, fp);
pclose(fp);
if (!chrret) {
warnx("Fail to get eDP interface - DpInt==3 portNo==%d i2c-* fgets() "
"failed", portNo);
return AUX_STATUS_FAIL;
}
sprintf(i2cPath, "/dev/%s", pollingPath);
strtok(i2cPath, "\n");
#if DEBUG_LOG
printf("eDP i2c device path: %s\n", i2cPath);
#endif // DEBUG_LOG
break;
}
} else {
warnx("unknown DP Interface");
return AUX_STATUS_FAIL;
}
// open Native aux device
if ((fpNativeAux = open(auxPath, O_RDWR)) < 0) {
warn("open fpNativeAux device failed");
return AUX_STATUS_FAIL;
}
// open I2CoverAux device
if ((fpI2CoverAux = open(i2cPath, O_RDWR)) < 0) {
warn("open I2CoverAux device failed");
return AUX_STATUS_FAIL;
}
return AUX_STATUS_OK;
}
NVTAUX_STATUS NVTAUX_Close() {
NVTAUX_STATUS retval = AUX_STATUS_OK;
if (close(fpNativeAux) < 0) {
warn("failed when attempting to close fpNativeAux");
retval = AUX_STATUS_FAIL;
}
if (close(fpI2CoverAux) < 0) {
warn("failed when attempting to close fpI2CoverAux");
retval = AUX_STATUS_FAIL;
}
return retval;
}
NVTAUX_STATUS NVTAUX_NativeAuxAccess(unsigned int op, unsigned int dpcdAddr,
unsigned int len, unsigned char *buf) {
int ret;
if (op == NATIVE_AUX_WRITE) {
ret = lseek(fpNativeAux, dpcdAddr, SEEK_SET);
if (ret < 0) return AUX_STATUS_FAIL;
ret = write(fpNativeAux, buf, len);
if (ret < 0) return AUX_STATUS_FAIL;
} else if (op == NATIVE_AUX_READ) {
ret = lseek(fpNativeAux, dpcdAddr, SEEK_SET);
if (ret < 0) return AUX_STATUS_FAIL;
ret = read(fpNativeAux, buf, len);
if (ret < 0) return AUX_STATUS_FAIL;
} else {
return AUX_STATUS_ERR_PARAM;
}
return AUX_STATUS_OK;
}
NVTAUX_STATUS NVTAUX_I2COverAuxWrite(unsigned int devAddr, unsigned int wrLen,
unsigned char *wrBuf) {
int ret;
int auxSize = auxConfig.m_AuxRequestByte, lastPacketSize;
struct i2c_rdwr_ioctl_data i2c_data;
// i2c_rdwr_ioctl_data defined in i2c-dev.h
// i2c_msg defined in i2c.h
#if 1
// standard I2C interface
i2c_data.nmsgs = ((wrLen - 1) / auxSize) + 1;
lastPacketSize = wrLen % auxSize;
i2c_data.msgs =
(struct i2c_msg *)malloc(i2c_data.nmsgs * sizeof(struct i2c_msg));
#if DEBUG_LOG
printf("msgs:%d, lastPacketSize:%d\n", i2c_data.nmsgs, lastPacketSize);
#endif // DEBUG_LOG
for (unsigned int i = 0; i < i2c_data.nmsgs - 1; i++) {
(i2c_data.msgs[i]).len = auxSize;
(i2c_data.msgs[i]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i]).flags = 0; // write
(i2c_data.msgs[i]).buf = (unsigned char *)malloc(auxSize);
for (int j = 0; j < auxSize; j++) {
(i2c_data.msgs[i]).buf[j] = wrBuf[i * auxSize + j];
#if DEBUG_LOG
printf("%02X ", wrBuf[i * auxSize + j]);
#endif // DEBUG_LOG
}
}
if (lastPacketSize != 0) {
(i2c_data.msgs[i2c_data.nmsgs - 1]).len = lastPacketSize;
(i2c_data.msgs[i2c_data.nmsgs - 1]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i2c_data.nmsgs - 1]).flags = 0; // write
(i2c_data.msgs[i2c_data.nmsgs - 1]).buf =
(unsigned char *)malloc(lastPacketSize);
for (int j = 0; j < lastPacketSize; j++) {
(i2c_data.msgs[i2c_data.nmsgs - 1]).buf[j] =
wrBuf[(i2c_data.nmsgs - 1) * auxSize + j];
#if DEBUG_LOG
printf("%02X ", wrBuf[(i2c_data.nmsgs - 1) * auxSize + j]);
#endif // DEBUG_LOG
}
} else {
(i2c_data.msgs[i2c_data.nmsgs - 1]).len = auxSize;
(i2c_data.msgs[i2c_data.nmsgs - 1]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i2c_data.nmsgs - 1]).flags = 0; // write
(i2c_data.msgs[i2c_data.nmsgs - 1]).buf = (unsigned char *)malloc(auxSize);
for (int j = 0; j < auxSize; j++) {
(i2c_data.msgs[i2c_data.nmsgs - 1]).buf[j] =
wrBuf[(i2c_data.nmsgs - 1) * auxSize + j];
#if DEBUG_LOG
printf("%02X ", wrBuf[(i2c_data.nmsgs - 1) * auxSize + j]);
#endif // DEBUG_LOG
}
}
#if DEBUG_LOG
printf("\n");
#endif // DEBUG_LOG
ret = ioctl(fpI2CoverAux, I2C_RDWR, (unsigned long)&i2c_data);
if (ret < 0) {
warnx("i2c write fail");
return AUX_STATUS_FAIL;
}
#else
// intel driver provided interface
ret = write(fpI2CoverAux, wrBuf, wrLen);
if (ret != wrLen) {
warnx("i2c write fail");
return AUX_STATUS_FAIL;
}
#endif // 0
return AUX_STATUS_OK;
}
NVTAUX_STATUS NVTAUX_I2COverAuxRead(unsigned int devAddr, unsigned int rdLen,
unsigned char *rdBuf) {
int ret;
struct i2c_rdwr_ioctl_data i2c_data;
i2c_data.nmsgs = 1;
i2c_data.msgs =
(struct i2c_msg *)malloc(i2c_data.nmsgs * sizeof(struct i2c_msg));
(i2c_data.msgs[0]).len = rdLen;
(i2c_data.msgs[0]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[0]).flags = I2C_M_RD;
(i2c_data.msgs[0]).buf = (unsigned char *)malloc(rdLen);
ret = ioctl(fpI2CoverAux, I2C_RDWR, (unsigned long)&i2c_data);
if (ret < 0) {
warnx("i2c read fail");
return AUX_STATUS_FAIL;
}
for (unsigned int i = 0; i < rdLen; i++) rdBuf[i] = (i2c_data.msgs[0]).buf[i];
return AUX_STATUS_OK;
}
NVTAUX_STATUS NVTAUX_I2COverAuxBurstRead(unsigned int devAddr,
unsigned int wrLen,
unsigned char *wrBuf,
unsigned int rdLen,
unsigned char *rdBuf) {
// this function is to compose the repeated start I2C read
int ret;
int auxSize = auxConfig.m_AuxRequestByte, lastPacketSize;
struct i2c_rdwr_ioctl_data i2c_data;
i2c_data.nmsgs = ((((wrLen - 1) / auxSize) + 1) + 1);
lastPacketSize = wrLen % auxSize;
i2c_data.msgs =
(struct i2c_msg *)malloc(i2c_data.nmsgs * sizeof(struct i2c_msg));
#if DEBUG_LOG
printf("msgs:%d, lastPacketSize:%d\n", i2c_data.nmsgs, lastPacketSize);
#endif // DEBUG_LOG
// compose write message
for (unsigned int i = 0; i < i2c_data.nmsgs - 2; i++) {
(i2c_data.msgs[i]).len = auxSize;
(i2c_data.msgs[i]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i]).flags = 0; // write
(i2c_data.msgs[i]).buf = (unsigned char *)malloc(auxSize);
for (int j = 0; j < auxSize; j++)
(i2c_data.msgs[i]).buf[j] = wrBuf[i * auxSize + j];
}
if (lastPacketSize != 0) {
(i2c_data.msgs[i2c_data.nmsgs - 2]).len = lastPacketSize;
(i2c_data.msgs[i2c_data.nmsgs - 2]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i2c_data.nmsgs - 2]).flags = 0; // write
(i2c_data.msgs[i2c_data.nmsgs - 2]).buf =
(unsigned char *)malloc(lastPacketSize);
for (int j = 0; j < lastPacketSize; j++)
(i2c_data.msgs[i2c_data.nmsgs - 2]).buf[j] =
wrBuf[(i2c_data.nmsgs - 2) * auxSize + j];
} else {
(i2c_data.msgs[i2c_data.nmsgs - 2]).len = auxSize;
(i2c_data.msgs[i2c_data.nmsgs - 2]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i2c_data.nmsgs - 2]).flags = 0; // write
(i2c_data.msgs[i2c_data.nmsgs - 2]).buf = (unsigned char *)malloc(auxSize);
for (int j = 0; j < auxSize; j++)
(i2c_data.msgs[i2c_data.nmsgs - 2]).buf[j] =
wrBuf[(i2c_data.nmsgs - 2) * auxSize + j];
}
// compose read message
(i2c_data.msgs[i2c_data.nmsgs - 1]).len = rdLen;
(i2c_data.msgs[i2c_data.nmsgs - 1]).addr = ((devAddr >> 1) & 0x7F);
(i2c_data.msgs[i2c_data.nmsgs - 1]).flags = I2C_M_RD;
(i2c_data.msgs[i2c_data.nmsgs - 1]).buf = (unsigned char *)malloc(rdLen);
ret = ioctl(fpI2CoverAux, I2C_RDWR, (unsigned long)&i2c_data);
if (ret < 0) {
warnx("i2c burst read fail");
return AUX_STATUS_FAIL;
}
for (unsigned int i = 0; i < rdLen; i++)
rdBuf[i] = (i2c_data.msgs[i2c_data.nmsgs - 1]).buf[i];
return AUX_STATUS_OK;
}