⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2cdrv.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
字号:
/* I2C driver for MCF5206eLITE board. I2C bus accessed through on-chip * MCF5206e MBUS controller. * * The purpose of this module is to perform I2C driver initialization * and serialize I2C transfers. * * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia * Author: Victor V. Vengerov <vvv@oktet.ru> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * * http://www.rtems.com/license/LICENSE. * * @(#) $Id: i2cdrv.c,v 1.2.2.1 2003/09/04 18:44:30 joel Exp $ */#include <rtems.h>#include <bsp.h>#include <stdlib.h>#include <string.h>#include "i2c.h"#include "i2cdrv.h"#include "mcf5206/mcfmbus.h"#ifndef I2C_NUMBER_OF_BUSES#define I2C_NUMBER_OF_BUSES (1)#endif#ifndef I2C_SELECT_BUS#define I2C_SELECT_BUS(bus)#endif/*  * Few I2C transfers may be posted simultaneously, but MBUS driver is able * to process it one-by-one. To serialize transfers, function i2c_transfer * put transfer information to the queue and initiate new transfers if MBUS * driver is not busy. When driver is busy, next transfer is dequeued * when current active transfer is finished. *//*  * i2c_qel - I2C transfers queue element; contain information about * delayed transfer */typedef struct i2c_qel {    i2c_bus_number    bus;      /* I2C bus number */    i2c_message      *msg;      /* pointer to the transfer' messages array */    int               nmsg;     /* number of messages in transfer */    i2c_transfer_done done;     /* transfer done callback function */    rtems_unsigned32  done_arg; /* arbitrary argument to done callback */} i2c_qel;/* Memory for I2C transfer queue. This queue represented like a ring buffer */static i2c_qel *tqueue;/* Maximum number of elements in transfer queue */static int tqueue_size;/* Position of next free element in a ring buffer */static volatile int tqueue_head;/* Position of the first element in transfer queue */static volatile int tqueue_tail;/* MBus I2C bus controller busy flag */static volatile rtems_boolean mbus_busy;/* MBus I2C bus controller descriptor */static mcfmbus mbus;/* Clock rate selected for each of bus */static int i2cdrv_bus_clock_div[I2C_NUMBER_OF_BUSES];/* Currently selected I2C bus clock rate */static int i2cdrv_bus_clock_div_current;/* Forward function declaration */static void i2cdrv_unload(void);/* i2cdrv_done -- *     Callback function which is called from MBus low-level driver when *     transfer is finished. */static voidi2cdrv_done(rtems_unsigned32 arg){    rtems_interrupt_level level;    i2c_qel *qel = tqueue + tqueue_tail;    qel->done(qel->done_arg);    rtems_interrupt_disable(level);    tqueue_tail = (tqueue_tail + 1) % tqueue_size;    mbus_busy = 0;    rtems_interrupt_enable(level);    i2cdrv_unload();}/* i2cdrv_unload -- *     If MBUS controller is not busy and transfer waiting in a queue, *     initiate processing of the next transfer in queue. */static voidi2cdrv_unload(void){    rtems_interrupt_level level;    i2c_qel *qel;    rtems_status_code sc;    rtems_interrupt_disable(level);    if (!mbus_busy && (tqueue_head != tqueue_tail))    {        mbus_busy = 1;        rtems_interrupt_enable(level);        qel = tqueue + tqueue_tail;                I2C_SELECT_BUS(qel->bus);        if (i2cdrv_bus_clock_div[qel->bus] != i2cdrv_bus_clock_div_current)        {            i2cdrv_bus_clock_div_current = i2cdrv_bus_clock_div[qel->bus];            mcfmbus_select_clock_divider(&mbus, i2cdrv_bus_clock_div_current);        }        sc = mcfmbus_i2c_transfer(&mbus, qel->nmsg, qel->msg, i2cdrv_done,                                  (rtems_unsigned32)qel);        if (sc != RTEMS_SUCCESSFUL)        {            int i;            for (i = 0; i < qel->nmsg; i++)            {                qel->msg[i].status = I2C_RESOURCE_NOT_AVAILABLE;            }            i2cdrv_done((rtems_unsigned32)qel);        }    }    else    {        rtems_interrupt_enable(level);    }}/* i2c_transfer -- *     Initiate multiple-messages transfer over specified I2C bus or *     put request into queue if bus or some other resource is busy. (This *     is non-blocking function). * * PARAMETERS: *     bus - I2C bus number *     nmsg - number of messages *     msg - pointer to messages array *     done - function which is called when transfer is finished *     done_arg - arbitrary argument passed to done funciton * * RETURNS: *     RTEMS_SUCCESSFUL if transfer initiated successfully, or error *     code if something failed. */rtems_status_codei2c_transfer(i2c_bus_number bus, int nmsg, i2c_message *msg,             i2c_transfer_done done, rtems_unsigned32 done_arg){    i2c_qel qel;    rtems_interrupt_level level;        if (bus >= I2C_NUMBER_OF_BUSES)    {        return RTEMS_INVALID_NUMBER;    }        if (msg == NULL)    {        return RTEMS_INVALID_ADDRESS;    }        qel.bus = bus;    qel.msg = msg;    qel.nmsg = nmsg;    qel.done = done;    qel.done_arg = done_arg;    rtems_interrupt_disable(level);    if ((tqueue_head + 1) % tqueue_size == tqueue_tail)    {        rtems_interrupt_enable(level);        return RTEMS_TOO_MANY;    }    memcpy(tqueue + tqueue_head, &qel, sizeof(qel));    tqueue_head = (tqueue_head + 1) % tqueue_size;    rtems_interrupt_enable(level);    i2cdrv_unload();    return RTEMS_SUCCESSFUL;}/* i2cdrv_initialize -- *     I2C driver initialization (rtems I/O driver primitive) */rtems_device_driveri2cdrv_initialize(rtems_device_major_number major,                  rtems_device_minor_number minor,                  void *arg){    int i;    rtems_status_code sc;    mbus_busy = 0;    tqueue_tail = tqueue_head = 0;    tqueue_size = 32;    tqueue = calloc(tqueue_size, sizeof(i2c_qel));        sc = mcfmbus_initialize(&mbus, MBAR);    if (sc != RTEMS_SUCCESSFUL)        return sc;        for (i = 0; i < I2C_NUMBER_OF_BUSES; i++)    {        sc = i2c_select_clock_rate(i, 4096);        if (sc != RTEMS_SUCCESSFUL)            return sc;    }    i2cdrv_bus_clock_div_current = -1;    return RTEMS_SUCCESSFUL;}/* i2c_select_clock_rate -- *     select I2C bus clock rate for specified bus. Some bus controller do not *     allow to select arbitrary clock rate; in this case nearest possible  *     slower clock rate is selected. * * PARAMETERS: *     bus - I2C bus number *     bps - data transfer rate for this bytes in bits per second * * RETURNS: *     RTEMS_SUCCESSFUL, if operation performed successfully,  *     RTEMS_INVALID_NUMBER, if wrong bus number is specified, *     RTEMS_UNSATISFIED, if bus do not support data transfer rate selection *     or specified data transfer rate could not be used. */rtems_status_codei2c_select_clock_rate(i2c_bus_number bus, int bps){    int div;    if (bus >= I2C_NUMBER_OF_BUSES)        return RTEMS_INVALID_NUMBER;        if (bps == 0)        return RTEMS_UNSATISFIED;        div = BSP_SYSTEM_FREQUENCY / bps;    i2cdrv_bus_clock_div[bus] = div;    return RTEMS_SUCCESSFUL;}/* i2c_poll -- *     Poll I2C bus controller for events and hanle it. This function is *     used when I2C driver operates in poll-driven mode. * * PARAMETERS: *     bus - bus number to be polled * * RETURNS: *     none */voidi2c_poll(i2c_bus_number bus){    mcfmbus_poll(&mbus);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -