b97f4c11599c66fe6c434931ce4c84b6b83fefde
[platform/core/api/peripheral-io.git] / src / peripheral_i2c.c
1 /*
2  * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <sys/file.h>
19 #include <sys/ioctl.h>
20 #include <system_info.h>
21
22 #include "peripheral_io.h"
23 #include "peripheral_handle.h"
24 #include "peripheral_interface_i2c.h"
25 #include "peripheral_log.h"
26
27 #define PERIPHERAL_IO_I2C_FEATURE "http://tizen.org/feature/peripheral_io.i2c"
28
29 #define I2C_FEATURE_UNKNOWN -1
30 #define I2C_FEATURE_FALSE    0
31 #define I2C_FEATURE_TRUE     1
32
33 /* i2c_smbus_xfer read or write markers */
34 #define I2C_SMBUS_READ  1
35 #define I2C_SMBUS_WRITE 0
36
37 /* SMBus transaction types */
38 #define I2C_SMBUS_QUICK             0
39 #define I2C_SMBUS_BYTE              1
40 #define I2C_SMBUS_BYTE_DATA         2
41 #define I2C_SMBUS_WORD_DATA         3
42
43 static int i2c_feature = I2C_FEATURE_UNKNOWN;
44
45 static bool __is_feature_supported(void)
46 {
47         int ret = SYSTEM_INFO_ERROR_NONE;
48         bool feature = false;
49
50         if (i2c_feature == I2C_FEATURE_UNKNOWN) {
51                 ret = system_info_get_platform_bool(PERIPHERAL_IO_I2C_FEATURE, &feature);
52                 RETVM_IF(ret != SYSTEM_INFO_ERROR_NONE, false, "Failed to get system info");
53
54                 i2c_feature = (feature ? I2C_FEATURE_TRUE : I2C_FEATURE_FALSE);
55         }
56
57         return (i2c_feature == I2C_FEATURE_TRUE ? true : false);
58 }
59
60 static inline void cleanup_handlep(peripheral_i2c_h *handle) {
61         if (*handle != NULL) {
62                 if ((*handle)->fd != -1)
63                         close((*handle)->fd);
64                 free(*handle);
65         }
66 }
67
68 int peripheral_i2c_open_flags(int bus, int address, peripheral_open_flags_e flags, peripheral_i2c_h *i2c)
69 {
70         int ret = PERIPHERAL_ERROR_NONE;
71         int lock_type = LOCK_EX;
72
73 #define DEV_PATH_BASE "/dev/i2c-"
74         char path[sizeof(DEV_PATH_BASE "0000000000")] = {0, };  /* space for /dev/i2c-%d */
75
76         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
77         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid i2c handle");
78         RETVM_IF(bus < 0 || address < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
79         RETVM_IF(flags != PERIPHERAL_OPEN_FLAGS_PRIVATE && flags != PERIPHERAL_OPEN_FLAGS_SHARED,
80                         PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid flags");
81
82         __attribute__ ((cleanup(cleanup_handlep))) peripheral_i2c_h handle = NULL;
83
84         handle = (peripheral_i2c_h)malloc(sizeof(struct _peripheral_i2c_s));
85         if (handle == NULL) {
86                 _E("Failed to allocate peripheral_i2c_h");
87                 return PERIPHERAL_ERROR_OUT_OF_MEMORY;
88         }
89
90         snprintf(path, sizeof path, DEV_PATH_BASE "%d", bus);
91         handle->fd = open(path, O_RDWR | O_CLOEXEC);
92         CHECK_ERROR(handle->fd < 0);
93
94         ret = ioctl(handle->fd, I2C_SLAVE, address);
95         CHECK_ERROR(ret);
96
97         if (flags == PERIPHERAL_OPEN_FLAGS_SHARED)
98                 lock_type = LOCK_SH;
99
100         if (flock(handle->fd, lock_type | LOCK_NB)) {
101                 if (errno == EWOULDBLOCK) {
102                         _E("bus : %d, address : 0x%x is not available", bus, address);
103                         return PERIPHERAL_ERROR_RESOURCE_BUSY;
104                 } else {
105                         _E("bus : %d, address : 0x%x flock() error: %d", bus, address, errno);
106                         return PERIPHERAL_ERROR_IO_ERROR;
107                 }
108         }
109
110         *i2c = handle;
111         handle = NULL;
112
113         return PERIPHERAL_ERROR_NONE;
114 }
115
116 int peripheral_i2c_open(int bus, int address, peripheral_i2c_h *i2c)
117 {
118         return peripheral_i2c_open_flags(bus, address, PERIPHERAL_OPEN_FLAGS_PRIVATE, i2c);
119 }
120
121 int peripheral_i2c_close(peripheral_i2c_h i2c)
122 {
123         int ret = PERIPHERAL_ERROR_NONE;
124
125         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
126         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
127
128         peripheral_interface_i2c_close(i2c);
129
130         free(i2c);
131         i2c = NULL;
132
133         return ret;
134 }
135
136 int peripheral_i2c_read(peripheral_i2c_h i2c, uint8_t *data, uint32_t length)
137 {
138         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
139         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
140         RETVM_IF(data == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
141
142         return peripheral_interface_i2c_read(i2c, data, length);
143 }
144
145 int peripheral_i2c_write(peripheral_i2c_h i2c, uint8_t *data, uint32_t length)
146 {
147         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
148         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
149         RETVM_IF(data == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
150
151         return peripheral_interface_i2c_write(i2c, data, length);
152 }
153
154 int peripheral_i2c_read_register_byte(peripheral_i2c_h i2c, uint8_t reg, uint8_t *data)
155 {
156         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
157         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
158         RETVM_IF(data == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
159
160         return peripheral_interface_i2c_read_register_byte(i2c, reg, data);
161 }
162
163 int peripheral_i2c_write_register_byte(peripheral_i2c_h i2c, uint8_t reg, uint8_t data)
164 {
165         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
166         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
167
168         return peripheral_interface_i2c_write_register_byte(i2c, reg, data);
169 }
170
171 int peripheral_i2c_read_register_word(peripheral_i2c_h i2c, uint8_t reg, uint16_t *data)
172 {
173         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
174         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
175         RETVM_IF(data == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid parameter");
176
177         return peripheral_interface_i2c_read_register_word(i2c, reg, data);
178 }
179
180 int peripheral_i2c_write_register_word(peripheral_i2c_h i2c, uint8_t reg, uint16_t data)
181 {
182         RETVM_IF(__is_feature_supported() == false, PERIPHERAL_ERROR_NOT_SUPPORTED, "I2C feature is not supported");
183         RETVM_IF(i2c == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "i2c handle is NULL");
184
185         return peripheral_interface_i2c_write_register_word(i2c, reg, data);
186 }