/** * struct i2c_client - represent an I2C slave device * @flags: see I2C_CLIENT_* for possible flags * @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. * @init_irq: IRQ that was set at initialization * @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. */ structi2c_client { unsignedshort flags; /* div., see below */ #define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ #define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ /* Must equal I2C_M_TEN below */ #define I2C_CLIENT_SLAVE 0x20 /* we are the slave */ #define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */ #define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ #define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */ /* Must match I2C_M_STOP|IGNORE_NAK */
unsignedshort addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ char name[I2C_NAME_SIZE]; structi2c_adapter *adapter;/* the adapter we sit on */ structdevicedev;/* the device structure */ int init_irq; /* irq set at initialization */ int irq; /* irq issued by device */ structlist_headdetected; #if IS_ENABLED(CONFIG_I2C_SLAVE) i2c_slave_cb_t slave_cb; /* callback for slave mode */ #endif };
用C编写I2C Client
一般使用设备树编写I2C Client,不过在引入设备树之前使用C文件也可以
i2c_get_adapter()
i2c_get_adapter 函数的主要作用是根据给定的 I2C 适配器编号 nr 从 i2c_adapter_idr 中查找对应的 i2c_adapter 结构体,该函数定义在drivers/i2c/i2c-core-base.c文件中,具体内容如下所示
/* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ structi2c_adapter { structmodule *owner; unsignedintclass;/* classes to allow probing for */ conststructi2c_algorithm *algo;/* the algorithm to access the bus */ void *algo_data;
/* data fields that are valid for all devices */ conststructi2c_lock_operations *lock_ops; structrt_mutexbus_lock; structrt_mutexmux_lock;
int timeout; /* in jiffies */ int retries; structdevicedev;/* the adapter device */ unsignedlong locked_flags; /* owned by the I2C core */ #define I2C_ALF_IS_SUSPENDED 0 #define I2C_ALF_SUSPEND_REPORTED 1
int nr; char name[48]; structcompletiondev_released;
/** * i2c_new_client_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * * Create an i2c device. Binding is handled through driver model * probe()/remove() methods. A driver may be bound to this device when we * return from this function, or any later moment (e.g. maybe hotplugging will * load the driver module). This call is not appropriate for use by mainboard * initialization logic, which usually runs during an arch_initcall() long * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or an ERR_PTR to describe the error. */ struct i2c_client * i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { structi2c_client *client; int status; // 分配 i2c_client 结构体空间 client = kzalloc(sizeof *client, GFP_KERNEL); if (!client) return ERR_PTR(-ENOMEM); // 设置 i2c_client 的适配器指针 client->adapter = adap; // 从 i2c_board_info 结构体中拷贝相关信息到 i2c_client client->dev.platform_data = info->platform_data; client->flags = info->flags; client->addr = info->addr;
client->init_irq = info->irq; if (!client->init_irq) client->init_irq = i2c_dev_irq_from_resources(info->resources, info->num_resources);
/* * An I2C ID table is not mandatory, if and only if, a suitable OF * or ACPI ID table is supplied for the probing device. */ // 如果 driver 没有 ID 表,且设备也没有匹配的 OF 或 ACPI ID 表,则返回 -ENODEV if (!driver->id_table && !acpi_driver_match_device(dev, dev->driver) && !i2c_of_match_device(dev->driver->of_match_table, client)) { status = -ENODEV; goto put_sync_adapter; }
// 如果 client 需要唤醒功能,则尝试设置唤醒中断 if (client->flags & I2C_CLIENT_WAKE) { int wakeirq;
wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); if (wakeirq == -EPROBE_DEFER) { status = wakeirq; goto put_sync_adapter; } // 启用设备的唤醒功能 device_init_wakeup(&client->dev, true); // 如果获取到了唤醒中断号,且与普通中断号不同,则设置专用唤醒中断 if (wakeirq > 0 && wakeirq != client->irq) status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); elseif (client->irq > 0)// 否则,使用普通中断作为唤醒中断 status = dev_pm_set_wake_irq(dev, client->irq); else status = 0; // 如果设置唤醒中断失败,则输出警告 if (status) dev_warn(&client->dev, "failed to set up wakeup irq\n"); }
dev_dbg(dev, "probe\n"); // 设置设备的时钟默认值 status = of_clk_set_defaults(dev->of_node, false); if (status < 0) goto err_clear_wakeup_irq; // 附加 PM 域 status = dev_pm_domain_attach(&client->dev, true); if (status) goto err_clear_wakeup_irq;
/* * When there are no more users of probe(), * rename probe_new to probe. */ if (driver->probe_new)// 调用 driver 的 probe_new 或 probe 函数 status = driver->probe_new(client); elseif (driver->probe) status = driver->probe(client, i2c_match_id(driver->id_table, client)); else status = -EINVAL;
if (status)// 如果 probe 函数失败,则清除唤醒中断并分离 PM 域 goto err_detach_pm_domain;
// include/linux/i2c.h /** * struct i2c_board_info - template for device creation * @type: chip type, to initialize i2c_client.name * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr * @dev_name: Overrides the default <busnr>-<addr> dev_name if set * @platform_data: stored in i2c_client.dev.platform_data * @of_node: pointer to OpenFirmware device node * @fwnode: device node supplied by the platform firmware * @properties: additional device properties for the device * @resources: resources associated with the device * @num_resources: number of resources in the @resources array * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * a device at a given address. Drivers commonly need more information than * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices * that are present. This information is used to grow the driver model tree. * For mainboards this is done statically using i2c_register_board_info(); * bus numbers identify adapters that aren't yet available. For add-on boards, * i2c_new_client_device() does this dynamically with the adapter already known. */ structi2c_board_info { char type[I2C_NAME_SIZE];// I2C 设备的类型名称,最大长度为 I2C_NAME_SIZE unsignedshort flags;// I2C 设备的标志位,用于指定设备的特殊属性 unsignedshort addr;// I2C 设备的地址 constchar *dev_name;// I2C 设备的设备名称 void *platform_data;// I2C 设备的平台数据,可为 NUL structdevice_node *of_node;// I2C 设备节点在设备树中的节点指针 structfwnode_handle *fwnode;// I2C 设备节点在 ACPI 中的 fwnode 句柄 conststructproperty_entry *properties;// I2C 设备的属性列表 conststructresource *resources;// I2C 设备使用的资源列表 unsignedint num_resources;// I2C 设备使用的资源数量 int irq; };
// include/linux/i2c.h /** * i2c_master_recv - issue a single I2C message in master receive mode * @client: Handle to slave device * @buf: Where to store data read from slave * @count: How many bytes to read, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes read. */ staticinlineinti2c_master_recv(conststruct i2c_client *client, char *buf, int count) { return i2c_transfer_buffer_flags(client, buf, count, I2C_M_RD); };
i2c_master_send()
1 2 3 4 5 6 7 8 9 10 11 12 13
/** * i2c_master_send - issue a single I2C message in master transmit mode * @client: Handle to slave device * @buf: Data that will be written to the slave * @count: How many bytes to write, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes written. */ staticinlineinti2c_master_send(conststruct i2c_client *client, constchar *buf, int count) { return i2c_transfer_buffer_flags(client, (char *)buf, count, 0); };
// drivers/i2c/i2c-core-base.c /** * i2c_transfer_buffer_flags - issue a single I2C message transferring data * to/from a buffer * @client: Handle to slave device * @buf: Where the data is stored * @count: How many bytes to transfer, must be less than 64k since msg.len is u16 * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads * * Returns negative errno, or else the number of bytes transferred. */ inti2c_transfer_buffer_flags(conststruct i2c_client *client, char *buf, int count, u16 flags) { int ret; // 构建 i2c_msg 结构体,描述本次传输操作 structi2c_msgmsg = { .addr = client->addr, // 设置从设备地址 .flags = flags | (client->flags & I2C_M_TEN),// 设置传输标志位,包括用户传入的标志位和客户端对象自身的标志位 .len = count,// 设置传输数据长度 .buf = buf,// 设置数据缓冲区 }; // 调用 i2c_transfer 函数进行数据传输 // 该函数会根据传输的消息数量返回实际传输成功的消息数量 ret = i2c_transfer(client->adapter, &msg, 1);
/* * If everything went ok (i.e. 1 msg transferred), return #bytes * transferred, else error code. */ return (ret == 1) ? count : ret; } EXPORT_SYMBOL(i2c_transfer_buffer_flags);
/** * i2c_transfer - execute a single or combined I2C message * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. * * Returns negative errno, else the number of messages executed. * * Note that there is no requirement that each message be sent to * the same slave address, although that is the most common model. */ inti2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { int ret;
if (!adap->algo->master_xfer) {// 如果适配器不支持 master_xfer 操作,直接返回错误 dev_dbg(&adap->dev, "I2C level transfers not supported\n"); return -EOPNOTSUPP; }
/* REVISIT the fault reporting model here is weak: * * - When we get an error after receiving N bytes from a slave, * there is no way to report "N". * * - When we get a NAK after transmitting N bytes to a slave, * there is no way to report "N" ... or to let the master * continue executing the rest of this combined message, if * that's the appropriate response. * * - When for example "num" is two and we successfully complete * the first message but get an error part way through the * second, it's unclear whether that should be reported as * one (discarding status on the second message) or errno * (discarding status on the first one). */ ret = __i2c_lock_bus_helper(adap); if (ret) return ret; // 调用__i2c_transfer 执行实际的消息传输 ret = __i2c_transfer(adap, msgs, num); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);// 解锁 I2C 总线
// include/uapi/linux/i2c.h /** * struct i2c_msg - an I2C transaction segment beginning with START * @addr: Slave address, either seven or ten bits. When this is a ten * bit address, I2C_M_TEN must be set in @flags and the adapter * must support I2C_FUNC_10BIT_ADDR. * @flags: I2C_M_RD is handled by all adapters. No other flags may be * provided unless the adapter exported the relevant I2C_FUNC_* * flags through i2c_check_functionality(). * @len: Number of data bytes in @buf being read from or written to the * I2C slave address. For read transactions where I2C_M_RECV_LEN * is set, the caller guarantees that this buffer can hold up to * 32 bytes in addition to the initial length byte sent by the * slave (plus, if used, the SMBus PEC); and this value will be * incremented by the number of block data bytes received. * @buf: The buffer into which data is read, or from which it's written. * * An i2c_msg is the low level representation of one segment of an I2C * transaction. It is visible to drivers in the @i2c_transfer() procedure, * to userspace from i2c-dev, and to I2C adapter drivers through the * @i2c_adapter.@master_xfer() method. * * Except when I2C "protocol mangling" is used, all I2C adapters implement * the standard rules for I2C transactions. Each transaction begins with a * START. That is followed by the slave address, and a bit encoding read * versus write. Then follow all the data bytes, possibly including a byte * with SMBus PEC. The transfer terminates with a NAK, or when all those * bytes have been transferred and ACKed. If this is the last message in a * group, it is followed by a STOP. Otherwise it is followed by the next * @i2c_msg transaction segment, beginning with a (repeated) START. * * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then * passing certain @flags may have changed those standard protocol behaviors. * Those flags are only for use with broken/nonconforming slaves, and with * adapters which are known to support the specific mangling options they * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR). */ structi2c_msg { __u16 addr; /* slave address */ __u16 flags; #define I2C_M_RD 0x0001 /* read data, from slave to master */ /* I2C_M_RD is guaranteed to be 0x0001! */ #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */ /* makes only sense in kernelspace */ /* userspace buffers are copied anyway */ #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ #define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ };
/** * struct i2c_algorithm - represent I2C transfer method * @master_xfer: Issue a set of i2c transactions to the given I2C adapter * defined by the msgs array, with num messages available to transfer via * the adapter specified by adap. * @master_xfer_atomic: same as @master_xfer. Yet, only using atomic context * so e.g. PMICs can be accessed very late before shutdown. Optional. * @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this * is not present, then the bus layer will try and convert the SMBus calls * into I2C transfers instead. * @smbus_xfer_atomic: same as @smbus_xfer. Yet, only using atomic context * so e.g. PMICs can be accessed very late before shutdown. Optional. * @functionality: Return the flags that this algorithm/adapter pair supports * from the ``I2C_FUNC_*`` flags. * @reg_slave: Register given client to I2C slave mode of this adapter * @unreg_slave: Unregister given client from I2C slave mode of this adapter * * The following structs are for those who like to implement new bus drivers: * i2c_algorithm is the interface to a class of hardware solutions which can * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 * to name two of the most common. * * The return codes from the ``master_xfer{_atomic}`` fields should indicate the * type of error code that occurred during the transfer, as documented in the * Kernel Documentation file Documentation/i2c/fault-codes.rst. */ structi2c_algorithm { /* * If an adapter algorithm can't do I2C-level access, set master_xfer * to NULL. If an adapter algorithm can do SMBus access, set * smbus_xfer. If set to NULL, the SMBus protocol is simulated * using common I2C messages. * * master_xfer should return the number of messages successfully * processed, or a negative value on error */ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*master_xfer_atomic)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsignedshort flags, char read_write, u8 command, int size, union i2c_smbus_data *data); int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr, unsignedshort flags, char read_write, u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */ u32 (*functionality)(struct i2c_adapter *adap);
#if IS_ENABLED(CONFIG_I2C_SLAVE) int (*reg_slave)(struct i2c_client *client); int (*unreg_slave)(struct i2c_client *client); #endif };
/* * We only allow atomic transfers for very late communication, e.g. to access a * PMIC when powering down. Atomic transfers are a corner case and not for * generic use! */ staticinlinebooli2c_in_atomic_xfer_mode(void) { return system_state > SYSTEM_RUNNING && irqs_disabled(); }
staticinlineint __i2c_lock_bus_helper(struct i2c_adapter *adap) { int ret = 0;
if (i2c_in_atomic_xfer_mode()) { WARN(!adap->algo->master_xfer_atomic && !adap->algo->smbus_xfer_atomic, "No atomic I2C transfer handler for '%s'\n", dev_name(&adap->dev)); ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT) ? 0 : -EAGAIN; } else { i2c_lock_bus(adap, I2C_LOCK_SEGMENT); }
/** * __i2c_transfer - unlocked flavor of i2c_transfer * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. * * Returns negative errno, else the number of messages executed. * * Adapter lock must be held when calling this function. No debug logging * takes place. adap->algo->master_xfer existence isn't checked. */ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { unsignedlong orig_jiffies;// 记录初始的 jiffies 值 int ret, try;// 返回值和重试次数 // 如果 msgs 为空或 num 小于 1,返回无效参数错误 if (WARN_ON(!msgs || num < 1)) return -EINVAL;
ret = __i2c_check_suspended(adap); if (ret) return ret; // 如果适配器有特殊需求,检查是否支持当前的 I2C 消息 if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP;
/* * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed. */ /* * 如果启用了 i2c_trace_msg_key 这个分支点(用于跟踪 I2C 传输消息), * 则遍历所有消息,分别记录读操作和写操作的跟踪信息 */ if (static_branch_unlikely(&i2c_trace_msg_key)) { int i; for (i = 0; i < num; i++) if (msgs[i].flags & I2C_M_RD) trace_i2c_read(adap, &msgs[i], i); else trace_i2c_write(adap, &msgs[i], i); }
/* Retry automatically on arbitration loss */// 自动重试仲裁丢失错误 orig_jiffies = jiffies; for (ret = 0, try = 0; try <= adap->retries; try++) { // 调用适配器的 master_xfer 函数完成 I2C 传输 if (i2c_in_atomic_xfer_mode() && adap->algo->master_xfer_atomic) ret = adap->algo->master_xfer_atomic(adap, msgs, num); else ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)// 如果不是仲裁丢失错误,退出循环 break; if (time_after(jiffies, orig_jiffies + adap->timeout))// 如果超时,退出循环 break; } // 如果启用了 i2c_trace_msg_key 这个分支点,记录 I2C 传输的结果 if (static_branch_unlikely(&i2c_trace_msg_key)) { int i; for (i = 0; i < ret; i++) if (msgs[i].flags & I2C_M_RD) trace_i2c_reply(adap, &msgs[i], i); trace_i2c_result(adap, num, ret); }
// include/linux/i2c.h /* use a define to avoid include chaining to get THIS_MODULE */ #define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver)
// drivers/i2c/i2c-core-base.c /* * 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. */
inti2c_register_driver(struct module *owner, struct i2c_driver *driver) { int res;
/* Can't register until after driver model init */ if (WARN_ON(!is_registered)) 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; INIT_LIST_HEAD(&driver->clients);
/* 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;
// include/linux/i2c.h /** * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) * @probe: Callback for device binding - soon to be deprecated * @probe_new: New 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. */ structi2c_driver { unsignedintclass;// 驱动程序所属的设备类型
/* Standard driver model interfaces */ int (*probe)(struct i2c_client *client, conststruct i2c_device_id *id);// 探测并绑定设备的回调函数 int (*remove)(struct i2c_client *client);// 从设备上解绑驱动程序的回调函数
/* New driver model interface to aid the seamless removal of the * current probe()'s, more commonly unused than used second parameter. */ int (*probe_new)(struct i2c_client *client);// 新的探测设备并绑定的回调函数
/* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *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 *client, enum i2c_alert_protocol protocol, unsignedint data);// 设备报警时调用的回调函数,格式和含义取决于所使用的协议
/* a ioctl like command that can be used to perform specific functions * with the device. */ int (*command)(struct i2c_client *client, unsignedint cmd, void *arg);
structdevice_driverdriver;// 设备驱动程序基础结构 conststructi2c_device_id *id_table;// 与该驱动程序匹配的设备 ID 表
/* /dev/i2c-X ioctl commands. The ioctl's parameter is always an * unsigned long, except for: * - I2C_FUNCS, takes pointer to an unsigned long * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data */ //设置重试次数,即当从设备没有响应时要重新轮询的次数 #define I2C_RETRIES 0x0701 /* number of times a device address should be polled when not acknowledging */ //设置超时时间,单位为 10 毫秒 #define I2C_TIMEOUT 0x0702 /* set timeout in units of 10 ms */
/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses * are NOT supported! (due to code brokenness) */ //使用此从机地址 #define I2C_SLAVE 0x0703 /* Use this slave address */ //强制使用此从机地址 #define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it is already in use by a driver! */ //0 表示 7 位地址, 非 0 表示 10 位地址 #define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ //获取适配器功能掩码 #define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ //执行合并读写传输(只有一个 STOP 信号) #define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */ //使用 PEC(校验码)进行 SMBus 传输 #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ //执行 SMBus 传输 #define I2C_SMBUS 0x0720 /* SMBus transfer */
/* This is the structure as used in the I2C_SMBUS ioctl call */ structi2c_smbus_ioctl_data { __u8 read_write; __u8 command; __u32 size; unioni2c_smbus_data __user *data; };
/* This is the structure as used in the I2C_RDWR ioctl call */ structi2c_rdwr_ioctl_data { structi2c_msg __user *msgs;/* pointers to i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */ };
#define I2C_RDWR_IOCTL_MAX_MSGS 42 /* Originally defined with a typo, keep it for compatibility */ #define I2C_RDRW_IOCTL_MAX_MSGS I2C_RDWR_IOCTL_MAX_MSGS
staticint __init i2c_dev_init(void) { int res; // 打印内核日志,表示 i2c /dev 条目驱动已经初始化 printk(KERN_INFO "i2c /dev entries driver\n"); // 注册字符设备驱动,主设备号为 I2C_MAJOR,次设备号范围为 0 到 I2C_MINORS-1,设备名为"i2c" res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c"); if (res) goto out; // 创建一个 class 对象,名称为 "i2c-dev",用于在用户空间创建设备节点 i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); if (IS_ERR(i2c_dev_class)) { res = PTR_ERR(i2c_dev_class); goto out_unreg_chrdev; } // 将 i2c_groups 数组设置为该 class 的 dev_groups 属性 i2c_dev_class->dev_groups = i2c_groups;
/* Keep track of adapters which will be added or removed later */ // 注册一个总线通知函数 i2cdev_notifier,用于追踪 i2c 总线上新添加或删除的适配器 res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res) goto out_unreg_class;
/* Bind to already existing adapters right away */ // 立即绑定已经存在的 i2c 适配器到 i2c 设备 i2c_for_each_dev(NULL, i2cdev_attach_adapter);
/* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. * * This client is ** NEVER REGISTERED ** with the driver model * or I2C core code!! It just holds private copies of addressing * information and maybe a PEC flag. */ client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) {// 如果内存分配失败,释放 i2c_adapter 并返回 -ENOMEM 错误 i2c_put_adapter(adap); return -ENOMEM; } // 设置 i2c_client 的名称 snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
/* * After opening an instance of this character special file, a file * descriptor starts out associated only with an i2c_adapter (and bus). * * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg * traffic to any devices on the bus used by that adapter. That's because * the i2c_msg vectors embed all the addressing information they need, and * are submitted directly to an i2c_adapter. However, SMBus-only adapters * don't support that interface. * * To use read()/write() system calls on that file descriptor, or to use * SMBus interfaces (and work with SMBus-only hosts!), you must first issue * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous * (never registered) i2c_client so it holds the addressing information * needed by those system calls and by this SMBus interface. */
case I2C_SMBUS: {// 处理 I2C_SMBUS 命令 structi2c_smbus_ioctl_datadata_arg; if (copy_from_user(&data_arg, (struct i2c_smbus_ioctl_data __user *) arg, sizeof(struct i2c_smbus_ioctl_data))) return -EFAULT; return i2cdev_ioctl_smbus(client, data_arg.read_write, data_arg.command, data_arg.size, data_arg.data); } case I2C_RETRIES:// 设置 i2c 适配器的重试次数 if (arg > INT_MAX) return -EINVAL;
client->adapter->retries = arg; break; case I2C_TIMEOUT:// 设置 i2c 适配器的超时时间 if (arg > INT_MAX) return -EINVAL;
/* For historical reasons, user-space sets the timeout * value in units of 10 ms. */ // 用户空间设置的单位是 10 ms client->adapter->timeout = msecs_to_jiffies(arg * 10); break; default:// 不支持的 ioctl 命令 /* NOTE: returning a fault code here could cause trouble * in buggy userspace code. Some old kernel bugs returned * zero in this case, and userspace code might accidentally * have depended on that bug. */ return -ENOTTY; } return0; }
/** * struct i2c_algorithm - represent I2C transfer method * @master_xfer: Issue a set of i2c transactions to the given I2C adapter * defined by the msgs array, with num messages available to transfer via * the adapter specified by adap. * @master_xfer_atomic: same as @master_xfer. Yet, only using atomic context * so e.g. PMICs can be accessed very late before shutdown. Optional. * @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this * is not present, then the bus layer will try and convert the SMBus calls * into I2C transfers instead. * @smbus_xfer_atomic: same as @smbus_xfer. Yet, only using atomic context * so e.g. PMICs can be accessed very late before shutdown. Optional. * @functionality: Return the flags that this algorithm/adapter pair supports * from the ``I2C_FUNC_*`` flags. * @reg_slave: Register given client to I2C slave mode of this adapter * @unreg_slave: Unregister given client from I2C slave mode of this adapter * * The following structs are for those who like to implement new bus drivers: * i2c_algorithm is the interface to a class of hardware solutions which can * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 * to name two of the most common. * * The return codes from the ``master_xfer{_atomic}`` fields should indicate the * type of error code that occurred during the transfer, as documented in the * Kernel Documentation file Documentation/i2c/fault-codes.rst. */ structi2c_algorithm { /* * If an adapter algorithm can't do I2C-level access, set master_xfer * to NULL. If an adapter algorithm can do SMBus access, set * smbus_xfer. If set to NULL, the SMBus protocol is simulated * using common I2C messages. * * master_xfer should return the number of messages successfully * processed, or a negative value on error */ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*master_xfer_atomic)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsignedshort flags, char read_write, u8 command, int size, union i2c_smbus_data *data); int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr, unsignedshort flags, char read_write, u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */ u32 (*functionality)(struct i2c_adapter *adap);
#if IS_ENABLED(CONFIG_I2C_SLAVE) int (*reg_slave)(struct i2c_client *client); int (*unreg_slave)(struct i2c_client *client); #endif };