source: rtems/cpukit/dev/i2c/i2c-bus.c @ 80cf60e

5
Last change on this file since 80cf60e was 80cf60e, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 15, 2020 at 7:48:32 AM

Canonicalize config.h include

Use the following variant which was already used by most source files:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/**
2 * @file
3 *
4 * @brief Inter-Integrated Circuit (I2C) Bus Implementation
5 *
6 * @ingroup I2CBus
7 */
8
9/*
10 * Copyright (c) 2014, 2017 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <dev/i2c/i2c.h>
28
29#include <rtems/imfs.h>
30
31#include <stdlib.h>
32#include <string.h>
33
34void i2c_bus_obtain(i2c_bus *bus)
35{
36  rtems_recursive_mutex_lock(&bus->mutex);
37}
38
39void i2c_bus_release(i2c_bus *bus)
40{
41  rtems_recursive_mutex_unlock(&bus->mutex);
42}
43
44int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count)
45{
46  int err;
47  uint32_t i;
48  uint32_t j;
49
50  _Assert(msg_count > 0);
51
52  for (i = 0, j = 0; i < msg_count; ++i) {
53    if ((msgs[i].flags & I2C_M_NOSTART) != 0) {
54      if ((msgs[i].flags & I2C_M_RD) != (msgs[j].flags & I2C_M_RD)) {
55        return -EINVAL;
56      }
57
58      if (msgs[i].addr != msgs[j].addr) {
59        return -EINVAL;
60      }
61    } else {
62      j = i;
63    }
64  }
65
66  i2c_bus_obtain(bus);
67  err = (*bus->transfer)(bus, msgs, msg_count);
68  i2c_bus_release(bus);
69
70  return err;
71}
72
73static ssize_t i2c_bus_read(
74  rtems_libio_t *iop,
75  void *buffer,
76  size_t count
77)
78{
79  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
80  i2c_msg msg = {
81    .addr = bus->default_address,
82    .flags = I2C_M_RD,
83    .len = (uint16_t) count,
84    .buf = buffer
85  };
86  int err;
87
88  if (bus->ten_bit_address) {
89    msg.flags |= I2C_M_TEN;
90  }
91
92  err = i2c_bus_transfer(bus, &msg, 1);
93  if (err == 0) {
94    return msg.len;
95  } else {
96    rtems_set_errno_and_return_minus_one(-err);
97  }
98}
99
100static ssize_t i2c_bus_write(
101  rtems_libio_t *iop,
102  const void *buffer,
103  size_t count
104)
105{
106  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
107  i2c_msg msg = {
108    .addr = bus->default_address,
109    .flags = 0,
110    .len = (uint16_t) count,
111    .buf = RTEMS_DECONST(void *, buffer)
112  };
113  int err;
114
115  if (bus->ten_bit_address) {
116    msg.flags |= I2C_M_TEN;
117  }
118
119  err = i2c_bus_transfer(bus, &msg, 1);
120  if (err == 0) {
121    return msg.len;
122  } else {
123    rtems_set_errno_and_return_minus_one(-err);
124  }
125}
126
127static int i2c_bus_ioctl(
128  rtems_libio_t *iop,
129  ioctl_command_t command,
130  void *arg
131)
132{
133  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
134  i2c_rdwr_ioctl_data *rdwr;
135  int err;
136
137  switch (command) {
138    case I2C_RDWR:
139      rdwr = arg;
140      if (rdwr->nmsgs > 0) {
141        err = i2c_bus_transfer(bus, rdwr->msgs, rdwr->nmsgs);
142      } else {
143        err = 0;
144      }
145      break;
146    case I2C_BUS_OBTAIN:
147      i2c_bus_obtain(bus);
148      err = 0;
149      break;
150    case I2C_BUS_RELEASE:
151      i2c_bus_release(bus);
152      err = 0;
153      break;
154    case I2C_BUS_GET_CONTROL:
155      *(i2c_bus **) arg = bus;
156      err = 0;
157      break;
158    case I2C_FUNCS:
159      *(unsigned long *) arg = bus->functionality;
160      err = 0;
161      break;
162    case I2C_RETRIES:
163      bus->retries = (unsigned long) arg;
164      err = 0;
165      break;
166    case I2C_TIMEOUT:
167      bus->timeout = RTEMS_MILLISECONDS_TO_TICKS(10 * (unsigned long) arg);
168      err = 0;
169      break;
170    case I2C_SLAVE:
171    case I2C_SLAVE_FORCE:
172      bus->default_address = (unsigned long) arg;
173      err = 0;
174      break;
175    case I2C_TENBIT:
176      bus->ten_bit_address = (unsigned long) arg != 0;
177      err = 0;
178      break;
179    case I2C_PEC:
180      bus->use_pec = (unsigned long) arg != 0;
181      err = 0;
182      break;
183    case I2C_BUS_SET_CLOCK:
184      i2c_bus_obtain(bus);
185      err = (*bus->set_clock)(bus, (unsigned long) arg);
186      i2c_bus_release(bus);
187      break;
188    default:
189      err = -ENOTTY;
190      break;
191  }
192
193  if (err == 0) {
194    return 0;
195  } else {
196    rtems_set_errno_and_return_minus_one(-err);
197  }
198}
199
200static const rtems_filesystem_file_handlers_r i2c_bus_handler = {
201  .open_h = rtems_filesystem_default_open,
202  .close_h = rtems_filesystem_default_close,
203  .read_h = i2c_bus_read,
204  .write_h = i2c_bus_write,
205  .ioctl_h = i2c_bus_ioctl,
206  .lseek_h = rtems_filesystem_default_lseek,
207  .fstat_h = IMFS_stat,
208  .ftruncate_h = rtems_filesystem_default_ftruncate,
209  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
210  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
211  .fcntl_h = rtems_filesystem_default_fcntl,
212  .kqfilter_h = rtems_filesystem_default_kqfilter,
213  .mmap_h = rtems_filesystem_default_mmap,
214  .poll_h = rtems_filesystem_default_poll,
215  .readv_h = rtems_filesystem_default_readv,
216  .writev_h = rtems_filesystem_default_writev
217};
218
219static void i2c_bus_node_destroy(IMFS_jnode_t *node)
220{
221  i2c_bus *bus;
222
223  bus = IMFS_generic_get_context_by_node(node);
224  (*bus->destroy)(bus);
225
226  IMFS_node_destroy_default(node);
227}
228
229static const IMFS_node_control i2c_bus_node_control = IMFS_GENERIC_INITIALIZER(
230  &i2c_bus_handler,
231  IMFS_node_initialize_generic,
232  i2c_bus_node_destroy
233);
234
235int i2c_bus_register(
236  i2c_bus *bus,
237  const char *bus_path
238)
239{
240  int rv;
241
242  rv = IMFS_make_generic_node(
243    bus_path,
244    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
245    &i2c_bus_node_control,
246    bus
247  );
248  if (rv != 0) {
249    (*bus->destroy)(bus);
250  }
251
252  return rv;
253}
254
255static int i2c_bus_transfer_default(
256  i2c_bus *bus,
257  i2c_msg *msgs,
258  uint32_t msg_count
259)
260{
261  (void) bus;
262  (void) msgs;
263  (void) msg_count;
264
265  return -EIO;
266}
267
268static int i2c_bus_set_clock_default(i2c_bus *bus, unsigned long clock)
269{
270  (void) bus;
271  (void) clock;
272
273  return -EIO;
274}
275
276static int i2c_bus_do_init(
277  i2c_bus *bus,
278  void (*destroy)(i2c_bus *bus)
279)
280{
281  rtems_recursive_mutex_init(&bus->mutex, "I2C Bus");
282  bus->transfer = i2c_bus_transfer_default;
283  bus->set_clock = i2c_bus_set_clock_default;
284  bus->destroy = destroy;
285
286  return 0;
287}
288
289void i2c_bus_destroy(i2c_bus *bus)
290{
291  rtems_recursive_mutex_destroy(&bus->mutex);
292}
293
294void i2c_bus_destroy_and_free(i2c_bus *bus)
295{
296  i2c_bus_destroy(bus);
297  free(bus);
298}
299
300int i2c_bus_init(i2c_bus *bus)
301{
302  memset(bus, 0, sizeof(*bus));
303
304  return i2c_bus_do_init(bus, i2c_bus_destroy);
305}
306
307i2c_bus *i2c_bus_alloc_and_init(size_t size)
308{
309  i2c_bus *bus = NULL;
310
311  if (size >= sizeof(*bus)) {
312    bus = calloc(1, size);
313    if (bus != NULL) {
314      int rv;
315
316      rv = i2c_bus_do_init(bus, i2c_bus_destroy_and_free);
317      if (rv != 0) {
318        return NULL;
319      }
320    }
321  }
322
323  return bus;
324}
Note: See TracBrowser for help on using the repository browser.