linux设备驱动
http://blog.csdn.net/bob_fly1984/article/details/8820670
struct ov5640_data {
struct ov5640_platform_data chip;
bool use_smbus;
/*
* Lock protects against activities from other Linux tasks,
* but not from changes by other I2C masters.
*/
struct mutex lock;
struct bin_attribute bin;
u8 *writebuf;
unsigned write_max;
unsigned num_addresses;
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls.
*/
struct i2c_client *client[];
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static struct ov5640_platform_data ov5640_chip_info;
static struct i2c_board_info ov5640_i2c_board_info __initdata ={
.type = CONFIG_OV5640_TYPE,
.addr = CONFIG_OV5640_DEVICE_ADDR,
};
static void __init i2c_board_init(void)
{
int i;
for (i = 0; i < sizeof(ov5640_list) / sizeof(struct ov5640_info); i++) {
if (strcmp(ov5640_i2c_board_info.type, ov5640_list[i].name) == 0) {
ov5640_chip_info.byte_len = ov5640_list[i].byte_len;
ov5640_chip_info.page_size = ov5640_list[i].page_size;
ov5640_chip_info.flags = ov5640_list[i].flags;
ov5640_i2c_board_info.platform_data = &ov5640_chip_info;
break;
}
}
i2c_register_board_info(CONFIG_OV5640_I2C_BUS_NUM, &ov5640_i2c_board_info, 1);
}
这一堆是一个从设备client dev的注册
一个从设备的属性,注册通过
i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
struct i2c_board_info {
char type[I2C_NAME_SIZE];/×相当于设备名用于区分×/
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
struct acpi_dev_node acpi_node;
int irq;
};
自定义一个结构体
struct ov5640_info {
char *name;
unsigned int byte_len; /* size (sum of all addr) */
unsigned short page_size; /* for writes */
unsigned char flags;
};
定义一个结构体数组
static const struct ov5640_info ov5640_list[] = {
{ "OV5640", 128 / 8, 1, ov5640_FLAG_TAKE8ADDR },
{ NULL, 0, 0, 0 } /* END OF LIST */
};
相当于busnum,几路i2c
定义一个结构体存储用户数据
struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
u8 flags;
#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
void (*setup)(struct memory_accessor *, void *context);
void *context;
};
static struct ov5640_platform_data ov5640_chip_info;
static struct i2c_board_info ov5640_i2c_board_info __initdata ={
.type = CONFIG_OV5640_TYPE,
.addr = CONFIG_OV5640_DEVICE_ADDR,
};
static void __init i2c_board_init(void)
{
int i;
for (i = 0; i < sizeof(ov5640_list) / sizeof(struct ov5640_info); i++) {
if (strcmp(ov5640_i2c_board_info.type, ov5640_list[i].name) == 0) {
ov5640_chip_info.byte_len = ov5640_list[i].byte_len;
ov5640_chip_info.page_size = ov5640_list[i].page_size;
ov5640_chip_info.flags = ov5640_list[i].flags;
ov5640_i2c_board_info.platform_data = &ov5640_chip_info;
break;
}
}
i2c_register_board_info(CONFIG_OV5640_I2C_BUS_NUM, &ov5640_i2c_board_info, 1);
}
将定义的platform_data注册进去
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static const struct i2c_device_id ov5640_ids[] = {
{ "OV5640", 0 },
};
MODULE_DEVICE_TABLE(i2c, ov5640_ids);
static struct i2c_driver ov5640_driver = {
.driver = {
.name = "OV5640",
.owner = THIS_MODULE,
},
.probe = ov5640_probe,
.remove = __devexit_p(ov5640_remove),
.id_table = ov5640_ids,
};
i2c_driver模型
struct i2c_driver {
unsigned int class;
/* Notifies the driver that a new bus has appeared. You should avoid
* using this, it will be removed in a near future.
*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated;
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
*/
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
struct i2c_client {
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
static int __init ov5640_init(void)
{
io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&ov5640_driver);
}
module_init(ov5640_init);
static void __exit ov5640_exit(void)
{
i2c_del_driver(&ov5640_driver);
}
module_exit(ov5640_exit);
/* eeprom device private list */