Linux Kernel 设备驱动之I2C之client描述

    xiaoxiao2021-03-25  152

    前面我们已经了解到i2c的host描述,对于设备来说,其描述较为简单,数据结构实现如下: /**  * struct i2c_client - represent an I2C slave device  * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;  * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking  * @addr: Address used on the I2C bus connected to the parent adapter.  * @name: Indicates the type of the device, usually a chip name that's  * generic enough to hide second-sourcing and compatible revisions.  * @adapter: manages the bus segment hosting this I2C device  * @dev: Driver model device node for the slave.  * @irq: indicates the IRQ generated by this device (if any)  * @detected: member of an i2c_driver.clients list or i2c-core's  * userspace_devices list  * @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter  * calls it to pass on slave events to the slave driver.  *  * An i2c_client identifies a single device (i.e. chip) connected to an  * i2c bus. The behaviour exposed to Linux is defined by the driver  * managing the device.  */ 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; #if IS_ENABLED(CONFIG_I2C_SLAVE)  i2c_slave_cb_t slave_cb; /* callback for slave mode */ #endif }; 显然,对于I2c设备来说,其最主要是提供的i2c地址,这里用addr描述。对于内核驱动模型来说,任何设备都需要内嵌 struct device dev,以能完全跟踪描述设备。   对于一个I2C设备来说,其驱动类型定义如下:  

    /**  * struct i2c_driver - represent an I2C device driver  * @class: What kind of i2c device we instantiate (for detect)  * @attach_adapter: Callback for bus addition (deprecated)  * @probe: Callback for device binding  * @remove: Callback for device unbinding  * @shutdown: Callback for device shutdown  * @alert: Alert callback, for example for the SMBus alert protocol  * @command: Callback for bus-wide signaling (optional)  * @driver: Device driver model driver  * @id_table: List of I2C devices supported by this driver  * @detect: Callback for device detection  * @address_list: The I2C addresses to probe (for detect)  * @clients: List of detected clients we created (for i2c-core use only)  *  * The driver.owner field should be set to the module owner of this driver.  * The driver.name field should be set to the name of this driver.  *  * For automatic device detection, both @detect and @address_list must  * be defined. @class should also be set, otherwise only devices forced  * with module parameters will be created. The detect function must  * fill at least the name field of the i2c_board_info structure it is  * handed upon successful detection, and possibly also the flags field.  *  * If @detect is missing, the driver will still work fine for enumerated  * devices. Detected devices simply won't be supported. This is expected  * for the many I2C/SMBus devices which can't be detected reliably, and  * the ones which can always be enumerated in practice.  *  * The i2c_client structure which is handed to the @detect callback is  * not a real i2c_client. It is initialized just enough so that you can  * call i2c_smbus_read_byte_data and friends on it. Don't do anything  * else with it. In particular, calling dev_dbg and friends on it is  * not allowed.  */ 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 *);

     /* 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").   * For the SMBus Host Notify protocol, the data corresponds to the   * 16-bit payload data reported by the slave device acting as master.   */  void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol,         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; }; 显然,设备驱动是完成对I2C设备的驱动。

    需要注意里面struct device_driver driver的设置,其也是用于满足设备驱动模型要求。

     

    需要注意,一般来说,i2c_client是静态定义或者DTS分析得到的一个内核对象,也就是说其是内核I2C框架层

    分析得到的对象,一般不需要用户直接分配。而I2C设备的驱动则需要静态定义实现,并通过函数

    i2c_register_driver()注册到I2C框架层,此函数对外提供i2c_add_driver().

    #define i2c_add_driver(driver) \  i2c_register_driver(THIS_MODULE, driver)

    /*  * An i2c_driver is used with one or more i2c_client (device) nodes to access  * i2c slave chips, on a bus instance associated with some i2c_adapter.  */

    int i2c_register_driver(struct module *owner, struct i2c_driver *driver) {  int res;

     /* Can't register until after driver model init */  if (unlikely(WARN_ON(!i2c_bus_type.p)))   return -EAGAIN;

     /* add the driver to the list of i2c drivers in the driver core */  driver->driver.owner = owner;设备驱动  driver->driver.bus = &i2c_bus_type;设备驱动所在总线类型

     /* When registration returns, the driver core   * will have called probe() for all matching-but-unbound devices.   */  res = driver_register(&driver->driver);注册设备驱动,设备驱动模型要求  if (res)   return res;

     /* Drivers should switch to dev_pm_ops instead. */  if (driver->suspend)   pr_warn("i2c-core: driver [%s] using legacy suspend method\n",    driver->driver.name);  if (driver->resume)   pr_warn("i2c-core: driver [%s] using legacy resume method\n",    driver->driver.name);

     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

     INIT_LIST_HEAD(&driver->clients);  /* Walk the adapters that are already present */  i2c_for_each_dev(driver, __process_new_driver);驱动开始探测设备,如果有设备,则初始化它。

     return 0; }

    设备驱动定义形式如下:

    static const struct i2c_device_id i2c_slave_eeprom_id[] = {  { "slave-24c02", 2048 / 8 },  { } }; MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);

    static struct i2c_driver i2c_slave_eeprom_driver = {  .driver = {   .name = "i2c-slave-eeprom",  },  .probe = i2c_slave_eeprom_probe,  .remove = i2c_slave_eeprom_remove,  .id_table = i2c_slave_eeprom_id, }; module_i2c_driver(i2c_slave_eeprom_driver);

     

               
    转载请注明原文地址: https://ju.6miu.com/read-11344.html

    最新回复(0)