linux i2c设备驱动

客户加了一个MCU来控制主板电源,该MCU作为pnx8735的一个i2C从设备,接收来自pnx8735的i2C的命令。
因此,需要增加一个设备驱动程序,用来控制该MCU工作。

. 在stb225/src/open/comps/下增加新的设备驱动模块,phStbMCU
. 把该模块加入到linux编译列表中
  stb225/etc/roster.mk
  增加phStbMCU,_phStbMCU_KCONFIG = m到列表中
. 完成phStbMCU设备驱动源码,简单引用如下:

  注意:由于MCU挂在i2c 1上,因此需要打开I2C 1,并且最好设置成polling模式。打开之后,在sys/devices/platform/i2c-adapter/下看到i2c-1,下面驱动挂上后,会在i2c-1/下看到挂载的MCU设备,以i2c address命名。

... ... ...
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

... ... ...

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(POWER_MCU_I2CDEV_DESCRIPTION);
MODULE_AUTHOR("Trident B.V.");

/*------------------------------------------------------------------------------------------
**----------- Local Defines, Structures, Enums ---------------------------------------------
**----------------------------------------------------------------------------------------*/
#define I2C_MCU        0x4c

/* I2C Support Structures */
/* Generic i2c probe ... addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */
static unsigned short normal_i2c      [ ] =   { I2C_MCU >> 1, I2C_CLIENT_END };
static unsigned short probe           [2] =   { I2C_CLIENT_END  , I2C_CLIENT_END };
static unsigned short ignore          [2] =   { I2C_CLIENT_END  , I2C_CLIENT_END };

static struct i2c_client_address_data dataAddress =
{
    .normal_i2c         =   normal_i2c,
    .probe              =   probe,
    .ignore             =   ignore
};

/*------------------------------------------------------------------------------------------
**----------- Functions Prototypes ----------- ---------------------------------------------
**----------------------------------------------------------------------------------------*/
static int     I2cAttachMcuAdapter(struct i2c_adapter *adapter);
static int     I2cDetachMcuClient(struct i2c_client *client);

static int     I2cDetectMcuClient(struct i2c_adapter *adapter, int address, int kind);

static int32_t I2cRead(uint32_t kByteCount, uint8_t* pData);
static int32_t I2cWrite(uint32_t kByteCount, uint8_t* pData);

/*------------------------------------------------------------------------------------------
**----------- Global ------ ------------------ ---------------------------------------------
**----------------------------------------------------------------------------------------*/
static struct i2c_driver i2cDriverMcu =
{
    .driver = {
        .name = "cvd-mcu",
    },
    .attach_adapter = I2cAttachMcuAdapter, //每个adapter都会调用该函数,以确定该adapter上有没有挂载该驱动对应的设备
    .detach_client = I2cDetachMcuClient,
};

static struct i2c_client *mcuClient = NULL;

/*------------------------------------------------------------------------------------------
**----------- Functions ------ ------------------ ---------------------------------------------
**----------------------------------------------------------------------------------------*/
static int I2cDetachMcuClient(struct i2c_client *client)
{
    int ret = 0;

    dprintk(1, "De-Attach I2C client (CVD-MCU)\n");
    ret = i2c_detach_client(client);
    if (ret)
    {
        dprintk(1, "De-Attach I2C client failed (CVD-MCU)\n");
        return ret;
    }
    kfree(client);

    return ret;
}

static int I2cAttachMcuAdapter(struct i2c_adapter *adapter)
{
    uint32_t ret = 0;

    dprintk(1, "Attach CVD Mcu\n");
    ret = i2c_probe(adapter, &dataAddress, &I2cDetectMcuClient);

    return ret;
}

static int I2cDetectMcuClient(struct i2c_adapter *adapter, int address, int kind)
{
    int ret = 0;

    dprintk(1, "Detect I2C client\n");
    dprintk(1, "Detecting mcu client on address 0x%x\n", address << 1);

    /* Check if the adapter supports the needed features */
    if (!i2c_check_functionality(adapter, (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA) ))
    {
        dprintk(1, "Detect client -> ERROR function not supported\n");
        return -ENXIO;
    }

    /* Create the I2C client data structure */
    mcuClient = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
    if (mcuClient == 0)
    {
        return -ENOMEM;
    }
    memset(mcuClient, 0, sizeof(struct i2c_client));
    mcuClient->addr = address;
    mcuClient->adapter = adapter;
    mcuClient->driver = &i2cDriverMcu;
    snprintf(mcuClient->name, (sizeof(mcuClient->name)) - 1, "cvd-mcu");

    /* Attach the MCU to the I2C adapter */
    ret = i2c_attach_client(mcuClient);
    if (ret)
    {
        dprintk(1, "Failed to attach to I2C client on adapter %s (0x%x) - 0x%02X\n",
                adapter->name, adapter->id, ret);

        kfree(mcuClient);
        return -EINVAL;
    }
    dprintk(1, "found device on I2C adapter %s (0x%x) - 0x%02X\n",
            adapter->name, (adapter->id), ret);

    return 0;

}

/* -------------------------------------------------------------------------- */
/* FUNCTION:    I2cWrite                                                      */
/*                                                                            */
/* DESCRIPTION: I2C Write API function.                                       */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t I2cWrite(uint32_t kByteCount, uint8_t *pData)
{
    int32_t        ret = 0;
    struct i2c_msg msg;

    if (mcuClient == NULL)
    {
        dprintk(1, "I2C write -> no I2C bus registered\n");
        ret = -EIO;
        goto I2cWrite_error;
    }

    msg.len = kByteCount;
    msg.buf = (char*)pData;
    msg.addr = (mcuClient->addr);
    msg.flags = 0;
#if 0
    dprintk(1, "msg.len = %d, msg.addr = 0x%02x\n", msg.len, msg.addr);
    dprintk(1, "msg.buf[0] = 0x%02x\n", msg.buf[0]);
    ret = i2c_transfer(mcuClient->adapter, &msg, 1);
    if (ret < 0)
    {
        dprintk(1, "I2C write error (autoincrement mode)\n");
        goto I2cWrite_error;
    }
#else
    ret = i2c_smbus_write_byte_data(mcuClient, 0x18, 0x18);
#endif

    dprintk(1, "I2cWrite data successfully\n");
    return 0;

I2cWrite_error:
    return ret;
}


static void __exit phStbMCU_Exit( void )
{
    dprintk(1, "phStbMCU_Exit\n");
    i2c_del_driver(&i2cDriverMcu);
}

static int __init phStbMCU_Init( void )
{
    int32_t ret;


    dprintk(1, "phStbMCU_Init\n");
    ret = i2c_add_driver(&i2cDriverMcu);
    if (ret == 0)
    {
        dprintk(1, "add i2c driver for cvd mcu\n");
    }

    //test //写standby命令
    {
        uint8_t data[10];

        data[0] = 0x18;

        I2cWrite(1, data);
    }
    return ret;
}



module_init(phStbMCU_Init);
module_exit(phStbMCU_Exit);

你可能感兴趣的:(linux,linux,职场,休闲,i2c)