×î½üÒòΪ¹¤×÷ÐèÒªÉæ¼°µ½ÁËI2C×ÜÏß¡£ËäÈ»ÎÒ¹ýÈ¥ÓùýI2c£¬µ«¿´ÁË Linux kernel ºó²Å·¢ÏÖ£¬Ò»¸ö layer Äܱ»×öµ½ÕâÑùÍêÉÆ¡£
1.LinuxµÄI2CÇý¶¯¼Ü
LinuxÖÐI2C×ÜÏßµÄÇý¶¯·ÖΪÁ½¸ö²¿·Ö£¬×ÜÏßÇý¶¯£¨BUS£©ºÍÉ豸Çý¶¯£¨DEVICE£©¡£ÆäÖÐ×ÜÏßÇý¶¯µÄÖ°Ôð£¬ÊÇΪϵͳÖÐÿ¸öI2C×ÜÏßÔö¼ÓÏàÓ¦µÄ¶Áд·½·¨¡£µ«ÊÇ×ÜÏßÇý¶¯±¾Éí²¢²»»á½øÐÐÈκεÄͨѶ£¬ËüÖ»ÊÇ´æÔÚÔÚÄÇÀµÈ´ýÉ豸Çý¶¯µ÷ÓÃÆ亯Êý¡£
É豸Çý¶¯ÔòÊÇÓë¹ÒÔÚI2C×ÜÏßÉϵľßÌåµÄÉ豸ͨѶµÄÇý¶¯¡£Í¨¹ýI2C×ÜÏßÇý¶¯ÌṩµÄº¯Êý£¬É豸Çý¶¯¿ÉÒÔºöÂÔ²»Í¬×ÜÏß¿ØÖÆÆ÷µÄ²îÒ죬²»¿¼ÂÇÆäʵÏÖϸ½ÚµØÓëÓ²¼þÉ豸ͨѶ¡£
1.1. ×ÜÏßÇý¶¯
ÔÚϵͳ¿ª»úʱ£¬Ê×ÏÈ×°ÔصÄÊÇI2C×ÜÏßÇý¶¯¡£Ò»¸ö×ÜÏßÇý¶¯ÓÃÓÚÖ§³ÖÒ»ÌõÌض¨µÄI2C×ÜÏߵĶÁд¡£Ò»¸ö×ÜÏßÇý¶¯Í¨³£ÐèÒªÁ½¸öÄ£¿é£¬Ò»¸östruct i2c_adapterºÍÒ»¸östruct i2c_algorithmÀ´ÃèÊö£º
static struct i2c_adapter pb1550_board_adapter =
{
name: "pb1550 adapter",
id: I2C_HW_AU1550_PSC,
algo: NULL,
algo_data: &pb1550_i2c_info,
inc_use: pb1550_inc_use,
dec_use: pb1550_dec_use,
client_register: pb1550_reg,
client_unregister: pb1550_unreg,
client_count: 0,
};
Õâ¸öÑùÀý¹Ò½ÓÁËÒ»¸ö½Ð×ö¡°pb1550 adapter¡±µÄÇý¶¯¡£µ«Õâ¸öÄ£¿é²¢Î´Ìṩ¶Áдº¯Êý£¬¾ßÌåµÄ¶Áд·½·¨Óɵڶþ¸öÄ£¿é£¬struct i2c_algorithmÌṩ¡£
static struct i2c_algorithm au1550_algo =
{
¡¡.name = "Au1550 algorithm",
¡¡.id = I2C_ALGO_AU1550,
¡¡.master_xfer = au1550_xfer,
¡¡.functionality = au1550_func,
};
i2c_adap->algo = &au1550_algo;
Õâ¸öÑùÀý¸øÉÏÊö×ÜÏßÇý¶¯Ôö¼ÓÁ˶Áд¡°Ëã·¨¡±¡£Í¨³£Çé¿öÏÂÿ¸öI2C×ÜÏßÇý¶¯¶¼¶¨ÒåÒ»¸ö×Ô¼ºµÄ¶ÁдËã·¨£¬µ«¼øÓÚÓÐЩ×ÜÏßʹÓÃÏàͬµÄËã·¨£¬Òò¶ø¿ÉÒÔ¹²ÓÃͬһÌ׶Áдº¯Êý¡£±¾ÀýÖеÄÇý¶¯¶¨ÒåÁË×Ô¼ºµÄ¶ÁдË㷨ģ¿é£¬ÆðÃû½Ð¡°Au1550 algorithm¡±¡£
È«²¿ÌîÍ׺ó£¬Í¨¹ýµ÷Óãº
i2c_add_adapter(i2c_adap);
½«ÕâÁ½¸öÄ£¿é×¢²áµ½²Ù×÷ϵͳÀ×ÜÏßÇý¶¯¾ÍËã×°ÉÏÁË¡£¶ÔÓÚAMD au1550£¬Õⲿ·ÖÒѾÓÉAMDÌṩÁË¡£
1.2 É豸Çý¶¯
ÈçÇ°ËùÊö£¬×ÜÏßÇý¶¯Ö»ÊÇÌṩÁ˶ÔÒ»Ìõ×ÜÏߵĶÁд»úÖÆ£¬±¾Éí²¢²»»áÈ¥×öͨÐÅ¡£Í¨ÐÅÊÇÓÉI2CÉ豸Çý¶¯À´×öµÄ£¬É豸Çý¶¯Í¸¹ýI2C×ÜÏßͬ¾ßÌåµÄÉ豸½øÐÐͨѶ¡£Ò»¸öÉ豸Çý¶¯ÓÐÁ½¸öÄ£¿éÀ´ÃèÊö£¬struct i2c_driverºÍstruct i2c_client¡£
µ±ÏµÍ³¿ª»ú¡¢I2C×ÜÏßÇý¶¯×°ÈëÍê³Éºó£¬¾Í¿ÉÒÔ×°ÈëÉ豸Çý¶¯ÁË¡£Ê×ÏÈ×°ÈëÈçϽṹ£º
static struct i2c_driver driver =
{
.name = "i2c TV tuner driver",
.id = I2C_DRIVERID_TUNER,
.flags = I2C_DF_NOTIFY,
.attach_adapter = tuner_probe,
.detach_client = tuner_detach,
.command = tuner_command,
};
i2c_add_driver(&driver);
Õâ¸öi2c_driverÒ»µ©×°ÈëÍê³É£¬ÆäÖеÄattach_adapterº¯Êý¾Í»á±»µ÷Óá£ÔÚÆäÖпÉÒÔ±éÀúϵͳÖеÄÿ¸öi2c×ÜÏßÇý¶¯£¬Ì½²âÏëÒª·ÃÎʵÄÉ豸£º
static int tuner_probe(struct i2c_adapter *adap)
{
¡¡return i2c_probe(adap, &addr_data, tuner_attach);
}
×¢Òâ̽²â¿ÉÄÜ»áÕÒµ½¶à¸öÉ豸£¬Òò¶ø²»½öÒ»¸öI2C×ÜÏß¿ÉÒÔ¹Ò¶à¸ö²»Í¬ÀàÐ͵ÄÉ豸£¬Ò»¸öÉ豸Çý¶¯Ò²¿ÉÒÔͬʱΪ¹ÒÔÚ¶à¸ö²»Í¬I2C×ÜÏßÉϵÄÉ豸·þÎñ¡£
ÿµ±É豸Çý¶¯Ì½²âµ½ÁËÒ»¸öËüÄÜÖ§³ÖµÄÉ豸£¬Ëü¾Í´´½¨Ò»¸östruct i2c_clientÀ´±êʶÕâ¸öÉ豸£º
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &driver;
/* Tell the I2C layer a new client has arrived */
err = i2c_attach_client(new_client);
if (err)
goto error;
¿É¼û£¬Ò»¸öi2c_client´ú±í×ÅλÓÚadapter×ÜÏßÉÏ£¬µØַΪaddress£¬Ê¹ÓÃdriverÀ´Çý¶¯µÄÒ»¸öÉ豸¡£Ëü½«×ÜÏßÇý¶¯ÓëÉ豸Çý¶¯£¬ÒÔ¼°É豸µØÖ·°ó¶¨ÔÚÁËÒ»Æð¡£Ò»¸öi2c_client¾Í´ú±í×ÅÒ»¸öI2CÉ豸¡£
µ±µÃµ½I2CÉ豸ºó£¬¾Í¿ÉÒÔÖ±½Ó¶Ô´ËÉ豸½øÐжÁд£º
/*
* The master routines are the ones normally used to transmit data to devices
* on a bus (or read from them). Apart from two basic transfer functions to
* transmit one message at a time, a more complex version can be used to
* transmit an arbitrary number of messages without interruption.
*/
extern int i2c_master_send(struct i2c_client *,const char* ,int);
extern int i2c_master_recv(struct i2c_client *,char* ,int);
Óëͨ³£ÒâÒåÉϵĶÁдº¯ÊýÒ»Ñù£¬ÕâÁ½¸öº¯Êý¶Ôi2c_clientÖ¸ÕëÖ¸¶¨µÄÉ豸£¬¶Áдint¸öchar¡£·µ»ØֵΪ¶ÁдµÄ×Ö½ÚÊý¡£¶ÔÓÚÎÒÃÇÏÖÓеÄSLICµÄÇý¶¯£¬Ö»Òª½«×îºóÒªÍù×ÜÏßÉϽøÐжÁдµÄÊý¾ÝÒý³ö´«Êäµ½ÕâÁ½¸öº¯ÊýÖУ¬ÒÆÖ²¹¤×÷¾ÍËãÍê³ÉÁË£¬ÎÒÃǽ«µÃµ½Ò»¸öLinux°æµÄI2CÉ豸Çý¶¯¡£