我们从2011年坚守至今,只想做存粹的技术论坛。  由于网站在外面,点击附件后要很长世间才弹出下载,请耐心等待,勿重复点击不要用Edge和IE浏览器下载,否则提示不安全下载不了

 找回密码
 立即注册
搜索
查看: 1549|回复: 1

RK3188  I2C 协议 源码

[复制链接]

该用户从未签到

812

主题

399

回帖

499

积分

二级逆天

积分
499

社区居民社区明星忠实会员宣传大使奖终身成就奖特殊贡献奖

QQ
发表于 2015-7-18 11:23:56 | 显示全部楼层 |阅读模式
/* i2c-core.c - a device driver for the iic-bus interface             */
/* ------------------------------------------------------------------------- */
/*   Copyright (C) 1995-99 Simon G. Vogl

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             */
/* ------------------------------------------------------------------------- */

    /* Consistency check */
    if (info.type[0] == '\0') {
        dev_err(&adapter->dev, "%s detection function provided "
            "no name for 0x%x\n", driver->driver.name,
            addr);
    } else {
        struct i2c_client *client;

        /* Detection succeeded, instantiate the device */
        dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
            info.type, info.addr);
        client = i2c_new_device(adapter, &info);
        if (client)
            list_add_tail(&client->detected, &driver->clients);
        else
            dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
                info.type, info.addr);
    }
    return 0;
}

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
    const unsigned short *address_list;
    struct i2c_client *temp_client;
    int i, err = 0;
    int adap_id = i2c_adapter_id(adapter);

    address_list = driver->address_list;
    if (!driver->detect || !address_list)
        return 0;

    /* Stop here if the classes do not match */
    if (!(adapter->class & driver->class))
        return 0;

    /* Set up a temporary client to help detect callback */
    temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
    if (!temp_client)
        return -ENOMEM;
    temp_client->adapter = adapter;

    for (i = 0; address_list != I2C_CLIENT_END; i += 1) {
        dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
            "addr 0x%02x\n", adap_id, address_list);
        temp_client->addr = address_list;
        err = i2c_detect_address(temp_client, driver);
        if (unlikely(err))
            break;
    }

    kfree(temp_client);
    return err;
}

int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
{
    return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
                  I2C_SMBUS_QUICK, NULL) >= 0;
}
EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);

struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
              struct i2c_board_info *info,
              unsigned short const *addr_list,
              int (*probe)(struct i2c_adapter *, unsigned short addr))
{
    int i;

    if (!probe)
        probe = i2c_default_probe;

    for (i = 0; addr_list != I2C_CLIENT_END; i++) {
        /* Check address validity */
        if (i2c_check_addr_validity(addr_list) < 0) {
            dev_warn(&adap->dev, "Invalid 7-bit address "
                 "0x%02x\n", addr_list);
            continue;
        }

        /* Check address availability */
        if (i2c_check_addr_busy(adap, addr_list)) {
            dev_dbg(&adap->dev, "Address 0x%02x already in "
                "use, not probing\n", addr_list);
            continue;
        }

        /* Test address responsiveness */
        if (probe(adap, addr_list))
            break;
    }

    if (addr_list == I2C_CLIENT_END) {
        dev_dbg(&adap->dev, &quotrobing failed, no device found\n");
        return NULL;
    }

    info->addr = addr_list;
    return i2c_new_device(adap, info);
}
EXPORT_SYMBOL_GPL(i2c_new_probed_device);

struct i2c_adapter *i2c_get_adapter(int nr)
{
    struct i2c_adapter *adapter;

    mutex_lock(&core_lock);
    adapter = idr_find(&i2c_adapter_idr, nr);
    if (adapter && !try_module_get(adapter->owner))
        adapter = NULL;

    mutex_unlock(&core_lock);
    return adapter;
}
EXPORT_SYMBOL(i2c_get_adapter);

void i2c_put_adapter(struct i2c_adapter *adap)
{
    module_put(adap->owner);
}
EXPORT_SYMBOL(i2c_put_adapter);

/* The SMBus parts */

#define POLY    (0x1070U << 3)
static u8 crc8(u16 data)
{
    int i;

    for (i = 0; i < 8; i++) {
        if (data & 0x8000)
            data = data ^ POLY;
        data = data << 1;
    }
    return (u8)(data >> 8);
}

/* Incremental CRC8 over count bytes in the array pointed to by p */
static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
{
    int i;

    for (i = 0; i < count; i++)
        crc = crc8((crc ^ p) << 8);
    return crc;
}

/* Assume a 7-bit address, which is reasonable for SMBus */
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
{
    /* The address will be sent first */
    u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
    pec = i2c_smbus_pec(pec, &addr, 1);

    /* The data buffer follows */
    return i2c_smbus_pec(pec, msg->buf, msg->len);
}

/* Used for write only transactions */
static inline void i2c_smbus_add_pec(struct i2c_msg *msg)
{
    msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg);
    msg->len++;
}

