Back to home page

LXR

 
 

    


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

0001 /*
0002  * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>
0003  * All rights reserved.
0004  *
0005  * The license and distribution terms for this file may be
0006  * found in the file LICENSE in this distribution or at
0007  * http://www.rtems.org/license/LICENSE.
0008  */
0009 
0010 /*
0011  * I2C slave for testing:
0012  *       https://github.com/oetr/FPGA-I2C-Slave
0013  */
0014 
0015 #ifdef HAVE_CONFIG_H
0016 #include "config.h"
0017 #endif
0018 
0019 #include <dev/i2c/i2c.h>
0020 #include <dev/i2c/fpga-i2c-slave.h>
0021 
0022 typedef struct {
0023   i2c_dev  base;
0024   uint16_t address;
0025   size_t   size;
0026 } fpga_i2c_slave;
0027 
0028 static ssize_t
0029 fpga_i2c_slave_read(i2c_dev* base, void* buf, size_t n, off_t offset)
0030 {
0031   fpga_i2c_slave* dev = (fpga_i2c_slave*) base;
0032   off_t           avail = dev->size - offset;
0033   uint8_t*        in = buf;
0034   size_t          todo;
0035 
0036   if (avail <= 0) {
0037     return 0;
0038   }
0039 
0040   if (n > avail) {
0041     n = (size_t) avail;
0042   }
0043 
0044   todo = n;
0045 
0046   while (todo > 0) {
0047     /*
0048      * Limit the transfer size so that it can be stored in 8-bits.  This may
0049      * help some bus controllers.
0050      */
0051     uint16_t cur = (uint16_t) (todo < 255 ?  todo : 255);
0052     i2c_msg msgs = {
0053       .addr = dev->base.address,
0054       .flags = I2C_M_RD,
0055       .buf = in,
0056       .len = cur
0057     };
0058     int err;
0059     err = i2c_bus_transfer(dev->base.bus, &msgs, 1);
0060     if (err != 0) {
0061       return err;
0062     }
0063     todo -= cur;
0064     in += cur;
0065   }
0066 
0067   return (ssize_t) n;
0068 }
0069 
0070 static ssize_t
0071 fpga_i2c_slave_write(i2c_dev* base, const void* buf, size_t n, off_t offset)
0072 {
0073   fpga_i2c_slave* dev = (fpga_i2c_slave*) base;
0074   off_t           avail = dev->size - offset;
0075   const uint8_t*  out = buf;
0076   size_t          todo;
0077 
0078   if (avail <= 0) {
0079     return 0;
0080   }
0081 
0082   if (n > avail) {
0083     n = (size_t) avail;
0084   }
0085 
0086   todo = n;
0087 
0088   while (todo > 0) {
0089     /*
0090      * Limit the transfer size so that it can be stored in 8-bits.  This may
0091      * help some bus controllers.
0092      */
0093     uint16_t cur = (uint16_t) (todo < 255 ?  todo : 255);
0094     i2c_msg msgs = {
0095       .addr = dev->base.address,
0096       .flags = 0,
0097       .buf = RTEMS_DECONST(uint8_t*, out),
0098       .len = cur
0099     };
0100     int err;
0101     err = i2c_bus_transfer(dev->base.bus, &msgs, 1);
0102     if (err != 0) {
0103       return err;
0104     }
0105     todo -= cur;
0106     out += cur;
0107   }
0108 
0109   return (ssize_t) n;
0110 }
0111 
0112 int
0113 i2c_dev_register_fpga_i2c_slave(const char* bus_path,
0114                                 const char* dev_path,
0115                                 uint16_t    address,
0116                                 size_t      size)
0117 
0118 {
0119   fpga_i2c_slave* dev;
0120 
0121   dev = (fpga_i2c_slave*)
0122     i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
0123   if (dev == NULL) {
0124     return -1;
0125   }
0126 
0127   dev->base.read = fpga_i2c_slave_read;
0128   dev->base.write = fpga_i2c_slave_write;
0129   dev->size = size;
0130 
0131   return i2c_dev_register(&dev->base, dev_path);
0132 }