summaryrefslogtreecommitdiffstats
path: root/cpukit/dev/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/dev/i2c')
-rw-r--r--cpukit/dev/i2c/fpga-i2c-slave.c132
-rw-r--r--cpukit/dev/i2c/ti-ads-16bit-adc.c239
-rw-r--r--cpukit/dev/i2c/ti-lm25066a.c376
-rw-r--r--cpukit/dev/i2c/ti-tmp112.c229
4 files changed, 976 insertions, 0 deletions
diff --git a/cpukit/dev/i2c/fpga-i2c-slave.c b/cpukit/dev/i2c/fpga-i2c-slave.c
new file mode 100644
index 0000000000..cf00a57b41
--- /dev/null
+++ b/cpukit/dev/i2c/fpga-i2c-slave.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+/*
+ * I2C slave for testing:
+ * https://github.com/oetr/FPGA-I2C-Slave
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <dev/i2c/i2c.h>
+#include <dev/i2c/fpga-i2c-slave.h>
+
+typedef struct {
+ i2c_dev base;
+ uint16_t address;
+ size_t size;
+} fpga_i2c_slave;
+
+static ssize_t
+fpga_i2c_slave_read(i2c_dev* base, void* buf, size_t n, off_t offset)
+{
+ fpga_i2c_slave* dev = (fpga_i2c_slave*) base;
+ off_t avail = dev->size - offset;
+ uint8_t* in = buf;
+ size_t todo;
+
+ if (avail <= 0) {
+ return 0;
+ }
+
+ if (n > avail) {
+ n = (size_t) avail;
+ }
+
+ todo = n;
+
+ while (todo > 0) {
+ /*
+ * Limit the transfer size so that it can be stored in 8-bits. This may
+ * help some bus controllers.
+ */
+ uint16_t cur = (uint16_t) (todo < 255 ? todo : 255);
+ i2c_msg msgs = {
+ .addr = dev->base.address,
+ .flags = I2C_M_RD,
+ .buf = in,
+ .len = cur
+ };
+ int err;
+ err = i2c_bus_transfer(dev->base.bus, &msgs, 1);
+ if (err != 0) {
+ return err;
+ }
+ todo -= cur;
+ in += cur;
+ }
+
+ return (ssize_t) n;
+}
+
+static ssize_t
+fpga_i2c_slave_write(i2c_dev* base, const void* buf, size_t n, off_t offset)
+{
+ fpga_i2c_slave* dev = (fpga_i2c_slave*) base;
+ off_t avail = dev->size - offset;
+ const uint8_t* out = buf;
+ size_t todo;
+
+ if (avail <= 0) {
+ return 0;
+ }
+
+ if (n > avail) {
+ n = (size_t) avail;
+ }
+
+ todo = n;
+
+ while (todo > 0) {
+ /*
+ * Limit the transfer size so that it can be stored in 8-bits. This may
+ * help some bus controllers.
+ */
+ uint16_t cur = (uint16_t) (todo < 255 ? todo : 255);
+ i2c_msg msgs = {
+ .addr = dev->base.address,
+ .flags = 0,
+ .buf = RTEMS_DECONST(uint8_t*, out),
+ .len = cur
+ };
+ int err;
+ err = i2c_bus_transfer(dev->base.bus, &msgs, 1);
+ if (err != 0) {
+ return err;
+ }
+ todo -= cur;
+ out += cur;
+ }
+
+ return (ssize_t) n;
+}
+
+int
+i2c_dev_register_fpga_i2c_slave(const char* bus_path,
+ const char* dev_path,
+ uint16_t address,
+ size_t size)
+
+{
+ fpga_i2c_slave* dev;
+
+ dev = (fpga_i2c_slave*)
+ i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
+ if (dev == NULL) {
+ return -1;
+ }
+
+ dev->base.read = fpga_i2c_slave_read;
+ dev->base.write = fpga_i2c_slave_write;
+ dev->size = size;
+
+ return i2c_dev_register(&dev->base, dev_path);
+}
diff --git a/cpukit/dev/i2c/ti-ads-16bit-adc.c b/cpukit/dev/i2c/ti-ads-16bit-adc.c
new file mode 100644
index 0000000000..35e6a7eb63
--- /dev/null
+++ b/cpukit/dev/i2c/ti-ads-16bit-adc.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016-2016 Chris Johns <chrisj@rtems.org>
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <unistd.h>
+
+#include <dev/i2c/i2c.h>
+#include <dev/i2c/ti-ads-16bit-adc.h>
+
+/*
+ * Registers.
+ */
+#define ADS_CONVERSION (0)
+#define ADS_CONFIG (1)
+#define ADS_LO_THRESH (2)
+#define ADS_HI_THRESH (3)
+
+/*
+ * Configuration register.
+ */
+#define CFG_OS_NOT_CONVERTING (1 << 15) /* read */
+#define CFG_OS_START_SSHOT (1 << 15) /* write */
+#define CFG_MUX_BASE (12)
+#define CFG_MUX_MASK (7)
+#define CFG_PGA_BASE (9)
+#define CFG_PGA_MASK (7)
+#define CFG_MODE_BASE (8)
+#define CFG_MODE_MASK (1)
+#define CFG_DATA_RATE_BASE (5)
+#define CFG_DATA_RATE_MASK (7)
+#define CFG_COMP_BASE (0)
+#define CFG_COMP_MASK (0x1f)
+#define CFG_COMP_MODE_ACTIVE_LOW (0 << 4)
+#define CFG_COMP_MODE_ACTIVE_HIGH (1 << 4)
+
+#define CFG_MODE_CONT (0 << CFG_MODE_BASE)
+#define CFG_MODE_SSHOT (1 << CFG_MODE_BASE)
+
+typedef struct {
+ i2c_dev base;
+ ti_ads_adc device;
+ uint32_t poll_wait_period;
+ int reg;
+ uint16_t config_shadow;
+} ti_ads;
+
+static int
+ti_ads_reg_write(ti_ads* dev, int reg, uint16_t value)
+{
+ uint8_t out[3];
+ i2c_msg msgs[1] = {
+ {
+ .addr = dev->base.address,
+ .flags = 0,
+ .len = (uint16_t) sizeof(out),
+ .buf = &out[0]
+ }
+ };
+ out[0] = (uint8_t) reg;
+ out[1] = (uint8_t) (value >> 8);
+ out[2] = (uint8_t) value;
+ return i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+}
+
+static int
+ti_ads_reg_read(ti_ads* dev, int reg, uint16_t* value)
+{
+ uint8_t in[2] = { 0, 0 };
+ uint8_t out[1] = { (uint8_t) reg };
+ i2c_msg msgs[2] = {
+ {
+ .addr = dev->base.address,
+ .flags = 0,
+ .len = (uint16_t) sizeof(out),
+ .buf = &out[0]
+ }, {
+ .addr = dev->base.address,
+ .flags = I2C_M_RD,
+ .len = (uint16_t) sizeof(in),
+ .buf = &in[0]
+ }
+ };
+ int err;
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ *value = (((uint16_t) in[0]) << 8) | in[1];
+ return err;
+}
+
+static int
+ti_ads_set_config(ti_ads* dev, uint16_t value, int base, uint16_t mask)
+{
+ int err;
+ dev->config_shadow &= ~(mask << base);
+ dev->config_shadow |= (value & mask) << base;
+ err = ti_ads_reg_write(dev, ADS_CONFIG, dev->config_shadow);
+ return err;
+}
+
+static int
+ti_ads_sample(ti_ads* dev, uint16_t* value)
+{
+ int err;
+ if ((dev->config_shadow & CFG_MODE_SSHOT) == CFG_MODE_SSHOT) {
+ i2c_bus_obtain(dev->base.bus);
+ err = ti_ads_reg_write(dev,
+ ADS_CONFIG,
+ dev->config_shadow | CFG_OS_START_SSHOT);
+ if (err == 0) {
+ uint16_t config = 0;
+ while (err == 0 && (config & CFG_OS_NOT_CONVERTING) == 0) {
+ err = ti_ads_reg_read(dev, ADS_CONFIG, &config);
+ if (dev->poll_wait_period && (config & CFG_OS_NOT_CONVERTING) == 0)
+ usleep(dev->poll_wait_period);
+ }
+ err = ti_ads_reg_read(dev, ADS_CONVERSION, value);
+ }
+ i2c_bus_release(dev->base.bus);
+ }
+ else {
+ err = ti_ads_reg_read(dev, ADS_CONVERSION, value);
+ }
+ return err;
+}
+
+static int
+ti_ads_ioctl(i2c_dev* iic_dev, ioctl_command_t command, void* arg)
+{
+ ti_ads* dev = (ti_ads*) iic_dev;
+ uint16_t value;
+ int err;
+
+ switch (command) {
+ case TI_ADS_ADC_GET_CONVERSION:
+ value = 0;
+ err = ti_ads_sample(dev, &value);
+ if (err == 0)
+ *((uint16_t*) arg) = value;
+ break;
+ case TI_ADS_ADC_SET_MUX:
+ if (dev->device == TI_ADS1115) {
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_set_config(dev, value, CFG_MUX_BASE, CFG_MUX_MASK);
+ }
+ else {
+ err = -ENOTTY;
+ }
+ break;
+ case TI_ADS_ADC_SET_MODE:
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_set_config(dev, value, CFG_MODE_BASE, CFG_MODE_MASK);
+ break;
+ case TI_ADS_ADC_SET_PGA:
+ if (dev->device == TI_ADS1114 || dev->device == TI_ADS1115) {
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_set_config(dev, value, CFG_PGA_BASE, CFG_PGA_MASK);
+ }
+ else {
+ err = -ENOTTY;
+ }
+ break;
+ case TI_ADS_ADC_SET_COMP:
+ if (dev->device == TI_ADS1114 || dev->device == TI_ADS1115) {
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_set_config(dev, value, CFG_COMP_BASE, CFG_COMP_MASK);
+ }
+ else {
+ err = -ENOTTY;
+ }
+ break;
+ case TI_ADS_ADC_SET_LO_THRESH:
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_reg_write(dev, ADS_LO_THRESH, value);
+ break;
+ case TI_ADS_ADC_SET_HI_THRESH:
+ value = (uint16_t)(uintptr_t) arg;
+ err = ti_ads_reg_write(dev, ADS_HI_THRESH, value);
+ break;
+ case TI_ADS_ADC_SET_CONV_WAIT:
+ dev->poll_wait_period = (uint32_t)(uintptr_t) arg;
+ err = 0;
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ return err;
+}
+
+int
+i2c_dev_register_ti_ads_adc(const char* bus_path,
+ const char* dev_path,
+ uint16_t address,
+ ti_ads_adc device)
+{
+ ti_ads* dev;
+
+ dev = (ti_ads*)
+ i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
+ if (dev == NULL) {
+ return -1;
+ }
+
+ dev->base.ioctl = ti_ads_ioctl;
+ dev->device = device;
+ dev->config_shadow = 0;
+
+ switch (device) {
+ default:
+ errno = EIO;
+ return -1;
+ case TI_ADS1115:
+ dev->config_shadow |= ((TI_ADS_MUX_ApA0_AnA1 << CFG_MUX_BASE) |
+ (TI_ADS_PGA_FS_2_048V << CFG_PGA_BASE) |
+ ((TI_ADS_COMP_MODE_HYSTERESIS |
+ TI_ADS_COMP_POL_ACTIVE_LOW |
+ TI_ADS_COMP_LAT_NON_LATCHING |
+ TI_ADS_COMP_QUE_DISABLE_COMP) << CFG_COMP_BASE));
+ /* FALLTHRU */
+ case TI_ADS1114:
+ dev->config_shadow |= TI_ADS_PGA_FS_2_048V << CFG_PGA_BASE;
+ /* FALLTHRU */
+ case TI_ADS1113:
+ dev->config_shadow |= (CFG_MODE_SSHOT |
+ (TI_ADS_DATARATE_8SPS << CFG_DATA_RATE_BASE));
+ break;
+ }
+
+ return i2c_dev_register(&dev->base, dev_path);
+}
diff --git a/cpukit/dev/i2c/ti-lm25066a.c b/cpukit/dev/i2c/ti-lm25066a.c
new file mode 100644
index 0000000000..3f8c32ff56
--- /dev/null
+++ b/cpukit/dev/i2c/ti-lm25066a.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <dev/i2c/i2c.h>
+#include <dev/i2c/ti-lm25066a.h>
+
+/*
+ * Commands.
+ *
+ * The commands are listed in Table 1 in the datasheet. These are the mapped to
+ * command ids in the intreface. Commands have different data size, a mix of
+ * read and write amd formats.
+ *
+ * The formats for values is listed in Table 41 in the datasheet.
+ */
+
+#define CMD_RD (1 << 0)
+#define CMD_WR (1 << 1)
+#define CMD_RW (CMD_RD | CMD_WR)
+#define CMD_STR (1 << 2)
+#define CMD_VAL_ (1 << 3)
+#define CMD_BLK_ (1 << 4)
+#define CMD_INDEX_BASE (16UL)
+#define CMD_INDEX_MASK (0xfUL)
+#define CMD_VAL(l) (CMD_VAL_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
+#define CMD_BLK(l) (CMD_BLK_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
+#define CMD_INDEX(f) ((((uint32_t) (f)) >> CMD_INDEX_BASE) & CMD_INDEX_MASK)
+
+/*
+ * Number of bits in the ADC.
+ */
+#define ADC_BITS (12)
+
+/*
+ * Blocks of values that can be read.
+ */
+static const ti_lm25066a_cmd block_read[] =
+{
+ TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
+ TI_LM25066A_MFR_READ_IIN,
+ TI_LM25066A_READ_VOUT,
+ TI_LM25066A_READ_VIN,
+ TI_LM25066A_MFR_READ_PIN,
+ TI_LM25066A_READ_TEMPERATURE_1
+};
+
+static const ti_lm25066a_cmd avg_block_read[] =
+{
+ TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
+ TI_LM25066A_MFR_READ_AVG_IIN,
+ TI_LM25066A_MFR_READ_AVG_VOUT,
+ TI_LM25066A_MFR_READ_AVG_VIN,
+ TI_LM25066A_MFR_READ_AVG_PIN,
+ TI_LM25066A_READ_TEMPERATURE_1
+};
+
+static const ti_lm25066a_cmd* blocks[] =
+{
+ block_read,
+ avg_block_read
+};
+
+typedef struct
+{
+ uint8_t cmd;
+ uint16_t size;
+ uint32_t flags;
+} ti_lm25066a_i2c_cmd;
+
+/*
+ * Table 1.
+ */
+static const ti_lm25066a_i2c_cmd commands[] =
+{
+ { 0x01, 1, CMD_RW }, /* OPERATION */
+ { 0x03, 0, CMD_WR }, /* CLEAR_FAULTS */
+ { 0x19, 1, CMD_RD }, /* CAPABILITY */
+ { 0x43, 2, CMD_RW | CMD_VAL(1) }, /* VOUT_UV_WARN_LIMIT */
+ { 0x4f, 2, CMD_RW | CMD_VAL(5) }, /* OT_FAULT_LIMIT */
+ { 0x51, 2, CMD_RW | CMD_VAL(5) }, /* OT_WARN_LIMIT */
+ { 0x57, 2, CMD_RD | CMD_VAL(0) }, /* VIN_OV_WARN_LIMIT */
+ { 0x58, 2, CMD_RW | CMD_VAL(0) }, /* VIN_UV_WARN_LIMIT */
+ { 0x78, 1, CMD_RD }, /* STATUS_BYTE */
+ { 0x79, 2, CMD_RD }, /* STATUS_WORD */
+ { 0x7a, 1, CMD_RD }, /* STATUS_VOUT */
+ { 0x7c, 1, CMD_RD }, /* STATUS_INPUT */
+ { 0x7d, 1, CMD_RD }, /* STATUS_TEMPERATURE */
+ { 0x7e, 1, CMD_RD }, /* STATUS_CML */
+ { 0x80, 1, CMD_RD }, /* STATUS_MFR_SPECIFIC */
+ { 0x88, 2, CMD_RD | CMD_VAL(0) }, /* READ_VIN */
+ { 0x8b, 2, CMD_RD | CMD_VAL(1) }, /* READ_VOUT */
+ { 0x8d, 2, CMD_RD | CMD_VAL(5) }, /* READ_TEMPERATURE_1 */
+ { 0x99, 4, CMD_RD | CMD_STR }, /* MFR_ID */
+ { 0x9a, 9, CMD_RD | CMD_STR }, /* MFR_MODEL */
+ { 0x9b, 2, CMD_RD | CMD_STR }, /* MFR_REVISION */
+ { 0xd0, 2, CMD_RD | CMD_VAL(2) }, /* MFR_READ_VAUX */
+ { 0xd1, 2, CMD_RD | CMD_VAL(3) }, /* MFR_READ_IIN */
+ { 0xd2, 2, CMD_RD | CMD_VAL(4) }, /* MFR_READ_PIN */
+ { 0xd3, 2, CMD_RW | CMD_VAL(3) }, /* MFR_IIN_OC_WARN_LIMIT */
+ { 0xd4, 2, CMD_RW | CMD_VAL(4) }, /* MFR_PIN_OP_WARN_LIMIT */
+ { 0xd5, 2, CMD_RD | CMD_VAL(4) }, /* MFR_PIN_PEAK */
+ { 0xd6, 0, CMD_WR }, /* MFR_CLEAR_PIN_PEAK */
+ { 0xd7, 1, CMD_RW }, /* MFR_GATE_MASK */
+ { 0xd8, 2, CMD_RW }, /* MFR_ALERT_MASK */
+ { 0xd9, 1, CMD_RD }, /* MFR_DEVICE_SETUP */
+ { 0xda, 13, CMD_RD | CMD_BLK(0) }, /* MFR_BLOCK_READ */
+ { 0xdb, 1, CMD_RW }, /* MFR_SAMPLES_FOR_AVG */
+ { 0xdc, 2, CMD_RD | CMD_VAL(0) }, /* MFR_READ_AVG_VIN */
+ { 0xdd, 2, CMD_RD | CMD_VAL(1) }, /* MFR_READ_AVG_VOUT */
+ { 0xde, 2, CMD_RD | CMD_VAL(3) }, /* MFR_READ_AVG_IIN */
+ { 0xdf, 2, CMD_RD | CMD_VAL(4) }, /* MFR_READ_AVG_PIN */
+ { 0xe0, 13, CMD_RD | CMD_BLK(0) }, /* MFR_BLACK_BOX_READ */
+ { 0xe1, 2, CMD_RD }, /* MFR_DIAGNOSTIC_WORD_READ */
+ { 0xe2, 13, CMD_RD | CMD_BLK(1) }, /* MFR_AVG_BLOCK_READ */
+};
+
+#define IO_CMDS (sizeof(commands) / sizeof(commands[0]))
+#define IO_INTS (6)
+#define IO_MESSAGE_SIZE ((sizeof(uint16_t) * IO_INTS) + 2)
+
+typedef struct {
+ i2c_dev base;
+ uint8_t pointer;
+ uint16_t config_shadow;
+ const ti_lm25066a_conversion* conversions;
+ int scale;
+ uint8_t buffer[IO_MESSAGE_SIZE];
+} ti_lm25066a;
+
+/*
+ * Convert a value using table 41 in the data sheet.
+ */
+static int
+ti_lm25066a_io_convert_to_real(ti_lm25066a* dev, uint16_t word, int conversion)
+{
+ const ti_lm25066a_conversion* const con = &dev->conversions[conversion];
+ uint32_t u = word;
+ int value;
+ value = ((int) (u & ((1 << ADC_BITS) - 1))) * dev->scale;
+ value = ((value * con->R) - con->b) / con->m;
+ return value;
+}
+
+static void
+ti_lm25066a_io_convert_block(ti_lm25066a* dev,
+ const uint16_t* words,
+ int* values,
+ int block)
+{
+ const ti_lm25066a_cmd* cmds = blocks[block];
+ int c;
+ /*
+ * A block is always 6 values.
+ */
+ values[0] = words[0];
+ for (c = 1; c < 6; ++c) {
+ const ti_lm25066a_i2c_cmd* cmd = &commands[cmds[c]];
+ if ((cmd->flags & CMD_VAL_) != 0) {
+ values[c] =
+ ti_lm25066a_io_convert_to_real(dev, words[c], CMD_INDEX(cmd->flags));
+ } else {
+ values[c] = words[c];
+ }
+ }
+}
+
+static int
+ti_lm25066a_io_read(ti_lm25066a* dev, ti_lm25066a_io* io)
+{
+ const ti_lm25066a_i2c_cmd* cmd;
+ uint8_t out[1];
+ uint8_t* in = dev->buffer;
+ i2c_msg msgs[2];
+ int err;
+
+ if (io->cmd >= IO_CMDS)
+ return -EIO;
+
+ cmd = &commands[io->cmd];
+
+ if ((cmd->flags & CMD_RD) == 0)
+ return -EIO;
+
+ out[0] = cmd->cmd;
+ msgs[0].addr = dev->base.address;
+ msgs[0].flags = 0;
+ msgs[0].len = (uint16_t) sizeof(out);
+ msgs[0].buf = &out[0];
+ msgs[1].addr = dev->base.address;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = (uint16_t) cmd->size;
+ msgs[1].buf = &in[0];
+
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ if (err != 0)
+ return err;
+
+ err = -EIO;
+
+ switch (io->type) {
+ case TI_LM25066A_8BIT:
+ io->data.u8 = in[0];
+ err = 0;
+ break;
+ case TI_LM25066A_16BIT:
+ io->data.u16 = (((uint16_t) in[0]) << 8) | in[1];
+ err = 0;
+ break;
+ case TI_LM25066A_VALUE:
+ if ((cmd->flags & CMD_VAL_) != 0) {
+ uint16_t data = ((uint16_t) in[1]) << 8 | in[0];
+ io->data.value =
+ ti_lm25066a_io_convert_to_real(dev, data, CMD_INDEX(cmd->flags));
+ }
+ else {
+ io->data.value = ((uint16_t) in[1]) << 8 | in[0];;
+ }
+ err = 0;
+ break;
+ case TI_LM25066A_VALUES:
+ if ((cmd->flags & CMD_BLK_) != 0) {
+ uint16_t data[in[0] / 2];
+ uint16_t* d = &data[0];
+ uint8_t* i = &in[1];
+ int w;
+ for (w = 0; w < (in[0] / 2); ++w, ++d, i += 2) {
+ *d = (((uint16_t) i[1]) << 8) | i[0] ;
+ }
+ ti_lm25066a_io_convert_block(dev,
+ &data[0],
+ &io->data.values[0],
+ CMD_INDEX(cmd->flags));
+ err = 0;
+ }
+ break;
+ case TI_LM25066A_STRING:
+ memcpy(&io->data.string[0], &in[0], cmd->size);
+ err = 0;
+ break;
+ case TI_LM25066A_RAW:
+ memcpy(io->data.raw, &in[0], cmd->size);
+ err = 0;
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+static int
+ti_lm25066a_io_write(ti_lm25066a* dev, ti_lm25066a_io* io)
+{
+ const ti_lm25066a_i2c_cmd* cmd;
+ uint8_t* out = dev->buffer;
+ uint16_t length = 0;
+ int err;
+
+ if (io->cmd >= IO_CMDS)
+ return -EIO;
+
+ cmd = &commands[io->cmd];
+
+ if ((cmd->flags & CMD_WR) == 0)
+ return -EIO;
+
+ out[0] = cmd->cmd;
+
+ if (cmd->size == 0) {
+ out[1] = 0;
+ length = 1;
+ }
+ else {
+ switch (io->type) {
+ case TI_LM25066A_8BIT:
+ out[1] = io->data.u8;
+ length = 1 + 1;
+ break;
+ case TI_LM25066A_16BIT:
+ out[1] = io->data.u16 >> 8;
+ out[2] = io->data.u16;
+ length = 2 + 1;
+ break;
+ case TI_LM25066A_VALUE:
+ break;
+ case TI_LM25066A_VALUES:
+ break;
+ case TI_LM25066A_STRING:
+ break;
+ case TI_LM25066A_RAW:
+ memcpy(&out[1], io->data.raw, cmd->size);
+ length = cmd->size + 1;
+ err = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (length == 0)
+ err = -EIO;
+ else {
+ i2c_msg msgs[1] = {
+ {
+ .addr = dev->base.address,
+ .flags = 0,
+ .len = length,
+ .buf = &out[0]
+ }
+ };
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ }
+
+ return err;
+}
+
+static int
+ti_lm25066a_ioctl(i2c_dev* iic_dev, ioctl_command_t command, void* arg)
+{
+ ti_lm25066a* dev = (ti_lm25066a*) iic_dev;
+ ti_lm25066a_io* io = (ti_lm25066a_io*) arg;
+ int err;
+
+ switch (command) {
+ case TI_LM25066A_GET:
+ err = ti_lm25066a_io_read(dev, io);
+ break;
+ case TI_LM25066A_SET:
+ err = ti_lm25066a_io_write(dev, io);
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ return err;
+}
+
+int
+i2c_dev_register_ti_lm25066a(const char* bus_path,
+ const char* dev_path,
+ uint16_t address,
+ const ti_lm25066a_conversion* const conversions,
+ const int decimal_points)
+{
+ ti_lm25066a* dev;
+ int i;
+
+ dev = (ti_lm25066a*)
+ i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
+ if (dev == NULL) {
+ return -1;
+ }
+
+ dev->base.ioctl = ti_lm25066a_ioctl;
+ dev->pointer = -1;
+ dev->config_shadow = 0;
+ dev->conversions = conversions;
+ dev->scale = 1;
+ for (i = 0; i < decimal_points; ++i)
+ dev->scale *= 10;
+
+ return i2c_dev_register(&dev->base, dev_path);
+}
diff --git a/cpukit/dev/i2c/ti-tmp112.c b/cpukit/dev/i2c/ti-tmp112.c
new file mode 100644
index 0000000000..0886a4de9c
--- /dev/null
+++ b/cpukit/dev/i2c/ti-tmp112.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <dev/i2c/i2c.h>
+#include <dev/i2c/ti-tmp112.h>
+
+/*
+ * Registers.
+ */
+#define TMP_TEMPERATURE (0)
+#define TMP_CONFIG (1)
+#define TMP_LOW_TEMP (2)
+#define TMP_HIGH_TEMP (3)
+
+/*
+ * Configuration register.
+ */
+#define CFG_ONE_SHOT_BASE (15)
+#define CFG_SHUTDOWN_BASE (8)
+#define CFG_EXTENDED_MODE_BASE (4)
+
+#define CFG_ONE_SHOT (1 << CFG_ONE_SHOT_BASE)
+#define CFG_SHUTDOWN (1 << CFG_SHUTDOWN_BASE)
+#define CFG_EXTENDED_MODE (1 << CFG_EXTENDED_MODE_BASE)
+
+typedef struct {
+ i2c_dev base;
+ uint8_t pointer;
+ uint16_t config_shadow;
+} ti_tmp112;
+
+static int
+ti_tmp112_reg_write(ti_tmp112* dev, int reg, uint16_t value)
+{
+ uint8_t out[3];
+ i2c_msg msgs[1] = {
+ {
+ .addr = dev->base.address,
+ .flags = 0,
+ .len = (uint16_t) sizeof(out),
+ .buf = &out[0]
+ }
+ };
+ int err;
+ if (dev->pointer == reg) {
+ out[0] = (uint8_t) (value >> 8);
+ out[1] = (uint8_t) value;
+ msgs[0].len = 2;
+ }
+ else {
+ out[0] = reg;
+ out[1] = (uint8_t) (value >> 8);
+ out[2] = (uint8_t) value;
+ }
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ if (err == 0)
+ dev->pointer = reg;
+ else
+ dev->pointer = -1;
+ return err;
+}
+
+static int
+ti_tmp112_reg_read(ti_tmp112* dev, int reg, uint16_t* value)
+{
+ uint8_t in[2] = { 0, 0 };
+ int err;
+ if (dev->pointer == reg) {
+ i2c_msg msgs[1] = {
+ {
+ .addr = dev->base.address,
+ .flags = I2C_M_RD,
+ .len = (uint16_t) sizeof(in),
+ .buf = &in[0]
+ }
+ };
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ }
+ else {
+ uint8_t out[1] = { (uint8_t) reg };
+ i2c_msg msgs[2] = {
+ {
+ .addr = dev->base.address,
+ .flags = 0,
+ .len = (uint16_t) sizeof(out),
+ .buf = &out[0]
+ }, {
+ .addr = dev->base.address,
+ .flags = I2C_M_RD,
+ .len = (uint16_t) sizeof(in),
+ .buf = &in[0]
+ }
+ };
+ err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
+ if (err == 0)
+ dev->pointer = reg;
+ else
+ dev->pointer = -1;
+ }
+ *value = (((uint16_t) in[0]) << 8) | in[1];
+ return err;
+}
+
+static int
+ti_tmp112_set_config(ti_tmp112* dev, uint16_t value)
+{
+ int err;
+ dev->config_shadow = value;
+ err = ti_tmp112_reg_write(dev, TMP_CONFIG, dev->config_shadow);
+ return err;
+}
+
+static int
+ti_tmp112_get_temp(ti_tmp112* dev, int* temp, bool raw)
+{
+ uint16_t value = 0;
+ int err;
+
+ *temp = 0;
+
+ if ((dev->config_shadow & CFG_SHUTDOWN) == CFG_SHUTDOWN) {
+ i2c_bus_obtain(dev->base.bus);
+ err = ti_tmp112_reg_write(dev,
+ TMP_CONFIG,
+ dev->config_shadow | CFG_ONE_SHOT);
+ if (err == 0) {
+ uint16_t config = 0;
+ while (err == 0 && (config & CFG_ONE_SHOT) == 0)
+ err = ti_tmp112_reg_read(dev, TMP_CONFIG, &config);
+ err = ti_tmp112_reg_read(dev, TMP_TEMPERATURE, &value);
+ }
+ i2c_bus_release(dev->base.bus);
+ }
+ else {
+ err = ti_tmp112_reg_read(dev, TMP_TEMPERATURE, &value);
+ }
+
+ if (err == 0) {
+ if (raw) {
+ *temp = (int) value;
+ }
+ else {
+ int bits = 12;
+ uint32_t u;
+ if ((dev->config_shadow & CFG_EXTENDED_MODE) != 0)
+ bits = 13;
+ u = value >> ((sizeof(value) * 8) - bits);
+ *temp = (int) (u & ((1 << bits) - 1));
+ if ((u & (1 << (bits - 1))) != 0)
+ *temp |= ~((1 << bits) - 1);
+ *temp = *temp * 625;
+ }
+ }
+
+ return err;
+}
+
+static int
+ti_tmp112_ioctl(i2c_dev* iic_dev, ioctl_command_t command, void* arg)
+{
+ ti_tmp112* dev = (ti_tmp112*) iic_dev;
+ uint16_t v16;
+ int vint;
+ int err;
+
+ switch (command) {
+ case TI_TMP112_GET_TEMP:
+ vint = 0;
+ err = ti_tmp112_get_temp(dev, &vint, false);
+ if (err == 0)
+ *((int*) arg) = vint;
+ break;
+ case TI_TMP112_GET_TEMP_RAW:
+ vint = 0;
+ err = ti_tmp112_get_temp(dev, &vint, true);
+ if (err == 0)
+ *((uint16_t*) arg) = (uint16_t) vint;
+ break;
+ case TI_TMP112_SET_CONFIG:
+ v16 = (uint16_t)(uintptr_t) arg;
+ err = ti_tmp112_set_config(dev, v16);
+ break;
+ case TI_TMP112_SET_LOW_TEMP:
+ v16 = (uint16_t)(uintptr_t) arg;
+ err = ti_tmp112_reg_write(dev, TMP_LOW_TEMP, v16);
+ break;
+ case TI_TMP112_SET_HIGH_TEMP:
+ v16 = (uint16_t)(uintptr_t) arg;
+ err = ti_tmp112_reg_write(dev, TMP_HIGH_TEMP, v16);
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+
+ return err;
+}
+
+int
+i2c_dev_register_ti_tmp112(const char* bus_path,
+ const char* dev_path,
+ uint16_t address)
+{
+ ti_tmp112* dev;
+
+ dev = (ti_tmp112*)
+ i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
+ if (dev == NULL) {
+ return -1;
+ }
+
+ dev->base.ioctl = ti_tmp112_ioctl;
+ dev->pointer = -1;
+ dev->config_shadow = 0x60a0;
+
+ return i2c_dev_register(&dev->base, dev_path);
+}