/* Return <0 on CRC error
   If there was a write before this read (most cases) we need to take the
   partial CRC from the write part into account.
   Note that this function does modify the message (we need to decrease the
   message length to hide the CRC byte from the caller). */
static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
{
    u8 rpec = msg->buf[--msg->len];
    cpec = i2c_smbus_msg_pec(cpec, msg);

    if (rpec != cpec) {
        pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
            rpec, cpec);
        return -EBADMSG;
    }
    return 0;
}

/**
* i2c_smbus_read_byte - SMBus "receive byte" protocol
* @client: Handle to slave device
*
* This executes the SMBus "receive byte" protocol, returning negative errno
* else the byte received from the device.
*/
s32 i2c_smbus_read_byte(const struct i2c_client *client)
{
    union i2c_smbus_data data;
    int status;

    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_READ, 0,
                I2C_SMBUS_BYTE, &data);
    return (status < 0) ? status : data.byte;
}
EXPORT_SYMBOL(i2c_smbus_read_byte);

/**
* i2c_smbus_write_byte - SMBus "send byte" protocol
* @client: Handle to slave device
* @value: Byte to be sent
*
* This executes the SMBus "send byte" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
{
    return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                          I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
}
EXPORT_SYMBOL(i2c_smbus_write_byte);

/**
* i2c_smbus_read_byte_data - SMBus "read byte" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
*
* This executes the SMBus "read byte" protocol, returning negative errno
* else a data byte received from the device.
*/
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
{
    union i2c_smbus_data data;
    int status;

    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_READ, command,
                I2C_SMBUS_BYTE_DATA, &data);
    return (status < 0) ? status : data.byte;
}
EXPORT_SYMBOL(i2c_smbus_read_byte_data);

/**
* i2c_smbus_write_byte_data - SMBus "write byte" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @value: Byte being written
*
* This executes the SMBus "write byte" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
                  u8 value)
{
    union i2c_smbus_data data;
    data.byte = value;
    return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                  I2C_SMBUS_WRITE, command,
                  I2C_SMBUS_BYTE_DATA, &data);
}
EXPORT_SYMBOL(i2c_smbus_write_byte_data);

/**
* i2c_smbus_read_word_data - SMBus "read word" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
*
* This executes the SMBus "read word" protocol, returning negative errno
* else a 16-bit unsigned "word" received from the device.
*/
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
{
    union i2c_smbus_data data;
    int status;

    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_READ, command,
                I2C_SMBUS_WORD_DATA, &data);
    return (status < 0) ? status : data.word;
}
EXPORT_SYMBOL(i2c_smbus_read_word_data);

/**
* i2c_smbus_write_word_data - SMBus "write word" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @value: 16-bit "word" being written
*
* This executes the SMBus "write word" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
                  u16 value)
{
    union i2c_smbus_data data;
    data.word = value;
    return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                  I2C_SMBUS_WRITE, command,
                  I2C_SMBUS_WORD_DATA, &data);
}
EXPORT_SYMBOL(i2c_smbus_write_word_data);

/**
* i2c_smbus_process_call - SMBus "process call" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @value: 16-bit "word" being written
*
* This executes the SMBus "process call" protocol, returning negative errno
* else a 16-bit unsigned "word" received from the device.
*/
s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command,
               u16 value)
{
    union i2c_smbus_data data;
    int status;
    data.word = value;

    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_WRITE, command,
                I2C_SMBUS_PROC_CALL, &data);
    return (status < 0) ? status : data.word;
}
EXPORT_SYMBOL(i2c_smbus_process_call);

