File indexing completed on 2025-05-11 08:24:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifdef HAVE_CONFIG_H
0011 #include "config.h"
0012 #endif
0013
0014 #include <stdio.h>
0015 #include <string.h>
0016
0017 #include <dev/i2c/i2c.h>
0018 #include <dev/i2c/ti-lm25066a.h>
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #define CMD_RD (1 << 0)
0031 #define CMD_WR (1 << 1)
0032 #define CMD_RW (CMD_RD | CMD_WR)
0033 #define CMD_STR (1 << 2)
0034 #define CMD_VAL_ (1 << 3)
0035 #define CMD_BLK_ (1 << 4)
0036 #define CMD_INDEX_BASE (16UL)
0037 #define CMD_INDEX_MASK (0xfUL)
0038 #define CMD_VAL(l) (CMD_VAL_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
0039 #define CMD_BLK(l) (CMD_BLK_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
0040 #define CMD_INDEX(f) ((((uint32_t) (f)) >> CMD_INDEX_BASE) & CMD_INDEX_MASK)
0041
0042
0043
0044
0045 #define ADC_BITS (12)
0046
0047
0048
0049
0050 static const ti_lm25066a_cmd block_read[] =
0051 {
0052 TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
0053 TI_LM25066A_MFR_READ_IIN,
0054 TI_LM25066A_READ_VOUT,
0055 TI_LM25066A_READ_VIN,
0056 TI_LM25066A_MFR_READ_PIN,
0057 TI_LM25066A_READ_TEMPERATURE_1
0058 };
0059
0060 static const ti_lm25066a_cmd avg_block_read[] =
0061 {
0062 TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
0063 TI_LM25066A_MFR_READ_AVG_IIN,
0064 TI_LM25066A_MFR_READ_AVG_VOUT,
0065 TI_LM25066A_MFR_READ_AVG_VIN,
0066 TI_LM25066A_MFR_READ_AVG_PIN,
0067 TI_LM25066A_READ_TEMPERATURE_1
0068 };
0069
0070 static const ti_lm25066a_cmd* blocks[] =
0071 {
0072 block_read,
0073 avg_block_read
0074 };
0075
0076 typedef struct
0077 {
0078 uint8_t cmd;
0079 uint16_t size;
0080 uint32_t flags;
0081 } ti_lm25066a_i2c_cmd;
0082
0083
0084
0085
0086 static const ti_lm25066a_i2c_cmd commands[] =
0087 {
0088 { 0x01, 1, CMD_RW },
0089 { 0x03, 0, CMD_WR },
0090 { 0x19, 1, CMD_RD },
0091 { 0x43, 2, CMD_RW | CMD_VAL(1) },
0092 { 0x4f, 2, CMD_RW | CMD_VAL(5) },
0093 { 0x51, 2, CMD_RW | CMD_VAL(5) },
0094 { 0x57, 2, CMD_RD | CMD_VAL(0) },
0095 { 0x58, 2, CMD_RW | CMD_VAL(0) },
0096 { 0x78, 1, CMD_RD },
0097 { 0x79, 2, CMD_RD },
0098 { 0x7a, 1, CMD_RD },
0099 { 0x7c, 1, CMD_RD },
0100 { 0x7d, 1, CMD_RD },
0101 { 0x7e, 1, CMD_RD },
0102 { 0x80, 1, CMD_RD },
0103 { 0x88, 2, CMD_RD | CMD_VAL(0) },
0104 { 0x8b, 2, CMD_RD | CMD_VAL(1) },
0105 { 0x8d, 2, CMD_RD | CMD_VAL(5) },
0106 { 0x99, 4, CMD_RD | CMD_STR },
0107 { 0x9a, 9, CMD_RD | CMD_STR },
0108 { 0x9b, 2, CMD_RD | CMD_STR },
0109 { 0xd0, 2, CMD_RD | CMD_VAL(2) },
0110 { 0xd1, 2, CMD_RD | CMD_VAL(3) },
0111 { 0xd2, 2, CMD_RD | CMD_VAL(4) },
0112 { 0xd3, 2, CMD_RW | CMD_VAL(3) },
0113 { 0xd4, 2, CMD_RW | CMD_VAL(4) },
0114 { 0xd5, 2, CMD_RD | CMD_VAL(4) },
0115 { 0xd6, 0, CMD_WR },
0116 { 0xd7, 1, CMD_RW },
0117 { 0xd8, 2, CMD_RW },
0118 { 0xd9, 1, CMD_RD },
0119 { 0xda, 13, CMD_RD | CMD_BLK(0) },
0120 { 0xdb, 1, CMD_RW },
0121 { 0xdc, 2, CMD_RD | CMD_VAL(0) },
0122 { 0xdd, 2, CMD_RD | CMD_VAL(1) },
0123 { 0xde, 2, CMD_RD | CMD_VAL(3) },
0124 { 0xdf, 2, CMD_RD | CMD_VAL(4) },
0125 { 0xe0, 13, CMD_RD | CMD_BLK(0) },
0126 { 0xe1, 2, CMD_RD },
0127 { 0xe2, 13, CMD_RD | CMD_BLK(1) },
0128 };
0129
0130 #define IO_CMDS (sizeof(commands) / sizeof(commands[0]))
0131 #define IO_INTS (6)
0132 #define IO_MESSAGE_SIZE ((sizeof(uint16_t) * IO_INTS) + 2)
0133
0134 typedef struct {
0135 i2c_dev base;
0136 uint8_t pointer;
0137 uint16_t config_shadow;
0138 const ti_lm25066a_conversion* conversions;
0139 int scale;
0140 uint8_t buffer[IO_MESSAGE_SIZE];
0141 } ti_lm25066a;
0142
0143
0144
0145
0146 static int
0147 ti_lm25066a_io_convert_to_real(ti_lm25066a* dev, uint16_t word, int conversion)
0148 {
0149 const ti_lm25066a_conversion* const con = &dev->conversions[conversion];
0150 uint32_t u = word;
0151 int value;
0152 value = ((int) (u & ((1 << ADC_BITS) - 1))) * dev->scale;
0153 value = ((value * con->R) - con->b) / con->m;
0154 return value;
0155 }
0156
0157 static void
0158 ti_lm25066a_io_convert_block(ti_lm25066a* dev,
0159 const uint16_t* words,
0160 int* values,
0161 int block)
0162 {
0163 const ti_lm25066a_cmd* cmds = blocks[block];
0164 int c;
0165
0166
0167
0168 values[0] = words[0];
0169 for (c = 1; c < 6; ++c) {
0170 const ti_lm25066a_i2c_cmd* cmd = &commands[cmds[c]];
0171 if ((cmd->flags & CMD_VAL_) != 0) {
0172 values[c] =
0173 ti_lm25066a_io_convert_to_real(dev, words[c], CMD_INDEX(cmd->flags));
0174 } else {
0175 values[c] = words[c];
0176 }
0177 }
0178 }
0179
0180 static int
0181 ti_lm25066a_io_read(ti_lm25066a* dev, ti_lm25066a_io* io)
0182 {
0183 const ti_lm25066a_i2c_cmd* cmd;
0184 uint8_t out[1];
0185 uint8_t* in = dev->buffer;
0186 i2c_msg msgs[2];
0187 int err;
0188
0189 if (io->cmd >= IO_CMDS)
0190 return -EIO;
0191
0192 cmd = &commands[io->cmd];
0193
0194 if ((cmd->flags & CMD_RD) == 0)
0195 return -EIO;
0196
0197 out[0] = cmd->cmd;
0198 msgs[0].addr = dev->base.address;
0199 msgs[0].flags = 0;
0200 msgs[0].len = (uint16_t) sizeof(out);
0201 msgs[0].buf = &out[0];
0202 msgs[1].addr = dev->base.address;
0203 msgs[1].flags = I2C_M_RD;
0204 msgs[1].len = (uint16_t) cmd->size;
0205 msgs[1].buf = &in[0];
0206
0207 err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
0208 if (err != 0)
0209 return err;
0210
0211 err = -EIO;
0212
0213 switch (io->type) {
0214 case TI_LM25066A_8BIT:
0215 io->data.u8 = in[0];
0216 err = 0;
0217 break;
0218 case TI_LM25066A_16BIT:
0219 io->data.u16 = (((uint16_t) in[0]) << 8) | in[1];
0220 err = 0;
0221 break;
0222 case TI_LM25066A_VALUE:
0223 if ((cmd->flags & CMD_VAL_) != 0) {
0224 uint16_t data = ((uint16_t) in[1]) << 8 | in[0];
0225 io->data.value =
0226 ti_lm25066a_io_convert_to_real(dev, data, CMD_INDEX(cmd->flags));
0227 }
0228 else {
0229 io->data.value = ((uint16_t) in[1]) << 8 | in[0];;
0230 }
0231 err = 0;
0232 break;
0233 case TI_LM25066A_VALUES:
0234 if ((cmd->flags & CMD_BLK_) != 0) {
0235 uint16_t data[in[0] / 2];
0236 uint16_t* d = &data[0];
0237 uint8_t* i = &in[1];
0238 int w;
0239 for (w = 0; w < (in[0] / 2); ++w, ++d, i += 2) {
0240 *d = (((uint16_t) i[1]) << 8) | i[0] ;
0241 }
0242 ti_lm25066a_io_convert_block(dev,
0243 &data[0],
0244 &io->data.values[0],
0245 CMD_INDEX(cmd->flags));
0246 err = 0;
0247 }
0248 break;
0249 case TI_LM25066A_STRING:
0250 memcpy(&io->data.string[0], &in[0], cmd->size);
0251 err = 0;
0252 break;
0253 case TI_LM25066A_RAW:
0254 memcpy(io->data.raw, &in[0], cmd->size);
0255 err = 0;
0256 break;
0257 default:
0258 break;
0259 }
0260
0261 return err;
0262 }
0263
0264 static int
0265 ti_lm25066a_io_write(ti_lm25066a* dev, ti_lm25066a_io* io)
0266 {
0267 const ti_lm25066a_i2c_cmd* cmd;
0268 uint8_t* out = dev->buffer;
0269 uint16_t length = 0;
0270 int err;
0271
0272 if (io->cmd >= IO_CMDS)
0273 return -EIO;
0274
0275 cmd = &commands[io->cmd];
0276
0277 if ((cmd->flags & CMD_WR) == 0)
0278 return -EIO;
0279
0280 out[0] = cmd->cmd;
0281
0282 if (cmd->size == 0) {
0283 out[1] = 0;
0284 length = 1;
0285 }
0286 else {
0287 switch (io->type) {
0288 case TI_LM25066A_8BIT:
0289 out[1] = io->data.u8;
0290 length = 1 + 1;
0291 break;
0292 case TI_LM25066A_16BIT:
0293 out[1] = io->data.u16 >> 8;
0294 out[2] = io->data.u16;
0295 length = 2 + 1;
0296 break;
0297 case TI_LM25066A_VALUE:
0298 break;
0299 case TI_LM25066A_VALUES:
0300 break;
0301 case TI_LM25066A_STRING:
0302 break;
0303 case TI_LM25066A_RAW:
0304 memcpy(&out[1], io->data.raw, cmd->size);
0305 length = cmd->size + 1;
0306 err = 0;
0307 break;
0308 default:
0309 break;
0310 }
0311 }
0312
0313 if (length == 0)
0314 err = -EIO;
0315 else {
0316 i2c_msg msgs[1] = {
0317 {
0318 .addr = dev->base.address,
0319 .flags = 0,
0320 .len = length,
0321 .buf = &out[0]
0322 }
0323 };
0324 err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
0325 }
0326
0327 return err;
0328 }
0329
0330 static int
0331 ti_lm25066a_ioctl(i2c_dev* iic_dev, ioctl_command_t command, void* arg)
0332 {
0333 ti_lm25066a* dev = (ti_lm25066a*) iic_dev;
0334 ti_lm25066a_io* io = (ti_lm25066a_io*) arg;
0335 int err;
0336
0337 switch (command) {
0338 case TI_LM25066A_GET:
0339 err = ti_lm25066a_io_read(dev, io);
0340 break;
0341 case TI_LM25066A_SET:
0342 err = ti_lm25066a_io_write(dev, io);
0343 break;
0344 default:
0345 err = -ENOTTY;
0346 break;
0347 }
0348
0349 return err;
0350 }
0351
0352 int
0353 i2c_dev_register_ti_lm25066a(const char* bus_path,
0354 const char* dev_path,
0355 uint16_t address,
0356 const ti_lm25066a_conversion* const conversions,
0357 const int decimal_points)
0358 {
0359 ti_lm25066a* dev;
0360 int i;
0361
0362 dev = (ti_lm25066a*)
0363 i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
0364 if (dev == NULL) {
0365 return -1;
0366 }
0367
0368 dev->base.ioctl = ti_lm25066a_ioctl;
0369 dev->pointer = -1;
0370 dev->config_shadow = 0;
0371 dev->conversions = conversions;
0372 dev->scale = 1;
0373 for (i = 0; i < decimal_points; ++i)
0374 dev->scale *= 10;
0375
0376 return i2c_dev_register(&dev->base, dev_path);
0377 }