source: rtems/cpukit/dev/i2c/i2c-bus.c @ 255fe43

Last change on this file since 255fe43 was 255fe43, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 20:40:44

cpukit/: Scripted embedded brains header file clean up

Updates #4625.

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