1 /* 2 * Author: Brendan Le Foll <brendan.le.foll (at) intel.com> 3 * Copyright (c) 2014 Intel Corporation. 4 * 5 * Code is modified from the RoadNarrows-robotics i2c library (distributed under 6 * the MIT license, license is included verbatim under src/i2c/LICENSE) 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 #include "i2c.h" 29 #include "mraa_internal.h" 30 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <inttypes.h> 35 #include <sys/types.h> 36 #include <sys/errno.h> 37 #include <sys/ioctl.h> 38 #include "linux/i2c-dev.h" 39 40 41 typedef union i2c_smbus_data_union { 42 uint8_t byte; ///< data byte 43 unsigned short word; ///< data short word 44 uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; 45 ///< block[0] is used for length and one more for PEC 46 } i2c_smbus_data_t; 47 48 typedef struct i2c_smbus_ioctl_data_struct { 49 uint8_t read_write; ///< operation direction 50 uint8_t command; ///< ioctl command 51 int size; ///< data size 52 i2c_smbus_data_t* data; ///< data 53 } i2c_smbus_ioctl_data_t; 54 55 56 // static mraa_adv_func_t* func_table; 57 58 int 59 mraa_i2c_smbus_access(int fh, uint8_t read_write, uint8_t command, int size, i2c_smbus_data_t* data) 60 { 61 i2c_smbus_ioctl_data_t args; 62 63 args.read_write = read_write; 64 args.command = command; 65 args.size = size; 66 args.data = data; 67 68 return ioctl(fh, I2C_SMBUS, &args); 69 } 70 71 static mraa_i2c_context 72 mraa_i2c_init_internal(mraa_adv_func_t* advance_func, unsigned int bus) 73 { 74 mraa_result_t status = MRAA_SUCCESS; 75 76 if (advance_func == NULL) 77 return NULL; 78 79 mraa_i2c_context dev = (mraa_i2c_context) calloc(1, sizeof(struct _i2c)); 80 if (dev == NULL) { 81 syslog(LOG_CRIT, "i2c: Failed to allocate memory for context"); 82 return NULL; 83 } 84 85 dev->advance_func = advance_func; 86 dev->busnum = bus; 87 88 if (IS_FUNC_DEFINED(dev, i2c_init_pre)) { 89 status = advance_func->i2c_init_pre(bus); 90 if (status != MRAA_SUCCESS) 91 goto init_internal_cleanup; 92 } 93 94 if (IS_FUNC_DEFINED(dev, i2c_init_bus_replace)) { 95 status = dev->advance_func->i2c_init_bus_replace(dev); 96 if (status != MRAA_SUCCESS) 97 goto init_internal_cleanup; 98 } else { 99 char filepath[32]; 100 snprintf(filepath, 32, "/dev/i2c-%u", bus); 101 if ((dev->fh = open(filepath, O_RDWR)) < 1) { 102 syslog(LOG_ERR, "i2c: Failed to open requested i2c port %s", filepath); 103 status = MRAA_ERROR_NO_RESOURCES; 104 goto init_internal_cleanup; 105 } 106 107 if (ioctl(dev->fh, I2C_FUNCS, &dev->funcs) < 0) { 108 syslog(LOG_CRIT, "i2c: Failed to get I2C_FUNC map from device"); 109 dev->funcs = 0; 110 } 111 } 112 113 if (IS_FUNC_DEFINED(dev, i2c_init_post)) { 114 status = dev->advance_func->i2c_init_post(dev); 115 if (status != MRAA_SUCCESS) 116 goto init_internal_cleanup; 117 } 118 119 120 init_internal_cleanup: 121 if (status == MRAA_SUCCESS) { 122 return dev; 123 } else { 124 if (dev != NULL) 125 free(dev); 126 return NULL; 127 } 128 } 129 130 131 mraa_i2c_context 132 mraa_i2c_init(int bus) 133 { 134 mraa_board_t* board = plat; 135 if (board == NULL) { 136 syslog(LOG_ERR, "i2c: Platform Not Initialised"); 137 return NULL; 138 } 139 140 if (mraa_is_sub_platform_id(bus)) { 141 syslog(LOG_NOTICE, "i2c: Using sub platform"); 142 board = board->sub_platform; 143 if (board == NULL) { 144 syslog(LOG_ERR, "i2c: Sub platform Not Initialised"); 145 return NULL; 146 } 147 bus = mraa_get_sub_platform_index(bus); 148 } 149 syslog(LOG_NOTICE, "i2c: Selected bus %d", bus); 150 151 if (board->i2c_bus_count == 0) { 152 syslog(LOG_ERR, "No i2c buses defined in platform"); 153 return NULL; 154 } 155 if (bus >= board->i2c_bus_count) { 156 syslog(LOG_ERR, "Above i2c bus count"); 157 return NULL; 158 } 159 160 if (board->i2c_bus[bus].bus_id == -1) { 161 syslog(LOG_ERR, "Invalid i2c bus, moving to default i2c bus"); 162 bus = board->def_i2c_bus; 163 } 164 if (!board->no_bus_mux) { 165 int pos = board->i2c_bus[bus].sda; 166 if (board->pins[pos].i2c.mux_total > 0) { 167 if (mraa_setup_mux_mapped(board->pins[pos].i2c) != MRAA_SUCCESS) { 168 syslog(LOG_ERR, "i2c: Failed to set-up i2c sda multiplexer"); 169 return NULL; 170 } 171 } 172 173 pos = board->i2c_bus[bus].scl; 174 if (board->pins[pos].i2c.mux_total > 0) { 175 if (mraa_setup_mux_mapped(board->pins[pos].i2c) != MRAA_SUCCESS) { 176 syslog(LOG_ERR, "i2c: Failed to set-up i2c scl multiplexer"); 177 return NULL; 178 } 179 } 180 } 181 182 return mraa_i2c_init_internal(board->adv_func, (unsigned int) board->i2c_bus[bus].bus_id); 183 } 184 185 186 mraa_i2c_context 187 mraa_i2c_init_raw(unsigned int bus) 188 { 189 return mraa_i2c_init_internal(plat == NULL ? NULL : plat->adv_func, bus); 190 } 191 192 193 mraa_result_t 194 mraa_i2c_frequency(mraa_i2c_context dev, mraa_i2c_mode_t mode) 195 { 196 if (IS_FUNC_DEFINED(dev, i2c_set_frequency_replace)) { 197 return dev->advance_func->i2c_set_frequency_replace(dev, mode); 198 } 199 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 200 } 201 202 int 203 mraa_i2c_read(mraa_i2c_context dev, uint8_t* data, int length) 204 { 205 int bytes_read = 0; 206 if (IS_FUNC_DEFINED(dev, i2c_read_replace)) { 207 bytes_read = dev->advance_func->i2c_read_replace(dev, data, length); 208 } 209 else { 210 bytes_read = read(dev->fh, data, length); 211 } 212 if (bytes_read == length) { 213 return length; 214 } 215 216 return 0; 217 } 218 219 uint8_t 220 mraa_i2c_read_byte(mraa_i2c_context dev) 221 { 222 if (IS_FUNC_DEFINED(dev, i2c_read_byte_replace)) 223 return dev->advance_func->i2c_read_byte_replace(dev); 224 i2c_smbus_data_t d; 225 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_READ, I2C_NOCMD, I2C_SMBUS_BYTE, &d) < 0) { 226 syslog(LOG_ERR, "i2c: Failed to write"); 227 return 0; 228 } 229 return 0x0FF & d.byte; 230 } 231 232 uint8_t 233 mraa_i2c_read_byte_data(mraa_i2c_context dev, uint8_t command) 234 { 235 if (IS_FUNC_DEFINED(dev, i2c_read_byte_data_replace)) 236 return dev->advance_func->i2c_read_byte_data_replace(dev, command); 237 i2c_smbus_data_t d; 238 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &d) < 0) { 239 syslog(LOG_ERR, "i2c: Failed to write"); 240 return 0; 241 } 242 return 0x0FF & d.byte; 243 } 244 245 uint16_t 246 mraa_i2c_read_word_data(mraa_i2c_context dev, uint8_t command) 247 { 248 if (IS_FUNC_DEFINED(dev, i2c_read_word_data_replace)) 249 return dev->advance_func->i2c_read_word_data_replace(dev, command); 250 i2c_smbus_data_t d; 251 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &d) < 0) { 252 syslog(LOG_ERR, "i2c: Failed to write"); 253 return 0; 254 } 255 return 0xFFFF & d.word; 256 } 257 258 int 259 mraa_i2c_read_bytes_data(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length) 260 { 261 if (IS_FUNC_DEFINED(dev, i2c_read_bytes_data_replace)) 262 return dev->advance_func->i2c_read_bytes_data_replace(dev, command, data, length); 263 struct i2c_rdwr_ioctl_data d; 264 struct i2c_msg m[2]; 265 266 m[0].addr = dev->addr; 267 m[0].flags = 0x00; 268 m[0].len = 1; 269 m[0].buf = &command; 270 m[1].addr = dev->addr; 271 m[1].flags = I2C_M_RD; 272 m[1].len = length; 273 m[1].buf = data; 274 275 d.msgs = m; 276 d.nmsgs = 2; 277 278 return ioctl(dev->fh, I2C_RDWR, &d) < 0 ? -1 : length; 279 } 280 281 mraa_result_t 282 mraa_i2c_write(mraa_i2c_context dev, const uint8_t* data, int length) 283 { 284 if (IS_FUNC_DEFINED(dev, i2c_write_replace)) 285 return dev->advance_func->i2c_write_replace(dev, data, length); 286 i2c_smbus_data_t d; 287 int i; 288 uint8_t command = data[0]; 289 290 data = &data[1]; 291 length = length - 1; 292 if (length > I2C_SMBUS_I2C_BLOCK_MAX) { 293 length = I2C_SMBUS_I2C_BLOCK_MAX; 294 } 295 296 for (i = 1; i <= length; i++) { 297 d.block[i] = data[i - 1]; 298 } 299 d.block[0] = length; 300 301 return mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &d); 302 } 303 304 mraa_result_t 305 mraa_i2c_write_byte(mraa_i2c_context dev, const uint8_t data) 306 { 307 if (IS_FUNC_DEFINED(dev, i2c_write_byte_replace)) { 308 return dev->advance_func->i2c_write_byte_replace(dev, data); 309 } else { 310 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) < 0) { 311 syslog(LOG_ERR, "i2c: Failed to write"); 312 return MRAA_ERROR_INVALID_HANDLE; 313 } 314 return MRAA_SUCCESS; 315 } 316 } 317 318 mraa_result_t 319 mraa_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const uint8_t command) 320 { 321 if (IS_FUNC_DEFINED(dev, i2c_write_byte_data_replace)) 322 return dev->advance_func->i2c_write_byte_data_replace(dev, data, command); 323 i2c_smbus_data_t d; 324 d.byte = data; 325 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &d) < 0) { 326 syslog(LOG_ERR, "i2c: Failed to write"); 327 return MRAA_ERROR_INVALID_HANDLE; 328 } 329 return MRAA_SUCCESS; 330 } 331 332 mraa_result_t 333 mraa_i2c_write_word_data(mraa_i2c_context dev, const uint16_t data, const uint8_t command) 334 { 335 if (IS_FUNC_DEFINED(dev, i2c_write_word_data_replace)) 336 return dev->advance_func->i2c_write_word_data_replace(dev, data, command); 337 i2c_smbus_data_t d; 338 d.word = data; 339 if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &d) < 0) { 340 syslog(LOG_ERR, "i2c: Failed to write"); 341 return MRAA_ERROR_INVALID_HANDLE; 342 } 343 return MRAA_SUCCESS; 344 } 345 346 mraa_result_t 347 mraa_i2c_address(mraa_i2c_context dev, uint8_t addr) 348 { 349 if (dev == NULL) { 350 return MRAA_ERROR_INVALID_HANDLE; 351 } 352 353 dev->addr = (int) addr; 354 if (IS_FUNC_DEFINED(dev, i2c_address_replace)) { 355 return dev->advance_func->i2c_address_replace(dev, addr); 356 } else { 357 if (ioctl(dev->fh, I2C_SLAVE_FORCE, addr) < 0) { 358 syslog(LOG_ERR, "i2c: Failed to set slave address %d", addr); 359 return MRAA_ERROR_INVALID_HANDLE; 360 } 361 return MRAA_SUCCESS; 362 } 363 } 364 365 366 mraa_result_t 367 mraa_i2c_stop(mraa_i2c_context dev) 368 { 369 free(dev); 370 return MRAA_SUCCESS; 371 } 372 373