1e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang/*
2e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * Author: Henry Bruce <henry.bruce@intel.com>
3e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * Copyright (c) 2015 Intel Corporation.
4e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang *
5e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * Permission is hereby granted, free of charge, to any person obtaining
6e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * a copy of this software and associated documentation files (the
7e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * "Software"), to deal in the Software without restriction, including
8e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * without limitation the rights to use, copy, modify, merge, publish,
9e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * distribute, sublicense, and/or sell copies of the Software, and to
10e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * permit persons to whom the Software is furnished to do so, subject to
11e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * the following conditions:
12e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang *
13e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * The above copyright notice and this permission notice shall be
14e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * included in all copies or substantial portions of the Software.
15e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang *
16e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang */
24e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
25e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include <stdlib.h>
26e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include <string.h>
27e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include <time.h>
286b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#include <sys/time.h>
29e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include <errno.h>
30e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include "linux/i2c-dev.h"
31e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include "common.h"
32e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include "ftd2xx.h"
33e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include "libft4222.h"
34e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#include "usb/ftdi_ft4222.h"
35e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
36e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#define PLATFORM_NAME "FTDI FT4222"
37e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#define I2CM_ERROR(status) (((status) &0x02) != 0)
38e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang#define PCA9672_ADDR 0x20
396b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#define PCA9545_ADDR 0x70
406b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#define PCA9672_PINS 8
416b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#define PCA9545_BUSSES 4
426b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#define GPIO_PORT_IO_RESET GPIO_PORT2
436b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#define GPIO_PORT_IO_STATUS GPIO_PORT3
446b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
456b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic FT_HANDLE ftHandleGpio = (FT_HANDLE) NULL; //GPIO Handle
466b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic FT_HANDLE ftHandleI2c = (FT_HANDLE) NULL; //I2C/SPI Handle
476b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic FT_HANDLE ftHandleSpi = (FT_HANDLE) NULL; //I2C/SPI Handle
487d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serbanstatic GPIO_Dir pinDirection[] = {GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT};
49e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int bus_speed = 400;
506b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int numFt4222GpioPins = 4;
516b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int numI2cGpioExpanderPins = 8;
526b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int numI2cSwitchBusses = 4;
536b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int currentI2cBus = 0;
54e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
55e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_result_t
56e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_init()
57e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
586b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraa_result_t mraaStatus = MRAA_ERROR_NO_RESOURCES;
59e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    FT_DEVICE_LIST_INFO_NODE* devInfo = NULL;
607d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    FT_STATUS ftStatus;
61e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    DWORD numDevs = 0;
62e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    int i;
63e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    int retCode = 0;
64e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
65e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    ftStatus = FT_CreateDeviceInfoList(&numDevs);
66e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (ftStatus != FT_OK) {
67e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT_CreateDeviceInfoList failed: error code %d\n", ftStatus);
68e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
69e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
70e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
71e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    devInfo = calloc((size_t) numDevs, sizeof(FT_DEVICE_LIST_INFO_NODE));
72e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (devInfo == NULL) {
73e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222 allocation failure.\n");
74e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
75e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
76e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
77e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs);
786b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    syslog(LOG_NOTICE, "FT_GetDeviceInfoList returned %d devices\n", numDevs);
79e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (ftStatus != FT_OK) {
80e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT_GetDeviceInfoList failed (error code %d)\n", (int) ftStatus);
81e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
82e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
836b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (numDevs < 2) {
846b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "No FT4222 devices connected.\n");
856b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        goto init_exit;
866b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
877d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    if(numDevs > 2) {
887d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        syslog(LOG_ERR, "CNFMODE not supported. Valid modes are 0 or 3.\n");
89e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
90e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
91e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
926b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // FIXME: Assumes just one physical FTDI device present
936b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    DWORD locationIdI2c = 0;
946b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    DWORD locationIdGpio = 0;
956b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (devInfo[0].Type == FT_DEVICE_4222H_0)
966b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            locationIdI2c = devInfo[0].LocId;
976b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (devInfo[1].Type == FT_DEVICE_4222H_0)
986b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            locationIdGpio = devInfo[1].LocId;
997d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban
1006b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (locationIdI2c == 0) {
1016b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT_GetDeviceInfoList contains no I2C controllers\n");
1026b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        goto init_exit;
1036b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
1047d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban
1056b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (locationIdGpio == 0) {
1066b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT_GetDeviceInfoList contains no GPIO controllers\n");
1076b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        goto init_exit;
1086b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
1096b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
1106b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ftStatus = FT_OpenEx((PVOID)(uintptr_t) locationIdI2c, FT_OPEN_BY_LOCATION, &ftHandleI2c);
1116b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (ftStatus != FT_OK) {
1126b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT_OpenEx failed (error %d)\n", (int) ftStatus);
1136b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        goto init_exit;
1147d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
1157d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban
1166b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ftStatus = FT_OpenEx((PVOID)(uintptr_t) locationIdGpio, FT_OPEN_BY_LOCATION, &ftHandleGpio);
117e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (ftStatus != FT_OK) {
1186b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT_OpenEx failed (error %d)\n", (int) ftStatus);
1196b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        goto init_exit;
1206b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
1216b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
1226b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    FT4222_SetSuspendOut(ftHandleGpio, 0);
1236b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    FT4222_SetWakeUpInterrupt(ftHandleGpio, 0);
1246b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ftStatus =  FT4222_GPIO_Init(ftHandleGpio, pinDirection);
1256b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (ftStatus != FT_OK) {
1266b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT4222_GPIO_Init failed (error %d)\n", (int) ftStatus);
127e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        mraaStatus = MRAA_ERROR_NO_RESOURCES;
128e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
129e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
130e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
1317d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    // Tell the FT4222 to be an I2C Master by default on init.
1326b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    FT4222_STATUS ft4222Status = FT4222_I2CMaster_Init(ftHandleI2c, bus_speed);
133e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status) {
134e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222_I2CMaster_Init failed (error %d)!\n", ft4222Status);
135e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
136e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
137e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
1386b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ft4222Status = FT4222_I2CMaster_Reset(ftHandleI2c);
139e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status) {
140e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222_I2CMaster_Reset failed (error %d)!\n", ft4222Status);
141e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        goto init_exit;
142e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
143e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
1446b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraaStatus = MRAA_SUCCESS;
1456b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
146e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhanginit_exit:
147e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (devInfo != NULL)
1486b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        free(devInfo);
149e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (mraaStatus == MRAA_SUCCESS)
150e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_NOTICE, "mraa_ftdi_ft4222_init completed successfully\n");
151e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return mraaStatus;
152e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
153e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
154e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
155e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_result_t
156e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_get_version(unsigned int* versionChip, unsigned int* versionLib)
157e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
1586b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (ftHandleI2c != NULL) {
159e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        FT4222_Version ft4222Version;
1606b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_STATUS ft4222Status = FT4222_GetVersion(ftHandleI2c, &ft4222Version);
161e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        if (FT4222_OK == ft4222Status) {
162e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            *versionChip = (unsigned int) ft4222Version.chipVersion;
163e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            *versionLib = (unsigned int) ft4222Version.dllVersion;
164e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            syslog(LOG_NOTICE, "FT4222_GetVersion %08X %08X\n", *versionChip, *versionLib);
165e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            return MRAA_SUCCESS;
166e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        } else {
1676b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            syslog(LOG_ERR, "FT4222_GetVersion failed (error %d)\n", (int) ft4222Status);
168e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            return MRAA_ERROR_NO_RESOURCES;
169e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        }
170e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    } else {
1716b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "Bad FT4222 handle\n");
172e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return MRAA_ERROR_INVALID_HANDLE;
173e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
174e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
175e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
176e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
1776b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare/******************* Private I2C functions *******************/
1786b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
179e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int
180e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data, int length)
181e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
182e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint16 bytesRead = 0;
183e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8 controllerStatus;
184e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    // syslog(LOG_NOTICE, "FT4222_I2CMaster_Read(%#02X, %#02X)", addr, length);
185e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    FT4222_STATUS ft4222Status = FT4222_I2CMaster_Read(handle, addr, data, length, &bytesRead);
1866b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus);
187e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) {
1886b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT4222_I2CMaster_Read failed for address %#02x\n", addr);
1896b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_I2CMaster_Reset(handle);
190e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return 0;
191e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
192e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return bytesRead;
193e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
194e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
195e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int
196e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_t* data, int bytesToWrite)
197e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
198e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint16 bytesWritten = 0;
199e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8 controllerStatus;
200e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    // syslog(LOG_NOTICE, "FT4222_I2CMaster_Write(%#02X, %#02X, %d)", addr, *data, bytesToWrite);
2016b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    FT4222_STATUS ft4222Status = FT4222_I2CMaster_Write(handle, addr, (uint8_t*) data, bytesToWrite, &bytesWritten);
2026b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus);
203e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) {
2046b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        syslog(LOG_ERR, "FT4222_I2CMaster_Write failed address %#02x\n", addr);
2056b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_I2CMaster_Reset(handle);
206e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return 0;
207e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
208e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
209e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (bytesWritten != bytesToWrite)
210e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222_I2CMaster_Write wrote %u of %u bytes.\n", bytesWritten, bytesToWrite);
211e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
212e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return bytesWritten;
213e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
214e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2156b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2166b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare// Function detects known I2C I/O expanders and returns the number of GPIO pins on expander
2177d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serbanstatic int
218e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_detect_io_expander()
219e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
220e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8_t data;
2216b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if(mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, &data, 1) == 1) {
2226b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return PCA9672_PINS;
2237d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
2247d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    return 0;
225e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
226e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
227e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2286b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic mraa_boolean_t
2296b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_is_internal_gpio(int pin)
230e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
2316b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return pin < numFt4222GpioPins;
2326b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
233e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2346b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2356b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic mraa_result_t
2366b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beareftdi_ft4222_set_internal_gpio_dir(int pin, GPIO_Dir direction)
2376b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2386b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    pinDirection[pin] = direction;
2396b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (FT4222_GPIO_Init(ftHandleGpio, pinDirection) != FT4222_OK)
2406b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return MRAA_ERROR_UNSPECIFIED;
2416b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    else
2426b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return MRAA_SUCCESS;
2436b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
2446b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2456b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare// Function detects known I2C switches and returns the number of busses.
2466b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare// On startup switch is disabled so default bus will be integrated i2c bus.
2476b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int
2486b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_detect_i2c_switch()
2496b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2506b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    uint8_t data;
2516b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if(mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1) {
2526b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        data = 0;
2536b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1 ? PCA9545_BUSSES : 0;
254e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
2556b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return 0;
2566b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
257e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2586b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2596b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic mraa_result_t
2606b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_i2c_select_bus(int bus)
2616b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2626b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (bus != currentI2cBus) {
2636b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint8_t data;
2646b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (bus == 0)
2656b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            data = 0;
2666b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        else
2676b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            data = 1 << (bus-1);
2686b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9545_ADDR, &data, 1) == 1)
2696b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            currentI2cBus = bus;
2706b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        else
2716b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            return MRAA_ERROR_UNSPECIFIED;
272e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
2736b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return MRAA_SUCCESS;
2746b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
275e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2766b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int
2776b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_i2c_context_read(mraa_i2c_context dev, uint8_t* data, int length)
2786b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2796b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS)
2806b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return mraa_ftdi_ft4222_i2c_read_internal(dev->handle, dev->addr, data, length);
2816b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    else
2826b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return 0;
283e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
284e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
2856b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic int
2866b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_i2c_context_write(mraa_i2c_context dev, uint8_t* data, int length)
2876b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2886b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_select_bus(dev->busnum) == MRAA_SUCCESS)
2896b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return mraa_ftdi_ft4222_i2c_write_internal(dev->handle, dev->addr, data, length);
2906b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    else
2916b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        return 0;
2926b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
2936b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2946b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
2956b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic void
2966b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_sleep_ms(unsigned long mseconds)
2976b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
2986b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    struct timespec sleepTime;
2996b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
3006b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sleepTime.tv_sec = mseconds / 1000;              // Number of seconds
3016b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds
3026b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
3036b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // Iterate nanosleep in a loop until the total sleep time is the original
3046b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // value of the seconds parameter
3056b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR))
3066b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        ;
3076b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
3086b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
3096b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearestatic unsigned int
3106b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_get_tick_count_ms()
3116b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare{
3126b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    static unsigned int startTick = 0;
3136b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    unsigned int ticks;
3146b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    struct timeval now;
3156b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    gettimeofday(&now, NULL);
3166b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ticks = now.tv_sec * 1000;
3176b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ticks += now.tv_usec / 1000;
3186b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (startTick == 0)
3196b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        startTick = ticks;
3206b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return ticks - startTick;
3216b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare}
3226b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
3236b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
3246b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare/******************* I2C functions *******************/
3256b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
326e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
327e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_init_bus_replace(mraa_i2c_context dev)
328e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
329e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    // Tell the FT4222 to be an I2C Master.
3306b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    FT4222_STATUS ft4222Status = FT4222_I2CMaster_Init(ftHandleI2c, bus_speed);
331e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status) {
332e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222_I2CMaster_Init failed (error %d)!\n", ft4222Status);
333e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return MRAA_ERROR_NO_RESOURCES;
334e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
335e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
336e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    // Reset the I2CM registers to a known state.
3376b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    ft4222Status = FT4222_I2CMaster_Reset(ftHandleI2c);
338e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (FT4222_OK != ft4222Status) {
339e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        syslog(LOG_ERR, "FT4222_I2CMaster_Reset failed (error %d)!\n", ft4222Status);
340e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return MRAA_ERROR_NO_RESOURCES;
341e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
342e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
3437d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    syslog(LOG_NOTICE, "I2C interface enabled GPIO0 and GPIO1 will be unavailable.\n");
3446b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    dev->handle = ftHandleI2c;
345e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    dev->fh = -1;              // We don't use file descriptors
346e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    dev->funcs = I2C_FUNC_I2C; // Advertise minimal i2c support as per
347e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang                               // https://www.kernel.org/doc/Documentation/i2c/functionality
348e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
349e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
350e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
351e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
352e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
353e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_frequency(mraa_i2c_context dev, mraa_i2c_mode_t mode)
354e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
355e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    switch (mode) {
356e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        case MRAA_I2C_STD: /**< up to 100Khz */
357e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            bus_speed = 100;
358e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            break;
359e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        MRAA_I2C_FAST: /**< up to 400Khz */
360e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            bus_speed = 400;
361e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            break;
362e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        MRAA_I2C_HIGH: /**< up to 3.4Mhz */
363e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            bus_speed = 3400;
364e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            break;
365e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
3666b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return FT4222_I2CMaster_Init(ftHandleI2c, bus_speed) == FT4222_OK ? MRAA_SUCCESS : MRAA_ERROR_NO_RESOURCES;
367e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
368e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
369e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
370e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
371e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_address(mraa_i2c_context dev, uint8_t addr)
372e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
373e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    dev->addr = (int) addr;
3746b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return MRAA_SUCCESS;
375e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
376e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
377e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
378e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int
379e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read(mraa_i2c_context dev, uint8_t* data, int length)
380e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
381e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return mraa_ftdi_ft4222_i2c_read_internal(dev->handle, dev->addr, data, length);
382e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
383e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
384e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic uint8_t
385e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read_byte(mraa_i2c_context dev)
386e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
3877d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    uint8_t data;
3886b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_context_read(dev, &data, 1) == 1)
3897d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return data;
3907d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    else
3917d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return 0;
392e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
393e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
394e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
395e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic uint16_t
396e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read_word_data(mraa_i2c_context dev, uint8_t command)
397e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
3987d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    uint8_t buf[2];
3997d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    uint16_t data;
4006b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_context_write(dev, &command, 1) != 1)
4017d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return 0;
4026b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_context_read(dev, buf, 2) != 2)
4037d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return 0;
4047d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    data = *(uint16_t*)buf;
4057d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    return data;
406e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
407e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
408e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int
409e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read_bytes_data(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length)
410e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
4116b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_i2c_context_write(dev, &command, 1) != 1)
4127d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return 0;
4136b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    return mraa_ftdi_ft4222_i2c_context_read(dev, data, length);
414e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
415e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
416e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
417e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
418e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_write(mraa_i2c_context dev, const uint8_t* data, int bytesToWrite)
419e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
4206b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    uint16 bytesWritten = mraa_ftdi_ft4222_i2c_context_write(dev, (uint8_t*)data, bytesToWrite);
421e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return bytesToWrite == bytesWritten ? MRAA_SUCCESS : MRAA_ERROR_INVALID_HANDLE;
422e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
423e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
424e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
425e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
426e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_write_byte(mraa_i2c_context dev, uint8_t data)
427e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
428e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return mraa_ftdi_ft4222_i2c_write(dev, &data, 1);
429e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
430e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
431e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
432e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic uint8_t
433e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_read_byte_data(mraa_i2c_context dev, uint8_t command)
434e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
435e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    const uint8_t reg_addr = command;
436e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8_t data;
437e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (mraa_ftdi_ft4222_i2c_write(dev, &reg_addr, 1) != MRAA_SUCCESS)
438e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return 0;
439e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (mraa_ftdi_ft4222_i2c_read(dev, &data, 1) != 1)
440e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return 0;
441e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return data;
442e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
443e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
444e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
445e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const uint8_t command)
446e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
447e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8_t buf[2];
448e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    buf[0] = command;
449e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    buf[1] = data;
450e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return mraa_ftdi_ft4222_i2c_write(dev, buf, 2);
451e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
452e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
453e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
454e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_write_word_data(mraa_i2c_context dev, const uint16_t data, const uint8_t command)
455e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
456e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    uint8_t buf[3];
457e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    buf[0] = command;
458e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    buf[1] = (uint8_t) data;
459e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    buf[2] = (uint8_t)(data >> 8);
460e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return mraa_ftdi_ft4222_i2c_write(dev, buf, 3);
461e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
462e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
463e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
464e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_i2c_stop(mraa_i2c_context dev)
465e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
466e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
467e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
468e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
469e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang/******************* GPIO functions *******************/
470e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
471e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
4726b1611a178516c059b80b1fecb9bbea070a00d0dBruce Bearemraa_ftdi_ft4222_gpio_init_internal_replace(mraa_gpio_context dev, int pin)
473e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
4746b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    dev->phy_pin = (pin < numFt4222GpioPins) ? pin : pin - numFt4222GpioPins;
4756b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (pin < 2) {
4767d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        syslog(LOG_NOTICE, "Closing I2C interface to enable GPIO%d\n", pin);
4777d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban
4787d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        /* Replace with call to SPI init when SPI is fully implemented */
4796b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_STATUS ft4222Status = FT4222_SPIMaster_Init(ftHandleSpi, SPI_IO_SINGLE, CLK_DIV_4, CLK_IDLE_HIGH, CLK_LEADING, 0x01);
4807d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        if (FT4222_OK != ft4222Status){
4817d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            syslog(LOG_ERR, "Failed to close I2C interface and start SPI (error %d)!\n", ft4222Status);
4827d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return MRAA_ERROR_NO_RESOURCES;
4837d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        }
4847d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
485e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
486e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
487e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
488e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
489e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode)
490e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
491e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
492e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
493e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
494e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
495e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode)
496e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
497e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
498e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
499e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
500e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic int
501e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_read_replace(mraa_gpio_context dev)
502e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
5036b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    uint8_t pin = dev->pin;
5046b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_is_internal_gpio(pin)) {
5057d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        // FTDI GPIO
5066b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        BOOL value;
5076b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_STATUS ft4222Status = FT4222_GPIO_Read(ftHandleGpio, dev->phy_pin, &value);
5087d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        if (FT4222_OK != ft4222Status) {
5097d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            syslog(LOG_ERR, "FT4222_GPIO_Read failed (error %d)!\n", ft4222Status);
5107d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return -1;
5117d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        }
5127d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return value;
5137d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
5147d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    else {
5157d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        // Expander GPIO
5166b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint8_t mask = 1 << dev->phy_pin;
5176b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint8_t value;
5186b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, &value, 1) != 1)
5197d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return -1;
5207d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        return (value & mask) == mask;
5217d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
522e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
523e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
524e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
525e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
526e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_write_replace(mraa_gpio_context dev, int write_value)
527e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
5286b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    uint8_t pin = dev->pin;
5296b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    if (mraa_ftdi_ft4222_is_internal_gpio(pin)) {
5307d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        // FTDI GPIO
5316b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_STATUS ft4222Status = FT4222_GPIO_Write(ftHandleGpio, dev->phy_pin, write_value);
5327d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        if (FT4222_OK != ft4222Status) {
5337d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            syslog(LOG_ERR, "FT4222_GPIO_Write failed (error %d)!\n", ft4222Status);
5347d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return MRAA_ERROR_UNSPECIFIED;
5357d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        }
5367d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
5377d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    else {
5387d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        // Expander GPIO
5396b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint8_t mask = 1 << dev->phy_pin;
5406b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint8_t value;
5416b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (mraa_ftdi_ft4222_i2c_read_internal(ftHandleI2c, PCA9672_ADDR, &value, 1) != 1)
5427d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return MRAA_ERROR_UNSPECIFIED;
5437d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        if (write_value == 1)
5447d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            value |= mask;
5457d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        else
5467d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            value &= (~mask);
5476b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (mraa_ftdi_ft4222_i2c_write_internal(ftHandleI2c, PCA9672_ADDR, &value, 1) != 1)
5487d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return MRAA_ERROR_UNSPECIFIED;
5497d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    }
550e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return MRAA_SUCCESS;
551e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
552e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
553e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic mraa_result_t
554e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir)
555e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
556e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    switch (dir) {
557e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        case MRAA_GPIO_IN:
5586b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin))
5596b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                return ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_INPUT);
5606b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            else
5616b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                return mraa_ftdi_ft4222_gpio_write_replace(dev, 1);
5627d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        case MRAA_GPIO_OUT:
5636b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin))
5646b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                return ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT);
5656b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            else
5666b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                return MRAA_SUCCESS;
567e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        case MRAA_GPIO_OUT_HIGH:
5686b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) {
5696b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                if (ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS)
5707d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban                    return MRAA_ERROR_UNSPECIFIED;
5717d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            }
572e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            return mraa_ftdi_ft4222_gpio_write_replace(dev, 1);
573e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        case MRAA_GPIO_OUT_LOW:
5746b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) {
5756b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                if (ftdi_ft4222_set_internal_gpio_dir(dev->phy_pin, GPIO_OUTPUT) != MRAA_SUCCESS)
5767d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban                    return MRAA_ERROR_UNSPECIFIED;
5777d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            }
578e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            return mraa_ftdi_ft4222_gpio_write_replace(dev, 0);
579e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        default:
5807d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban            return MRAA_ERROR_INVALID_PARAMETER;
581e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
582e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
583e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
584e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
585e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic void*
586e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_gpio_interrupt_handler_replace(mraa_gpio_context dev)
587e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
5886b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#ifdef USE_FT4222_GPIO_TRIGGER
5896b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // FIXME: Use big buffer; shouldn't be more than this many events to read
5906b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    GPIO_Trigger event_buf[256];
5916b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev);
5926b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    while (1) {
5936b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        uint16 num_events = 0;
5946b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        FT4222_STATUS status = FT4222_GPIO_GetTriggerStatus(ftHandleGpio, GPIO_PORT_IO_STATUS, &num_events);
5956b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (status != FT4222_OK)
5966b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            printf("FT4222_GPIO_GetTriggerStatus failed with code %d\n", status);
5976b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        printf("%u: FT4222_GPIO_GetTriggerStatus Events = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events);
5986b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        if (num_events > 0) {
5996b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
6006b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            uint16 num_events_read;
6016b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, GPIO_PORT_IO_STATUS, event_buf, num_events, &num_events_read);
6026b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            // printf("%u: FT4222_GPIO_ReadTriggerQueue Events= %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events_read);
6036b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            printf("%u: level = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), level);
6046b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            if (level != prev_level) {
6056b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                dev->isr(dev->isr_args);
6066b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare                prev_level = level;
6076b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare            }
6086b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
6096b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        }
6106b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        mraa_ftdi_ft4222_sleep_ms(20);
6116b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        // int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
6126b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        // printf("level = %d\n", level);
6136b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
6146b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#else
615e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev);
616e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    while (1) {
617e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
6187d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban        // MRAA_GPIO_EDGE_BOTH
619e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        if (level != prev_level) {
620e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            dev->isr(dev->isr_args);
621e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang            prev_level = level;
622e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        }
623e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        mraa_ftdi_ft4222_sleep_ms(100);
624e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
6256b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare#endif
626e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return NULL;
627e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
628e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
629e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic void
630e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_populate_i2c_func_table(mraa_adv_func_t* func_table)
631e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
632e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_init_bus_replace = &mraa_ftdi_ft4222_i2c_init_bus_replace;
633e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_set_frequency_replace = &mraa_ftdi_ft4222_i2c_frequency;
634e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_address_replace = &mraa_ftdi_ft4222_i2c_address;
635e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_read_replace = &mraa_ftdi_ft4222_i2c_read;
636e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_read_byte_replace = &mraa_ftdi_ft4222_i2c_read_byte;
637e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_read_byte_data_replace = &mraa_ftdi_ft4222_i2c_read_byte_data;
638e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_read_word_data_replace = &mraa_ftdi_ft4222_i2c_read_word_data;
639e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_read_bytes_data_replace = &mraa_ftdi_ft4222_i2c_read_bytes_data;
640e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_write_replace = &mraa_ftdi_ft4222_i2c_write;
641e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_write_byte_replace = &mraa_ftdi_ft4222_i2c_write_byte;
642e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_write_byte_data_replace = &mraa_ftdi_ft4222_i2c_write_byte_data;
643e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_write_word_data_replace = &mraa_ftdi_ft4222_i2c_write_word_data;
644e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->i2c_stop_replace = &mraa_ftdi_ft4222_i2c_stop;
645e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
646e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
647e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangstatic void
648e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222_populate_gpio_func_table(mraa_adv_func_t* func_table)
649e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
650e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_init_internal_replace = &mraa_ftdi_ft4222_gpio_init_internal_replace;
651e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_mode_replace = &mraa_ftdi_ft4222_gpio_mode_replace;
652e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_edge_mode_replace = &mraa_ftdi_ft4222_gpio_edge_mode_replace;
653e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_dir_replace = &mraa_ftdi_ft4222_gpio_dir_replace;
654e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_read_replace = &mraa_ftdi_ft4222_gpio_read_replace;
655e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_write_replace = &mraa_ftdi_ft4222_gpio_write_replace;
656e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    func_table->gpio_interrupt_handler_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_replace;
657e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
658e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
659e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
660e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_board_t*
661e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhangmraa_ftdi_ft4222()
662e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang{
663e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    mraa_board_t* sub_plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
664e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (sub_plat == NULL)
665e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return NULL;
6667d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    numI2cGpioExpanderPins = mraa_ftdi_ft4222_detect_io_expander();
667e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    int pinIndex = 0;
6686b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    int numUsbGpio = numFt4222GpioPins + numI2cGpioExpanderPins;
6696b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    int numI2cBusses = 1 + mraa_ftdi_ft4222_detect_i2c_switch();
6706b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    int numUsbPins = numUsbGpio + 2 * (numI2cBusses-1); // Add SDA and SCL for each i2c switch bus
6716b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraa_pincapabilities_t pinCapsI2c = (mraa_pincapabilities_t){ 1, 0, 0, 0, 0, 1, 0, 0 };
6726b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraa_pincapabilities_t pinCapsI2cGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 1, 0, 0 };
6736b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraa_pincapabilities_t pinCapsGpio = (mraa_pincapabilities_t){ 1, 1, 0, 0, 0, 0, 0, 0 };
6746b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
675e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->platform_name = PLATFORM_NAME;
676e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->phy_pin_count = numUsbPins;
6776b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sub_plat->gpio_count = numUsbGpio;
6786b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    mraa_pininfo_t* pins = (mraa_pininfo_t*) calloc(numUsbPins,sizeof(mraa_pininfo_t));
679e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (pins == NULL) {
680e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return NULL;
681e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
682e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->pins = pins;
683e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
684e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    int bus = 0;
6856b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sub_plat->i2c_bus_count = numI2cBusses;
686e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->def_i2c_bus = bus;
687e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->i2c_bus[bus].bus_id = bus;
688e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
6897d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    // I2c pins (these are virtual, entries are required to configure i2c layer)
6906b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // We currently assume that GPIO 0/1 are reserved for i2c operation
6916b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    strncpy(sub_plat->pins[pinIndex].name, "IGPIO0/SCL0", MRAA_PIN_NAME_SIZE);
6926b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sub_plat->pins[pinIndex].capabilites = pinCapsI2cGpio;
6937d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.pinmap = pinIndex;
6947d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.mux_total = 0;
695e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->pins[pinIndex].i2c.mux_total = 0;
6967d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->i2c_bus[bus].scl = pinIndex;
697e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    pinIndex++;
6986b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    strncpy(sub_plat->pins[pinIndex].name, "IGPIO1/SDA0", MRAA_PIN_NAME_SIZE);
6996b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    sub_plat->pins[pinIndex].capabilites = pinCapsI2cGpio;
7007d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.pinmap = pinIndex;
7017d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.mux_total = 0;
702e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->pins[pinIndex].i2c.mux_total = 0;
7037d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->i2c_bus[bus].sda = pinIndex;
7047d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    pinIndex++;
7057d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban
7067d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    // FTDI4222 gpio
7076b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    strncpy(sub_plat->pins[pinIndex].name, "INT-GPIO2", MRAA_PIN_NAME_SIZE);
7087d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].capabilites = pinCapsGpio;
7097d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.pinmap = pinIndex;
7107d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.mux_total = 0;
7117d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    pinIndex++;
7126b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    strncpy(sub_plat->pins[pinIndex].name, "INT-GPIO3", MRAA_PIN_NAME_SIZE);
7137d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].capabilites = pinCapsGpio;
7147d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.pinmap = pinIndex;
7157d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    sub_plat->pins[pinIndex].gpio.mux_total = 0;
7166b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    pinIndex++;
7176b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
7186b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // Virtual gpio pins on i2c I/O expander.
7196b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    int i;
7206b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    for (i = 0; i < numI2cGpioExpanderPins; ++i) {
7216b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "EXP-GPIO%d", i);
7226b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].capabilites = pinCapsGpio;
7236b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].gpio.pinmap = pinIndex;
7246b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].gpio.mux_total = 0;
7256b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        pinIndex++;
7266b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
7276b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
7286b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    // Now add any extra i2c busses behind i2c switch
7296b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    for (bus = 1; bus < numI2cBusses; ++bus) {
7306b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->i2c_bus[bus].bus_id = bus;
7316b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].i2c.mux_total = 0;
7326b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "SDA%d", bus);
7336b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].capabilites = pinCapsI2c;
7346b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->i2c_bus[bus].sda = pinIndex;
7356b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        pinIndex++;
7366b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        snprintf(sub_plat->pins[pinIndex].name, MRAA_PIN_NAME_SIZE, "SCL%d", bus);
7376b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].capabilites = pinCapsI2c;
7386b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->pins[pinIndex].i2c.mux_total = 0;
7396b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        sub_plat->i2c_bus[bus].scl = pinIndex;
7406b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare        pinIndex++;
7416b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare    }
7426b1611a178516c059b80b1fecb9bbea070a00d0dBruce Beare
743e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
744e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    // Set override functions
745e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    mraa_adv_func_t* func_table = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t));
746e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    if (func_table == NULL) {
747e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang        return NULL;
748e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    }
749e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    mraa_ftdi_ft4222_populate_i2c_func_table(func_table);
7507d3978fad94b70b4cb0dba9231b30870022f8563Mihai Serban    mraa_ftdi_ft4222_populate_gpio_func_table(func_table);
751e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang
752e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    sub_plat->adv_func = func_table;
753e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang    return sub_plat;
754e595125fe2f8ed6af763b9da7cfd817f576958dcJianxun Zhang}
755