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