/**
* i2c_smbus_read_block_data - SMBus "block read" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @values: Byte array into which data will be read; big enough to hold
*    the data returned by the slave.  SMBus allows at most 32 bytes.
*
* This executes the SMBus "block read" protocol, returning negative errno
* else the number of data bytes in the slave's response.
*
* Note that using this function requires that the client's adapter support
* the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality.  Not all adapter drivers
* support this; its emulation through I2C messaging relies on a specific
* mechanism (I2C_M_RECV_LEN) which may not be implemented.
*/
s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command,
                  u8 *values)
{
    union i2c_smbus_data data;
    int status;

    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_READ, command,
                I2C_SMBUS_BLOCK_DATA, &data);
    if (status)
        return status;

    memcpy(values, &data.block[1], data.block[0]);
    return data.block[0];
}
EXPORT_SYMBOL(i2c_smbus_read_block_data);

/**
* i2c_smbus_write_block_data - SMBus "block write" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @length: Size of data block; SMBus allows at most 32 bytes
* @values: Byte array which will be written.
*
* This executes the SMBus "block write" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command,
                   u8 length, const u8 *values)
{
    union i2c_smbus_data data;

    if (length > I2C_SMBUS_BLOCK_MAX)
        length = I2C_SMBUS_BLOCK_MAX;
    data.block[0] = length;
    memcpy(&data.block[1], values, length);
    return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                  I2C_SMBUS_WRITE, command,
                  I2C_SMBUS_BLOCK_DATA, &data);
}
EXPORT_SYMBOL(i2c_smbus_write_block_data);

/* Returns the number of read bytes */
s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command,
                  u8 length, u8 *values)
{
    union i2c_smbus_data data;
    int status;

    if (length > I2C_SMBUS_BLOCK_MAX)
        length = I2C_SMBUS_BLOCK_MAX;
    data.block[0] = length;
    status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                I2C_SMBUS_READ, command,
                I2C_SMBUS_I2C_BLOCK_DATA, &data);
    if (status < 0)
        return status;

    memcpy(values, &data.block[1], data.block[0]);
    return data.block[0];
}
EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);

s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
                   u8 length, const u8 *values)
{
    union i2c_smbus_data data;

    if (length > I2C_SMBUS_BLOCK_MAX)
        length = I2C_SMBUS_BLOCK_MAX;
    data.block[0] = length;
    memcpy(data.block + 1, values, length);
    return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
                  I2C_SMBUS_WRITE, command,
                  I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);

