客户加了一个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);