source: rtems/cpukit/dev/i2c/ti-lm25066a.c @ 05015dc1

5
Last change on this file since 05015dc1 was b2ed712, checked in by Sebastian Huber <sebastian.huber@…>, on 08/25/17 at 08:58:58

Include missing <string.h>

Update #2133.

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>
3 * All rights reserved.
4 *
5 * The license and distribution terms for this file may be
6 * found in the file LICENSE in this distribution or at
7 * http://www.rtems.org/license/LICENSE.
8 */
9
10#if HAVE_CONFIG_H
11  #include "config.h"
12#endif
13
14#include <stdio.h>
15#include <string.h>
16
17#include <dev/i2c/i2c.h>
18#include <dev/i2c/ti-lm25066a.h>
19
20/*
21 * Commands.
22 *
23 * The commands are listed in Table 1 in the datasheet. These are the mapped to
24 * command ids in the intreface. Commands have different data size, a mix of
25 * read and write amd formats.
26 *
27 * The formats for values is listed in Table 41 in the datasheet.
28 */
29
30#define CMD_RD         (1 << 0)
31#define CMD_WR         (1 << 1)
32#define CMD_RW         (CMD_RD | CMD_WR)
33#define CMD_STR        (1 << 2)
34#define CMD_VAL_       (1 << 3)
35#define CMD_BLK_       (1 << 4)
36#define CMD_INDEX_BASE (16UL)
37#define CMD_INDEX_MASK (0xfUL)
38#define CMD_VAL(l)     (CMD_VAL_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
39#define CMD_BLK(l)     (CMD_BLK_ | (((uint32_t) (l)) << CMD_INDEX_BASE))
40#define CMD_INDEX(f)   ((((uint32_t) (f)) >> CMD_INDEX_BASE) & CMD_INDEX_MASK)
41
42/*
43 * Number of bits in the ADC.
44 */
45#define ADC_BITS (12)
46
47/*
48 * Blocks of values that can be read.
49 */
50static const ti_lm25066a_cmd block_read[] =
51{
52  TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
53  TI_LM25066A_MFR_READ_IIN,
54  TI_LM25066A_READ_VOUT,
55  TI_LM25066A_READ_VIN,
56  TI_LM25066A_MFR_READ_PIN,
57  TI_LM25066A_READ_TEMPERATURE_1
58};
59
60static const ti_lm25066a_cmd avg_block_read[] =
61{
62  TI_LM25066A_MFR_DIAGNOSTIC_WORD_READ,
63  TI_LM25066A_MFR_READ_AVG_IIN,
64  TI_LM25066A_MFR_READ_AVG_VOUT,
65  TI_LM25066A_MFR_READ_AVG_VIN,
66  TI_LM25066A_MFR_READ_AVG_PIN,
67  TI_LM25066A_READ_TEMPERATURE_1
68};
69
70static const ti_lm25066a_cmd* blocks[] =
71{
72  block_read,
73  avg_block_read
74};
75
76typedef struct
77{
78  uint8_t  cmd;
79  uint16_t size;
80  uint32_t flags;
81} ti_lm25066a_i2c_cmd;
82
83/*
84 * Table 1.
85 */
86static const ti_lm25066a_i2c_cmd commands[] =
87{
88  { 0x01,  1, CMD_RW              }, /* OPERATION */
89  { 0x03,  0, CMD_WR              }, /* CLEAR_FAULTS */
90  { 0x19,  1, CMD_RD              }, /* CAPABILITY */
91  { 0x43,  2, CMD_RW | CMD_VAL(1) }, /* VOUT_UV_WARN_LIMIT */
92  { 0x4f,  2, CMD_RW | CMD_VAL(5) }, /* OT_FAULT_LIMIT */
93  { 0x51,  2, CMD_RW | CMD_VAL(5) }, /* OT_WARN_LIMIT */
94  { 0x57,  2, CMD_RD | CMD_VAL(0) }, /* VIN_OV_WARN_LIMIT */
95  { 0x58,  2, CMD_RW | CMD_VAL(0) }, /* VIN_UV_WARN_LIMIT */
96  { 0x78,  1, CMD_RD              }, /* STATUS_BYTE */
97  { 0x79,  2, CMD_RD              }, /* STATUS_WORD */
98  { 0x7a,  1, CMD_RD              }, /* STATUS_VOUT */
99  { 0x7c,  1, CMD_RD              }, /* STATUS_INPUT */
100  { 0x7d,  1, CMD_RD              }, /* STATUS_TEMPERATURE */
101  { 0x7e,  1, CMD_RD              }, /* STATUS_CML */
102  { 0x80,  1, CMD_RD              }, /* STATUS_MFR_SPECIFIC */
103  { 0x88,  2, CMD_RD | CMD_VAL(0) }, /* READ_VIN */
104  { 0x8b,  2, CMD_RD | CMD_VAL(1) }, /* READ_VOUT */
105  { 0x8d,  2, CMD_RD | CMD_VAL(5) }, /* READ_TEMPERATURE_1 */
106  { 0x99,  4, CMD_RD | CMD_STR    }, /* MFR_ID */
107  { 0x9a,  9, CMD_RD | CMD_STR    }, /* MFR_MODEL */
108  { 0x9b,  2, CMD_RD | CMD_STR    }, /* MFR_REVISION */
109  { 0xd0,  2, CMD_RD | CMD_VAL(2) }, /* MFR_READ_VAUX */
110  { 0xd1,  2, CMD_RD | CMD_VAL(3) }, /* MFR_READ_IIN */
111  { 0xd2,  2, CMD_RD | CMD_VAL(4) }, /* MFR_READ_PIN */
112  { 0xd3,  2, CMD_RW | CMD_VAL(3) }, /* MFR_IIN_OC_WARN_LIMIT */
113  { 0xd4,  2, CMD_RW | CMD_VAL(4) }, /* MFR_PIN_OP_WARN_LIMIT */
114  { 0xd5,  2, CMD_RD | CMD_VAL(4) }, /* MFR_PIN_PEAK */
115  { 0xd6,  0, CMD_WR              }, /* MFR_CLEAR_PIN_PEAK */
116  { 0xd7,  1, CMD_RW              }, /* MFR_GATE_MASK */
117  { 0xd8,  2, CMD_RW              }, /* MFR_ALERT_MASK */
118  { 0xd9,  1, CMD_RD              }, /* MFR_DEVICE_SETUP */
119  { 0xda, 13, CMD_RD | CMD_BLK(0) }, /* MFR_BLOCK_READ */
120  { 0xdb,  1, CMD_RW              }, /* MFR_SAMPLES_FOR_AVG */
121  { 0xdc,  2, CMD_RD | CMD_VAL(0) }, /* MFR_READ_AVG_VIN */
122  { 0xdd,  2, CMD_RD | CMD_VAL(1) }, /* MFR_READ_AVG_VOUT */
123  { 0xde,  2, CMD_RD | CMD_VAL(3) }, /* MFR_READ_AVG_IIN */
124  { 0xdf,  2, CMD_RD | CMD_VAL(4) }, /* MFR_READ_AVG_PIN */
125  { 0xe0, 13, CMD_RD | CMD_BLK(0) }, /* MFR_BLACK_BOX_READ */
126  { 0xe1,  2, CMD_RD              }, /* MFR_DIAGNOSTIC_WORD_READ */
127  { 0xe2, 13, CMD_RD | CMD_BLK(1) }, /* MFR_AVG_BLOCK_READ */
128};
129
130#define IO_CMDS          (sizeof(commands) / sizeof(commands[0]))
131#define IO_INTS          (6)
132#define IO_MESSAGE_SIZE  ((sizeof(uint16_t) * IO_INTS) + 2)
133
134typedef struct {
135  i2c_dev                       base;
136  uint8_t                       pointer;
137  uint16_t                      config_shadow;
138  const ti_lm25066a_conversion* conversions;
139  int                           scale;
140  uint8_t                       buffer[IO_MESSAGE_SIZE];
141} ti_lm25066a;
142
143/*
144 * Convert a value using table 41 in the data sheet.
145 */
146static int
147ti_lm25066a_io_convert_to_real(ti_lm25066a* dev, uint16_t word, int conversion)
148{
149  const ti_lm25066a_conversion* const con = &dev->conversions[conversion];
150  uint32_t                            u = word;
151  int                                 value;
152  value = ((int) (u & ((1 << ADC_BITS) - 1))) * dev->scale;
153  value = ((value * con->R) - con->b) / con->m;
154  return value;
155}
156
157static void
158ti_lm25066a_io_convert_block(ti_lm25066a*    dev,
159                             const uint16_t* words,
160                             int*            values,
161                             int             block)
162{
163  const ti_lm25066a_cmd* cmds = blocks[block];
164  int                    c;
165  /*
166   * A block is always 6 values.
167   */
168  values[0] = words[0];
169  for (c = 1; c < 6; ++c) {
170    const ti_lm25066a_i2c_cmd* cmd = &commands[cmds[c]];
171    if ((cmd->flags & CMD_VAL_) != 0) {
172      values[c] =
173        ti_lm25066a_io_convert_to_real(dev, words[c], CMD_INDEX(cmd->flags));
174    } else {
175      values[c] = words[c];
176    }
177  }
178}
179
180static int
181ti_lm25066a_io_read(ti_lm25066a* dev, ti_lm25066a_io* io)
182{
183  const ti_lm25066a_i2c_cmd* cmd;
184  uint8_t                    out[1];
185  uint8_t*                   in = dev->buffer;
186  i2c_msg                    msgs[2];
187  int                        err;
188
189  if (io->cmd >= IO_CMDS)
190    return -EIO;
191
192  cmd = &commands[io->cmd];
193
194  if ((cmd->flags & CMD_RD) == 0)
195    return -EIO;
196
197  out[0] = cmd->cmd;
198  msgs[0].addr = dev->base.address;
199  msgs[0].flags = 0;
200  msgs[0].len = (uint16_t) sizeof(out);
201  msgs[0].buf = &out[0];
202  msgs[1].addr = dev->base.address;
203  msgs[1].flags = I2C_M_RD;
204  msgs[1].len = (uint16_t) cmd->size;
205  msgs[1].buf = &in[0];
206
207  err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
208  if (err != 0)
209    return err;
210
211  err = -EIO;
212
213  switch (io->type) {
214    case TI_LM25066A_8BIT:
215      io->data.u8 = in[0];
216      err = 0;
217      break;
218    case TI_LM25066A_16BIT:
219      io->data.u16 = (((uint16_t) in[0]) << 8) | in[1];
220      err = 0;
221      break;
222    case TI_LM25066A_VALUE:
223      if ((cmd->flags & CMD_VAL_) != 0) {
224        uint16_t data = ((uint16_t) in[1]) << 8 | in[0];
225        io->data.value =
226          ti_lm25066a_io_convert_to_real(dev, data, CMD_INDEX(cmd->flags));
227      }
228      else {
229        io->data.value = ((uint16_t) in[1]) << 8 | in[0];;
230      }
231      err = 0;
232      break;
233    case TI_LM25066A_VALUES:
234      if ((cmd->flags & CMD_BLK_) != 0) {
235        uint16_t  data[in[0] / 2];
236        uint16_t* d = &data[0];
237        uint8_t*  i = &in[1];
238        int       w;
239        for (w = 0; w < (in[0] / 2); ++w, ++d, i += 2) {
240          *d = (((uint16_t) i[1]) << 8) | i[0] ;
241        }
242        ti_lm25066a_io_convert_block(dev,
243                                     &data[0],
244                                     &io->data.values[0],
245                                     CMD_INDEX(cmd->flags));
246        err = 0;
247      }
248      break;
249    case TI_LM25066A_STRING:
250      memcpy(&io->data.string[0], &in[0], cmd->size);
251      err = 0;
252      break;
253    case TI_LM25066A_RAW:
254      memcpy(io->data.raw, &in[0], cmd->size);
255      err = 0;
256      break;
257    default:
258      break;
259  }
260
261  return err;
262}
263
264static int
265ti_lm25066a_io_write(ti_lm25066a* dev, ti_lm25066a_io* io)
266{
267  const ti_lm25066a_i2c_cmd* cmd;
268  uint8_t*                   out = dev->buffer;
269  uint16_t                   length = 0;
270  int                        err;
271
272  if (io->cmd >= IO_CMDS)
273    return -EIO;
274
275  cmd = &commands[io->cmd];
276
277  if ((cmd->flags & CMD_WR) == 0)
278    return -EIO;
279
280  out[0] = cmd->cmd;
281
282  if (cmd->size == 0) {
283    out[1] = 0;
284    length = 1;
285  }
286  else {
287    switch (io->type) {
288      case TI_LM25066A_8BIT:
289        out[1] = io->data.u8;
290        length = 1 + 1;
291        break;
292      case TI_LM25066A_16BIT:
293        out[1] = io->data.u16 >> 8;
294        out[2] = io->data.u16;
295        length = 2 + 1;
296        break;
297      case TI_LM25066A_VALUE:
298        break;
299      case TI_LM25066A_VALUES:
300        break;
301      case TI_LM25066A_STRING:
302        break;
303      case TI_LM25066A_RAW:
304        memcpy(&out[1], io->data.raw, cmd->size);
305        length = cmd->size + 1;
306        err = 0;
307      break;
308      default:
309        break;
310    }
311  }
312
313  if (length == 0)
314    err = -EIO;
315  else {
316    i2c_msg msgs[1] = {
317      {
318        .addr = dev->base.address,
319        .flags = 0,
320        .len = length,
321        .buf = &out[0]
322      }
323    };
324    err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
325  }
326
327  return err;
328}
329
330static int
331ti_lm25066a_ioctl(i2c_dev* iic_dev, ioctl_command_t command, void* arg)
332{
333  ti_lm25066a*    dev = (ti_lm25066a*) iic_dev;
334  ti_lm25066a_io* io = (ti_lm25066a_io*) arg;
335  int        err;
336
337  switch (command) {
338    case TI_LM25066A_GET:
339      err = ti_lm25066a_io_read(dev, io);
340      break;
341    case TI_LM25066A_SET:
342      err = ti_lm25066a_io_write(dev, io);
343      break;
344    default:
345      err = -ENOTTY;
346      break;
347  }
348
349  return err;
350}
351
352int
353i2c_dev_register_ti_lm25066a(const char*                         bus_path,
354                             const char*                         dev_path,
355                             uint16_t                            address,
356                             const ti_lm25066a_conversion* const conversions,
357                             const int                           decimal_points)
358{
359  ti_lm25066a* dev;
360  int          i;
361
362  dev = (ti_lm25066a*)
363    i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
364  if (dev == NULL) {
365    return -1;
366  }
367
368  dev->base.ioctl = ti_lm25066a_ioctl;
369  dev->pointer = -1;
370  dev->config_shadow = 0;
371  dev->conversions = conversions;
372  dev->scale = 1;
373  for (i = 0; i < decimal_points; ++i)
374    dev->scale *= 10;
375
376  return i2c_dev_register(&dev->base, dev_path);
377}
Note: See TracBrowser for help on using the repository browser.