Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:11

0001 /**
0002  * @file
0003  *
0004  * @brief Inter-Integrated Circuit (I2C) Bus Implementation
0005  *
0006  * @ingroup I2CBus
0007  */
0008 
0009 /*
0010  * Copyright (C) 2014, 2017 embedded brains GmbH & Co. KG
0011  *
0012  * The license and distribution terms for this file may be
0013  * found in the file LICENSE in this distribution or at
0014  * http://www.rtems.org/license/LICENSE.
0015  */
0016 
0017 #ifdef HAVE_CONFIG_H
0018 #include "config.h"
0019 #endif
0020 
0021 #include <dev/i2c/i2c.h>
0022 
0023 #include <rtems/imfs.h>
0024 
0025 #include <stdlib.h>
0026 #include <string.h>
0027 
0028 int i2c_bus_try_obtain(i2c_bus *bus)
0029 {
0030   return rtems_recursive_mutex_try_lock(&bus->mutex);
0031 }
0032 
0033 void i2c_bus_obtain(i2c_bus *bus)
0034 {
0035   rtems_recursive_mutex_lock(&bus->mutex);
0036 }
0037 
0038 void i2c_bus_release(i2c_bus *bus)
0039 {
0040   rtems_recursive_mutex_unlock(&bus->mutex);
0041 }
0042 
0043 int i2c_bus_do_transfer(
0044   i2c_bus *bus,
0045   i2c_msg *msgs,
0046   uint32_t msg_count,
0047   uint32_t flags
0048 )
0049 {
0050   int err;
0051   uint32_t i;
0052   uint32_t j;
0053 
0054   _Assert(msg_count > 0);
0055 
0056   for (i = 0, j = 0; i < msg_count; ++i) {
0057     if ((msgs[i].flags & I2C_M_NOSTART) != 0) {
0058       if ((msgs[i].flags & I2C_M_RD) != (msgs[j].flags & I2C_M_RD)) {
0059         return -EINVAL;
0060       }
0061 
0062       if (msgs[i].addr != msgs[j].addr) {
0063         return -EINVAL;
0064       }
0065     } else {
0066       j = i;
0067     }
0068   }
0069 
0070   if ((flags & I2C_BUS_NOBLOCK) != 0) {
0071     if (i2c_bus_try_obtain(bus) != 0) {
0072       return -EAGAIN;
0073     }
0074   } else {
0075     i2c_bus_obtain(bus);
0076   }
0077   err = (*bus->transfer)(bus, msgs, msg_count);
0078   i2c_bus_release(bus);
0079 
0080   return err;
0081 }
0082 
0083 int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count)
0084 {
0085   return i2c_bus_do_transfer(bus, msgs, msg_count, 0);
0086 }
0087 
0088 static ssize_t i2c_bus_read(
0089   rtems_libio_t *iop,
0090   void *buffer,
0091   size_t count
0092 )
0093 {
0094   i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
0095   i2c_msg msg = {
0096     .addr = bus->default_address,
0097     .flags = I2C_M_RD,
0098     .len = (uint16_t) count,
0099     .buf = buffer
0100   };
0101   int err;
0102   unsigned flags = 0;
0103 
0104   if (bus->ten_bit_address) {
0105     msg.flags |= I2C_M_TEN;
0106   }
0107 
0108   if (rtems_libio_iop_is_no_delay(iop)) {
0109     flags |= I2C_BUS_NOBLOCK;
0110   }
0111 
0112   err = i2c_bus_do_transfer(bus, &msg, 1, flags);
0113   if (err == 0) {
0114     return msg.len;
0115   } else {
0116     rtems_set_errno_and_return_minus_one(-err);
0117   }
0118 }
0119 
0120 static ssize_t i2c_bus_write(
0121   rtems_libio_t *iop,
0122   const void *buffer,
0123   size_t count
0124 )
0125 {
0126   i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
0127   i2c_msg msg = {
0128     .addr = bus->default_address,
0129     .flags = 0,
0130     .len = (uint16_t) count,
0131     .buf = RTEMS_DECONST(void *, buffer)
0132   };
0133   int err;
0134   unsigned flags = 0;
0135 
0136   if (bus->ten_bit_address) {
0137     msg.flags |= I2C_M_TEN;
0138   }
0139 
0140   if (rtems_libio_iop_is_no_delay(iop)) {
0141     flags |= I2C_BUS_NOBLOCK;
0142   }
0143 
0144   err = i2c_bus_do_transfer(bus, &msg, 1, flags);
0145   if (err == 0) {
0146     return msg.len;
0147   } else {
0148     rtems_set_errno_and_return_minus_one(-err);
0149   }
0150 }
0151 
0152 static int i2c_bus_ioctl(
0153   rtems_libio_t *iop,
0154   ioctl_command_t command,
0155   void *arg
0156 )
0157 {
0158   i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
0159   i2c_rdwr_ioctl_data *rdwr;
0160   int err;
0161   unsigned flags = 0;
0162 
0163   switch (command) {
0164     case I2C_RDWR:
0165       rdwr = arg;
0166       if (rdwr->nmsgs > 0) {
0167         if (rtems_libio_iop_is_no_delay(iop)) {
0168           flags |= I2C_BUS_NOBLOCK;
0169         }
0170         err = i2c_bus_do_transfer(bus, rdwr->msgs, rdwr->nmsgs, flags);
0171       } else {
0172         err = 0;
0173       }
0174       break;
0175     case I2C_BUS_OBTAIN:
0176       i2c_bus_obtain(bus);
0177       err = 0;
0178       break;
0179     case I2C_BUS_RELEASE:
0180       i2c_bus_release(bus);
0181       err = 0;
0182       break;
0183     case I2C_BUS_GET_CONTROL:
0184       *(i2c_bus **) arg = bus;
0185       err = 0;
0186       break;
0187     case I2C_FUNCS:
0188       *(unsigned long *) arg = bus->functionality;
0189       err = 0;
0190       break;
0191     case I2C_RETRIES:
0192       bus->retries = (unsigned long) arg;
0193       err = 0;
0194       break;
0195     case I2C_TIMEOUT:
0196       bus->timeout = RTEMS_MILLISECONDS_TO_TICKS(10 * (unsigned long) arg);
0197       err = 0;
0198       break;
0199     case I2C_SLAVE:
0200     case I2C_SLAVE_FORCE:
0201       bus->default_address = (unsigned long) arg;
0202       err = 0;
0203       break;
0204     case I2C_TENBIT:
0205       bus->ten_bit_address = (unsigned long) arg != 0;
0206       err = 0;
0207       break;
0208     case I2C_PEC:
0209       bus->use_pec = (unsigned long) arg != 0;
0210       err = 0;
0211       break;
0212     case I2C_BUS_SET_CLOCK:
0213       i2c_bus_obtain(bus);
0214       err = (*bus->set_clock)(bus, (unsigned long) arg);
0215       i2c_bus_release(bus);
0216       break;
0217     default:
0218       err = -ENOTTY;
0219       break;
0220   }
0221 
0222   if (err == 0) {
0223     return 0;
0224   } else {
0225     rtems_set_errno_and_return_minus_one(-err);
0226   }
0227 }
0228 
0229 static const rtems_filesystem_file_handlers_r i2c_bus_handler = {
0230   .open_h = rtems_filesystem_default_open,
0231   .close_h = rtems_filesystem_default_close,
0232   .read_h = i2c_bus_read,
0233   .write_h = i2c_bus_write,
0234   .ioctl_h = i2c_bus_ioctl,
0235   .lseek_h = rtems_filesystem_default_lseek,
0236   .fstat_h = IMFS_stat,
0237   .ftruncate_h = rtems_filesystem_default_ftruncate,
0238   .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
0239   .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0240   .fcntl_h = rtems_filesystem_default_fcntl,
0241   .kqfilter_h = rtems_filesystem_default_kqfilter,
0242   .mmap_h = rtems_filesystem_default_mmap,
0243   .poll_h = rtems_filesystem_default_poll,
0244   .readv_h = rtems_filesystem_default_readv,
0245   .writev_h = rtems_filesystem_default_writev
0246 };
0247 
0248 static void i2c_bus_node_destroy(IMFS_jnode_t *node)
0249 {
0250   i2c_bus *bus;
0251 
0252   bus = IMFS_generic_get_context_by_node(node);
0253   (*bus->destroy)(bus);
0254 
0255   IMFS_node_destroy_default(node);
0256 }
0257 
0258 static const IMFS_node_control i2c_bus_node_control = IMFS_GENERIC_INITIALIZER(
0259   &i2c_bus_handler,
0260   IMFS_node_initialize_generic,
0261   i2c_bus_node_destroy
0262 );
0263 
0264 int i2c_bus_register(
0265   i2c_bus *bus,
0266   const char *bus_path
0267 )
0268 {
0269   int rv;
0270 
0271   rv = IMFS_make_generic_node(
0272     bus_path,
0273     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
0274     &i2c_bus_node_control,
0275     bus
0276   );
0277   if (rv != 0) {
0278     (*bus->destroy)(bus);
0279   }
0280 
0281   return rv;
0282 }
0283 
0284 static int i2c_bus_transfer_default(
0285   i2c_bus *bus,
0286   i2c_msg *msgs,
0287   uint32_t msg_count
0288 )
0289 {
0290   (void) bus;
0291   (void) msgs;
0292   (void) msg_count;
0293 
0294   return -EIO;
0295 }
0296 
0297 static int i2c_bus_set_clock_default(i2c_bus *bus, unsigned long clock)
0298 {
0299   (void) bus;
0300   (void) clock;
0301 
0302   return -EIO;
0303 }
0304 
0305 static int i2c_bus_do_init(
0306   i2c_bus *bus,
0307   void (*destroy)(i2c_bus *bus)
0308 )
0309 {
0310   rtems_recursive_mutex_init(&bus->mutex, "I2C Bus");
0311   bus->transfer = i2c_bus_transfer_default;
0312   bus->set_clock = i2c_bus_set_clock_default;
0313   bus->destroy = destroy;
0314 
0315   return 0;
0316 }
0317 
0318 void i2c_bus_destroy(i2c_bus *bus)
0319 {
0320   rtems_recursive_mutex_destroy(&bus->mutex);
0321 }
0322 
0323 void i2c_bus_destroy_and_free(i2c_bus *bus)
0324 {
0325   i2c_bus_destroy(bus);
0326   free(bus);
0327 }
0328 
0329 int i2c_bus_init(i2c_bus *bus)
0330 {
0331   memset(bus, 0, sizeof(*bus));
0332 
0333   return i2c_bus_do_init(bus, i2c_bus_destroy);
0334 }
0335 
0336 i2c_bus *i2c_bus_alloc_and_init(size_t size)
0337 {
0338   i2c_bus *bus = NULL;
0339 
0340   if (size >= sizeof(*bus)) {
0341     bus = calloc(1, size);
0342     if (bus != NULL) {
0343       int rv;
0344 
0345       rv = i2c_bus_do_init(bus, i2c_bus_destroy_and_free);
0346       if (rv != 0) {
0347         return NULL;
0348       }
0349     }
0350   }
0351 
0352   return bus;
0353 }