/* Simulate a SMBus command using the i2c protocol
   No checking of parameters is done!  */
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
                   unsigned short flags,
                   char read_write, u8 command, int size,
                   union i2c_smbus_data *data)
{
    /* So we need to generate a series of msgs. In the case of writing, we
      need to use only one message; when reading, we need two. We initialize
      most things with sane defaults, to keep the code below somewhat
      simpler. */
    unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
    unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
    int num = read_write == I2C_SMBUS_READ ? 2 : 1;
    struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0, 100000, 0, 0 },
                              { addr, flags | I2C_M_RD, 0, msgbuf1, 100000, 0, 0 }
                            };
    int i;
    u8 partial_pec = 0;
    int status;

    msgbuf0[0] = command;
    switch (size) {
    case I2C_SMBUS_QUICK:
        msg[0].len = 0;
        /* Special case: The read/write field is used as data */
        msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
                    I2C_M_RD : 0);
        num = 1;
        break;
    case I2C_SMBUS_BYTE:
        if (read_write == I2C_SMBUS_READ) {
            /* Special case: only a read! */
            msg[0].flags = I2C_M_RD | flags;
            num = 1;
        }
        break;
    case I2C_SMBUS_BYTE_DATA:
        if (read_write == I2C_SMBUS_READ)
            msg[1].len = 1;
        else {
            msg[0].len = 2;
            msgbuf0[1] = data->byte;
        }
        break;
    case I2C_SMBUS_WORD_DATA:
        if (read_write == I2C_SMBUS_READ)
            msg[1].len = 2;
        else {
            msg[0].len = 3;
            msgbuf0[1] = data->word & 0xff;
            msgbuf0[2] = data->word >> 8;
        }
        break;
    case I2C_SMBUS_PROC_CALL:
        num = 2; /* Special case */
        read_write = I2C_SMBUS_READ;
        msg[0].len = 3;
        msg[1].len = 2;
        msgbuf0[1] = data->word & 0xff;
        msgbuf0[2] = data->word >> 8;
        break;
    case I2C_SMBUS_BLOCK_DATA:
        if (read_write == I2C_SMBUS_READ) {
            msg[1].flags |= I2C_M_RECV_LEN;
            msg[1].len = 1; /* block length will be added by
                       the underlying bus driver */
        } else {
            msg[0].len = data->block[0] + 2;
            if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
                dev_err(&adapter->dev,
                    "Invalid block write size %d\n",
                    data->block[0]);
                return -EINVAL;
            }
            for (i = 1; i < msg[0].len; i++)
                msgbuf0 = data->block[i-1];
        }
        break;
    case I2C_SMBUS_BLOCK_PROC_CALL:
        num = 2; /* Another special case */
        read_write = I2C_SMBUS_READ;
        if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
            dev_err(&adapter->dev,
                "Invalid block write size %d\n",
                data->block[0]);
            return -EINVAL;
        }
        msg[0].len = data->block[0] + 2;
        for (i = 1; i < msg[0].len; i++)
            msgbuf0 = data->block[i-1];
        msg[1].flags |= I2C_M_RECV_LEN;
        msg[1].len = 1; /* block length will be added by
                   the underlying bus driver */
        break;

            break;
        case I2C_SMBUS_BYTE_DATA:
            data->byte = msgbuf1[0];
            break;
        case I2C_SMBUS_WORD_DATA:
        case I2C_SMBUS_PROC_CALL:
            data->word = msgbuf1[0] | (msgbuf1[1] << 8);
            break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
            for (i = 0; i < data->block[0]; i++)
                data->block[i+1] = msgbuf1;
            break;
        case I2C_SMBUS_BLOCK_DATA:
        case I2C_SMBUS_BLOCK_PROC_CALL:
            for (i = 0; i < msgbuf1[0] + 1; i++)
                data->block = msgbuf1;
            break;
        }
    return 0;
}

/**
* i2c_smbus_xfer - execute SMBus protocol operations
* @adapter: Handle to I2C bus
* @addr: Address of SMBus slave on that bus
* @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
* @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
* @command: Byte interpreted by slave, for protocols which use such bytes
* @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
* @data: Data to be read or written
*
* This executes an SMBus protocol operation, and returns a negative
* errno code else zero on success.
*/
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
           char read_write, u8 command, int protocol,
           union i2c_smbus_data *data)
{
    unsigned long orig_jiffies;
    int try;
    s32 res;

    flags &= I2C_M_TEN | I2C_CLIENT_PEC;

    if (adapter->algo->smbus_xfer) {
        i2c_lock_adapter(adapter);

        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (res = 0, try = 0; try <= adapter->retries; try++) {
            res = adapter->algo->smbus_xfer(adapter, addr, flags,
                            read_write, command,
                            protocol, data);
            if (res != -EAGAIN)
                break;
            if (time_after(jiffies,
                       orig_jiffies + adapter->timeout))
                break;
        }
        i2c_unlock_adapter(adapter);
    } else
        res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
                          command, protocol, data);

    return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);

MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL");
回复

使用道具 举报

该用户从未签到

16

主题

756

回帖

415

积分

二级逆天

积分
415

终身成就奖原创先锋奖社区居民宣传大使奖

QQ
发表于 2015-8-1 16:30:46 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

论坛开启做任务可以
额外奖励金币快速赚
积分升级了


Copyright ©2011-2024 NTpcb.com All Right Reserved.  Powered by Discuz! (NTpcb)

本站信息均由会员发表,不代表NTpcb立场,如侵犯了您的权利请发帖投诉

平平安安
TOP
快速回复 返回顶部 返回列表