Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:46

0001 /* I2C bus common (driver-independent) primitives implementation.
0002  *
0003  * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
0004  * Author: Victor V. Vengerov <vvv@oktet.ru>
0005  *
0006  * The license and distribution terms for this file may be
0007  * found in the file LICENSE in this distribution or at
0008  *
0009  * http://www.rtems.org/license/LICENSE.
0010  */
0011 
0012 #include <bsp.h>
0013 #include <i2c.h>
0014 #include <rtems/score/sysstate.h>
0015 
0016 /* i2c_transfer_sema_done_func --
0017  *     This function called from I2C driver layer to signal that I2C
0018  *     transfer is finished. This function resumes of task execution which
0019  *     has invoked blocking I2C primitive.
0020  *
0021  * PARAMETERS:
0022  *     arg - done function argument; it is RTEMS semaphore ID.
0023  */
0024 static void
0025 i2c_transfer_sema_done_func(void * arg)
0026 {
0027     rtems_id sema = *(rtems_id *)arg;
0028     rtems_semaphore_release(sema);
0029 }
0030 
0031 /* i2c_transfer_poll_done_func --
0032  *     This function called from I2C driver layer to signal that I2C
0033  *     transfer is finished. This function set the flag polled by waiting
0034  *     function.
0035  *
0036  * PARAMETERS:
0037  *     arg - done function argument; address of poll_done_flag
0038  */
0039 static void
0040 i2c_transfer_poll_done_func(void *arg)
0041 {
0042     bool *poll_done_flag = (bool *)arg;
0043     *poll_done_flag = true;
0044 }
0045 
0046 /* i2c_transfer_wait_sema --
0047  *     Initiate I2C bus transfer and block on temporary created semaphore
0048  *     until this transfer will be finished.
0049  *
0050  * PARAMETERS:
0051  *     bus - I2C bus number
0052  *     msg - pointer to transfer messages array
0053  *     nmsg - number of messages in transfer
0054  *
0055  * RETURNS:
0056  *     RTEMS_SUCCESSFUL, if tranfer finished successfully,
0057  *     or RTEMS status code if semaphore operations has failed.
0058  */
0059 static i2c_message_status
0060 i2c_transfer_wait_sema(i2c_bus_number bus, i2c_message *msg, int nmsg)
0061 {
0062     rtems_status_code sc;
0063     rtems_id sema;
0064     sc = rtems_semaphore_create(
0065         rtems_build_name('I', '2', 'C', 'S'),
0066         0,
0067         RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
0068         RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
0069         0,
0070         &sema
0071     );
0072     if (sc != RTEMS_SUCCESSFUL)
0073         return I2C_RESOURCE_NOT_AVAILABLE;
0074     sc = i2c_transfer(bus, nmsg, msg,
0075               i2c_transfer_sema_done_func, &sema);
0076     if (sc != RTEMS_SUCCESSFUL)
0077     {
0078         rtems_semaphore_delete(sema);
0079         return sc;
0080     }
0081     rtems_semaphore_obtain(sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0082     sc = rtems_semaphore_delete(sema);
0083     return sc;
0084 }
0085 
0086 /* i2c_transfer_wait_poll --
0087  *     Initiate I2C bus transfer and wait by poll transaction done flag until
0088  *     this transfer will be finished.
0089  *
0090  * PARAMETERS:
0091  *     bus - I2C bus number
0092  *     msg - pointer to transfer messages array
0093  *     nmsg - number of messages in transfer
0094  *
0095  * RETURNS:
0096  *     RTEMS_SUCCESSFUL
0097  */
0098 static rtems_status_code
0099 i2c_transfer_wait_poll(i2c_bus_number bus, i2c_message *msg, int nmsg)
0100 {
0101   /*
0102    * this looks nasty, but is correct:
0103    * we wait in this function, until the poll_done_flag is
0104    * set deep inside the i2c_poll() function
0105    */
0106     volatile bool poll_done_flag;
0107     rtems_status_code sc;
0108     poll_done_flag = false;
0109     sc = i2c_transfer(bus, nmsg, msg,
0110               i2c_transfer_poll_done_func,(void *)&poll_done_flag);
0111     if (sc != RTEMS_SUCCESSFUL)
0112         return sc;
0113     while (poll_done_flag == false)
0114     {
0115         i2c_poll(bus);
0116     }
0117     return RTEMS_SUCCESSFUL;
0118 }
0119 
0120 /* i2c_transfer_wait --
0121  *     Initiate I2C bus transfer and block until this transfer will be
0122  *     finished. This function wait the semaphore if system in
0123  *     SYSTEM_STATE_UP state, or poll done flag in other states.
0124  *
0125  * PARAMETERS:
0126  *     bus - I2C bus number
0127  *     msg - pointer to transfer messages array
0128  *     nmsg - number of messages in transfer
0129  *
0130  * RETURNS:
0131  *     I2C_SUCCESSFUL, if tranfer finished successfully,
0132  *     I2C_RESOURCE_NOT_AVAILABLE, if semaphore operations has failed,
0133  *     value of status field of first error-finished message in transfer,
0134  *     if something wrong.
0135  */
0136 i2c_message_status
0137 i2c_transfer_wait(i2c_bus_number bus, i2c_message *msg, int nmsg)
0138 {
0139     rtems_status_code sc;
0140     int i;
0141     if (_System_state_Is_up(_System_state_Get()))
0142     {
0143         sc = i2c_transfer_wait_sema(bus, msg, nmsg);
0144     }
0145     else
0146     {
0147         sc = i2c_transfer_wait_poll(bus, msg, nmsg);
0148     }
0149 
0150     if (sc != RTEMS_SUCCESSFUL)
0151         return I2C_RESOURCE_NOT_AVAILABLE;
0152 
0153     for (i = 0; i < nmsg; i++)
0154     {
0155         if (msg[i].status != I2C_SUCCESSFUL)
0156         {
0157             return msg[i].status;
0158         }
0159     }
0160     return I2C_SUCCESSFUL;
0161 }
0162 
0163 /* i2c_write --
0164  *     Send single message over specified I2C bus to addressed device and
0165  *     wait while transfer is finished.
0166  *
0167  * PARAMETERS:
0168  *     bus  - I2C bus number
0169  *     addr - address of I2C device
0170  *     buf  - data to be sent to device
0171  *     size - data buffer size
0172  *
0173  * RETURNS:
0174  *     transfer status
0175  */
0176 i2c_message_status
0177 i2c_write(i2c_bus_number bus, i2c_address addr, void *buf, int size)
0178 {
0179     i2c_message msg;
0180     msg.addr = addr;
0181     msg.flags = I2C_MSG_WR;
0182     if (addr > 0xff)
0183         msg.flags |= I2C_MSG_ADDR_10;
0184     msg.status = 0;
0185     msg.len = size;
0186     msg.buf = buf;
0187     return i2c_transfer_wait(bus, &msg, 1);
0188 }
0189 
0190 /* i2c_wrbyte --
0191  *     Send single one-byte long message over specified I2C bus to
0192  *     addressed device and wait while transfer is finished.
0193  *
0194  * PARAMETERS:
0195  *     bus  - I2C bus number
0196  *     addr - address of I2C device
0197  *     cmd  - byte message to be sent to device
0198  *
0199  * RETURNS:
0200  *     transfer status
0201  */
0202 i2c_message_status
0203 i2c_wrbyte(i2c_bus_number bus, i2c_address addr, uint8_t         cmd)
0204 {
0205     i2c_message msg;
0206     uint8_t         data = cmd;
0207     msg.addr = addr;
0208     msg.flags = I2C_MSG_WR;
0209     if (addr > 0xff)
0210         msg.flags |= I2C_MSG_ADDR_10;
0211     msg.status = 0;
0212     msg.len = sizeof(data);
0213     msg.buf = &data;
0214     return i2c_transfer_wait(bus, &msg, 1);
0215 }
0216 
0217 /* i2c_read --
0218  *     receive single message over specified I2C bus from addressed device.
0219  *     This call will wait while transfer is finished.
0220  *
0221  * PARAMETERS:
0222  *     bus  - I2C bus number
0223  *     addr - address of I2C device
0224  *     buf  - buffer for received message
0225  *     size - receive buffer size
0226  *
0227  * RETURNS:
0228  *     transfer status
0229  */
0230 i2c_message_status
0231 i2c_read(i2c_bus_number bus, i2c_address addr, void *buf, int size)
0232 {
0233     i2c_message msg;
0234     msg.addr = addr;
0235     msg.flags = 0;
0236     if (addr > 0xff)
0237         msg.flags |= I2C_MSG_ADDR_10;
0238     msg.status = 0;
0239     msg.len = size;
0240     msg.buf = buf;
0241     return i2c_transfer_wait(bus, &msg, 1);
0242 }
0243 
0244 /* i2c_wrrd --
0245  *     Send message over I2C bus to specified device and receive message
0246  *     from the same device during single transfer.
0247  *
0248  * PARAMETERS:
0249  *     bus   - I2C bus number
0250  *     addr  - address of I2C device
0251  *     bufw  - data to be sent to device
0252  *     sizew - send data buffer size
0253  *     bufr  - buffer for received message
0254  *     sizer - receive buffer size
0255  *
0256  * RETURNS:
0257  *     transfer status
0258  */
0259 i2c_message_status
0260 i2c_wrrd(i2c_bus_number bus, i2c_address addr, void *bufw, int sizew,
0261          void *bufr, int sizer)
0262 {
0263     i2c_message msg[2];
0264     msg[0].addr = addr;
0265     msg[0].flags = I2C_MSG_WR | I2C_MSG_ERRSKIP;
0266     if (addr > 0xff)
0267         msg[0].flags |= I2C_MSG_ADDR_10;
0268     msg[0].status = 0;
0269     msg[0].len = sizew;
0270     msg[0].buf = bufw;
0271 
0272     msg[1].addr = addr;
0273     msg[1].flags = 0;
0274     if (addr > 0xff)
0275         msg[1].flags |= I2C_MSG_ADDR_10;
0276     msg[1].status = 0;
0277     msg[1].len = sizer;
0278     msg[1].buf = bufr;
0279 
0280     return i2c_transfer_wait(bus, msg, 2);
0281 }
0282 
0283 /* i2c_wbrd --
0284  *     Send one-byte message over I2C bus to specified device and receive
0285  *     message from the same device during single transfer.
0286  *
0287  * PARAMETERS:
0288  *     bus   - I2C bus number
0289  *     addr  - address of I2C device
0290  *     cmd   - one-byte message to be sent over I2C bus
0291  *     bufr  - buffer for received message
0292  *     sizer - receive buffer size
0293  *
0294  * RETURNS:
0295  *     transfer status
0296  */
0297 i2c_message_status
0298 i2c_wbrd(i2c_bus_number bus, i2c_address addr, uint8_t         cmd,
0299          void *bufr, int sizer)
0300 {
0301     i2c_message msg[2];
0302     uint8_t         bufw = cmd;
0303     msg[0].addr = addr;
0304     msg[0].flags = I2C_MSG_WR | I2C_MSG_ERRSKIP;
0305     if (addr > 0xff)
0306         msg[0].flags |= I2C_MSG_ADDR_10;
0307     msg[0].status = 0;
0308     msg[0].len = sizeof(bufw);
0309     msg[0].buf = &bufw;
0310 
0311     msg[1].addr = addr;
0312     msg[1].flags = I2C_MSG_ERRSKIP;
0313     if (addr > 0xff)
0314         msg[1].flags |= I2C_MSG_ADDR_10;
0315     msg[1].status = 0;
0316     msg[1].len = sizer;
0317     msg[1].buf = bufr;
0318 
0319     return i2c_transfer_wait(bus, msg, 2);
0320 }