File indexing completed on 2025-05-11 08:24:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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 }