You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hardware_samsung/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.c

290 lines
6.5 KiB

/*
* Copyright@ Samsung Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/i2c.h>
#include <cutils/log.h>
#include "i2c-dev.h"
#include "libddc.h"
#define DDC_DEBUG 0
/**
* @brief DDC device name.
* User should change this.
*/
#ifdef DDC_CH_I2C_1
#define DEV_NAME "/dev/i2c-1"
#endif
#ifdef DDC_CH_I2C_2
#define DEV_NAME "/dev/i2c-2"
#endif
#ifdef DDC_CH_I2C_7
#define DEV_NAME "/dev/i2c-7"
#endif
#ifdef DDC_CH_I2C_8
#define DEV_NAME "/dev/i2c-8"
#endif
/**
* DDC file descriptor
*/
static int ddc_fd = -1;
/**
* Reference count of DDC file descriptor
*/
static unsigned int ref_cnt = 0;
/**
* Check if DDC file is already opened or not
* @return If DDC file is already opened, return 1; Otherwise, return 0.
*/
static int DDCFileAvailable()
{
return (ddc_fd < 0) ? 0 : 1;
}
/**
* Initialze DDC library. Open DDC device
* @return If succeed in opening DDC device or it is already opened, return 1;@n
* Otherwise, return 0.
*/
int DDCOpen()
{
int ret = 1;
// check already open??
if (ref_cnt > 0) {
ref_cnt++;
return 1;
}
// open
if ((ddc_fd = open(DEV_NAME,O_RDWR)) < 0) {
LOGE("%s: Cannot open I2C_DDC : %s",__func__, DEV_NAME);
ret = 0;
}
ref_cnt++;
return ret;
}
/**
* Finalize DDC library. Close DDC device
* @return If succeed in closing DDC device or it is being used yet, return 1;@n
* Otherwise, return 0.
*/
int DDCClose()
{
int ret = 1;
// check if fd is available
if (ref_cnt == 0) {
#if DDC_DEBUG
LOGE("%s: I2C_DDC is not available!!!!", __func__);
#endif
return 1;
}
// close
if (ref_cnt > 1) {
ref_cnt--;
return 1;
}
if (close(ddc_fd) < 0) {
#if DDC_DEBUG
LOGE("%s: Cannot close I2C_DDC : %s",__func__,DEV_NAME);
#endif
ret = 0;
}
ref_cnt--;
ddc_fd = -1;
return ret;
}
/**
* Read data though DDC. For more information of DDC, refer DDC Spec.
* @param addr [in] Device address
* @param offset [in] Byte offset
* @param size [in] Sizes of data
* @param buffer [out] Pointer to buffer to store data
* @return If succeed in reading, return 1; Otherwise, return 0.
*/
int DDCRead(unsigned char addr, unsigned char offset,
unsigned int size, unsigned char* buffer)
{
struct i2c_rdwr_ioctl_data msgset;
struct i2c_msg msgs[2];
int ret = 1;
if (!DDCFileAvailable()) {
#if DDC_DEBUG
LOGE("%s: I2C_DDC is not available!!!!", __func__);
#endif
return 0;
}
// set offset
msgs[0].addr = addr>>1;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &offset;
// read data
msgs[1].addr = addr>>1;
msgs[1].flags = I2C_M_RD;
msgs[1].len = size;
msgs[1].buf = buffer;
// set rdwr ioctl data
msgset.nmsgs = 2;
msgset.msgs = msgs;
// i2c fast read
if ((ret = ioctl(ddc_fd, I2C_RDWR, &msgset)) < 0) {
perror("ddc error:");
ret = 0;
}
return ret;
}
/**
* Read data though E-DDC. For more information of E-DDC, refer E-DDC Spec.
* @param segpointer [in] Segment pointer
* @param segment [in] Segment number
* @param addr [in] Device address
* @param offset [in] Byte offset
* @param size [in] Sizes of data
* @param buffer [out] Pointer to buffer to store data
* @return If succeed in reading, return 1; Otherwise, return 0.
*/
int EDDCRead(unsigned char segpointer, unsigned char segment, unsigned char addr,
unsigned char offset, unsigned int size, unsigned char* buffer)
{
struct i2c_rdwr_ioctl_data msgset;
struct i2c_msg msgs[3];
int ret = 1;
if (!DDCFileAvailable()) {
#if DDC_DEBUG
LOGE("%s: I2C_DDC is not available!!!!", __func__);
#endif
return 0;
}
// set segment pointer
msgs[0].addr = segpointer>>1;
// ignore ack only if segment is "0"
if (segment == 0)
msgs[0].flags = I2C_M_IGNORE_NAK;
else
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &segment;
// set offset
msgs[1].addr = addr>>1;
msgs[1].flags = 0;
msgs[1].len = 1;
msgs[1].buf = &offset;
// read data
msgs[2].addr = addr>>1;
msgs[2].flags = I2C_M_RD;
msgs[2].len = size;
msgs[2].buf = buffer;
msgset.nmsgs = 3;
msgset.msgs = msgs;
// eddc read
if (ioctl(ddc_fd, I2C_RDWR, &msgset) < 0) {
#if DDC_DEBUG
LOGE("%s: ioctl(I2C_RDWR) failed!!!", __func__);
#endif
ret = 0;
}
return ret;
}
/**
* Write data though DDC. For more information of DDC, refer DDC Spec.
* @param addr [in] Device address
* @param offset [in] Byte offset
* @param size [in] Sizes of data
* @param buffer [out] Pointer to buffer to write
* @return If succeed in writing, return 1; Otherwise, return 0.
*/
int DDCWrite(unsigned char addr, unsigned char offset, unsigned int size, unsigned char* buffer)
{
unsigned char* temp;
int bytes;
int retval = 0;
// allocate temporary buffer
temp = (unsigned char*) malloc((size+1)*sizeof(unsigned char));
if (!temp) {
LOGE("%s: not enough resources at %s", __FUNCTION__);
goto exit;
}
temp[0] = offset;
memcpy(temp+1,buffer,size);
if (!DDCFileAvailable()) {
LOGE("%s: I2C_DDC is not available!!!!", __func__);
goto exit;
}
if (ioctl(ddc_fd, I2C_SLAVE, addr>>1) < 0) {
LOGE("%s: cannot set slave address 0x%02x", __func__,addr);
goto exit;
}
// write temp buffer
if ((bytes = write(ddc_fd,temp,size+1)) != (size+1)) {
LOGE("%s: fail to write %d bytes, only write %d bytes",__func__, size, bytes);
goto exit;
}
retval = 1;
exit:
// free temp buffer
if (temp)
free(temp);
return retval;
}