2 * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <sys/ioctl.h>
20 #include <system_info.h>
22 #include "peripheral_io.h"
23 #include "peripheral_interface_common.h"
24 #include "peripheral_log.h"
26 #define PERIPHERAL_IO_I2C_FEATURE "http://tizen.org/feature/peripheral_io.i2c"
28 #define I2C_FEATURE_UNKNOWN -1
29 #define I2C_FEATURE_FALSE 0
30 #define I2C_FEATURE_TRUE 1
32 #define I2C_SLAVE 0x0703 /* Use this slave address */
33 #define I2C_SMBUS 0x0720 /* SMBus transfer */
35 /* i2c_smbus_xfer read or write markers */
36 #define I2C_SMBUS_READ 1
37 #define I2C_SMBUS_WRITE 0
39 /* SMBus transaction types */
40 #define I2C_SMBUS_QUICK 0
41 #define I2C_SMBUS_BYTE 1
42 #define I2C_SMBUS_BYTE_DATA 2
43 #define I2C_SMBUS_WORD_DATA 3
46 * Data for SMBus Messages
48 #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
50 union i2c_smbus_data {
53 uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
54 /* and one more for user-space compatibility */
57 /* This is the structure as used in the I2C_SMBUS ioctl call */
58 struct i2c_smbus_ioctl_data {
62 union i2c_smbus_data *data;
65 static int i2c_feature = I2C_FEATURE_UNKNOWN;
67 static bool __is_feature_supported(void)
69 int ret = SYSTEM_INFO_ERROR_NONE;
72 if (i2c_feature == I2C_FEATURE_UNKNOWN) {
73 ret = system_info_get_platform_bool(PERIPHERAL_IO_I2C_FEATURE, &feature);
74 RETVM_IF(ret != SYSTEM_INFO_ERROR_NONE, false, "Failed to get system info");
76 i2c_feature = (feature ? I2C_FEATURE_TRUE : I2C_FEATURE_FALSE);
79 return (i2c_feature == I2C_FEATURE_TRUE ? true : false);
82 static inline void cleanup_handlep(peripheral_i2c_h *handle) {
83 if (*handle != NULL) {
84 if ((*handle)->fd != -1)
90 int peripheral_i2c_open_flags(int bus, int address, peripheral_open_flags_e flags, peripheral_i2c_h *i2c)
92 int ret = PERIPHERAL_ERROR_NONE;
93 int lock_type = LOCK_EX;
95 #define DEV_PATH_BASE "/dev/i2c-"
96 char path[sizeof(DEV_PATH_BASE "0000000000")] = {0, }; /* space for /dev/i2c-%d */
98 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
99 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid i2c handle");
100 RETVM_IF(bus < 0 || address < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
101 RETVM_IF(flags != PERIPHERAL_OPEN_FLAGS_PRIVATE && flags != PERIPHERAL_OPEN_FLAGS_SHARED,
102 PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid flags");
104 __attribute__ ((cleanup(cleanup_handlep))) peripheral_i2c_h handle = NULL;
106 handle = (peripheral_i2c_h)malloc(sizeof(struct _peripheral_i2c_s));
107 if (handle == NULL) {
108 _E("Failed to allocate peripheral_i2c_h");
109 return PERIPHERAL_ERROR_OUT_OF_MEMORY;
112 snprintf(path, sizeof path, DEV_PATH_BASE "%d", bus);
113 handle->fd = open(path, O_RDWR | O_CLOEXEC);
114 CHECK_ERROR(handle->fd < 0);
116 ret = ioctl(handle->fd, I2C_SLAVE, address);
119 if (flags == PERIPHERAL_OPEN_FLAGS_SHARED)
122 if (flock(handle->fd, lock_type | LOCK_NB)) {
123 if (errno == EWOULDBLOCK) {
124 _E("bus : %d, address : 0x%x is not available", bus, address);
125 return PERIPHERAL_ERROR_RESOURCE_BUSY;
127 _E("bus : %d, address : 0x%x flock() error: %d", bus, address, errno);
128 return PERIPHERAL_ERROR_IO_ERROR;
135 return PERIPHERAL_ERROR_NONE;
138 int peripheral_i2c_open(int bus, int address, peripheral_i2c_h *i2c)
140 return peripheral_i2c_open_flags(bus, address, PERIPHERAL_OPEN_FLAGS_PRIVATE, i2c);
143 int peripheral_i2c_close(peripheral_i2c_h i2c)
145 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
146 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
148 cleanup_handlep(&i2c);
150 return PERIPHERAL_ERROR_NONE;
153 int peripheral_i2c_read(peripheral_i2c_h i2c, uint8_t *data_out, uint32_t length)
155 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
156 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
157 RETVM_IF(data_out == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
159 int ret = read(i2c->fd, data_out, length);
161 return PERIPHERAL_ERROR_NONE;
163 struct i2c_smbus_ioctl_data data_arg;
164 union i2c_smbus_data data;
166 memset(&data, 0x0, sizeof(data.block));
168 data_arg.read_write = I2C_SMBUS_READ;
169 data_arg.size = I2C_SMBUS_BYTE;
170 data_arg.data = &data;
171 data_arg.command = *data_out;
173 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
174 CHECK_ERROR(ret != 0);
176 *data_out = data.byte;
178 return PERIPHERAL_ERROR_NONE;
181 int peripheral_i2c_write(peripheral_i2c_h i2c, uint8_t *data_in, uint32_t length)
183 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
184 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
185 RETVM_IF(data_in == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
187 int ret = write(i2c->fd, data_in, length);
189 return PERIPHERAL_ERROR_NONE;
191 struct i2c_smbus_ioctl_data data_arg;
192 union i2c_smbus_data data;
194 memset(&data, 0x0, sizeof(data.block));
196 data_arg.read_write = I2C_SMBUS_WRITE;
197 data_arg.size = I2C_SMBUS_BYTE;
198 data_arg.data = &data;
199 data_arg.command = *data_in;
201 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
202 CHECK_ERROR(ret != 0);
204 return PERIPHERAL_ERROR_NONE;
207 int peripheral_i2c_read_register_byte(peripheral_i2c_h i2c, uint8_t reg, uint8_t *data_out)
209 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
210 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
211 RETVM_IF(data_out == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
215 struct i2c_smbus_ioctl_data data_arg;
216 union i2c_smbus_data data;
218 memset(&data, 0x0, sizeof(data.block));
220 data_arg.read_write = I2C_SMBUS_READ;
221 data_arg.size = I2C_SMBUS_BYTE_DATA;
222 data_arg.data = &data;
223 data_arg.command = reg;
225 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
226 CHECK_ERROR(ret != 0);
228 *data_out = data.byte;
230 return PERIPHERAL_ERROR_NONE;
233 int peripheral_i2c_write_register_byte(peripheral_i2c_h i2c, uint8_t reg, uint8_t data_in)
235 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
236 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
240 struct i2c_smbus_ioctl_data data_arg;
241 union i2c_smbus_data data;
243 memset(&data, 0x0, sizeof(data.block));
245 data_arg.read_write = I2C_SMBUS_WRITE;
246 data_arg.size = I2C_SMBUS_BYTE_DATA;
247 data_arg.data = &data;
248 data_arg.command = reg;
252 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
253 CHECK_ERROR(ret != 0);
255 return PERIPHERAL_ERROR_NONE;
258 int peripheral_i2c_read_register_word(peripheral_i2c_h i2c, uint8_t reg, uint16_t *data_out)
260 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
261 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
262 RETVM_IF(data_out == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
266 struct i2c_smbus_ioctl_data data_arg;
267 union i2c_smbus_data data;
269 memset(&data, 0x0, sizeof(data.block));
271 data_arg.read_write = I2C_SMBUS_READ;
272 data_arg.size = I2C_SMBUS_WORD_DATA;
273 data_arg.data = &data;
274 data_arg.command = reg;
276 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
277 CHECK_ERROR(ret != 0);
279 *data_out = data.word;
281 return PERIPHERAL_ERROR_NONE;
284 int peripheral_i2c_write_register_word(peripheral_i2c_h i2c, uint8_t reg, uint16_t data_in)
286 RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
287 RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
291 struct i2c_smbus_ioctl_data data_arg;
292 union i2c_smbus_data data;
294 memset(&data, 0x0, sizeof(data.block));
296 data_arg.read_write = I2C_SMBUS_WRITE;
297 data_arg.size = I2C_SMBUS_WORD_DATA;
298 data_arg.data = &data;
299 data_arg.command = reg;
303 ret = ioctl(i2c->fd, I2C_SMBUS, &data_arg);
304 CHECK_ERROR(ret != 0);
306 return PERIPHERAL_ERROR_NONE;