/* * 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 #include #include #include #include #include #include #include #include #include #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; }