Читайте полезные статьи впервые
1
Ядро Linux делит драйвер I2C на две части:
Несколько важных членов в рамках I2C
1. Шина I2C
Структура шины I2C определена в файле driver\i2c\i2c-core.c следующим образом:
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
};
Шина I2C соответствует шине в каталоге /bus. Эта структура шины i2c управляет сопоставлением, удалением и другими операциями устройства i2c и драйвера I2C. Шина I2C вызывает функцию i2c_device_match, чтобы проверить, совпадают ли устройство I2C и драйвер I2C. Если они совпадают, он вызывает функцию i2c_device_probe, а затем вызывает функцию проверки драйвера I2C.
Форма как:
i2c_device_match будет управлять правилами сопоставления устройств I2C и шины I2C, которые будут тесно связаны с написанием драйверов I2C.
2. Драйвер I2C
i2c_driver аналогичен Platform_driver и используется для написания драйверов устройств I2C. Структура i2c_driver определена в файле include/linux/i2c.h и имеет следующее содержимое:
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").
*/
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;
};
Ключевые члены:
int (*probe)(struct i2c_client *, const struct i2c_device_id *)
Когда устройство I2C и драйвер успешно сопоставлены, функция зонда будет выполнена.
struct device_driver driver device_driver
Для структуры драйвера, если вы используете дерево устройств, вам необходимо установить переменную-член of_match_table для устройства_драйвер, которая является совместимым атрибутом драйвера.
const struct i2c_device_id *id_table
id_table — традиционная таблица идентификаторов соответствия устройств, которая не использует дерево устройств.
3. I2C-устройства
Структура устройства I2C Структура i2c_client определена в файле include/linux/i2c.h и имеет следующее содержимое:
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_client Каждый раз, когда обнаруживается устройство I2C, этому устройству I2C назначается i2c_client.
4. Адаптер I2C
После приведенного выше введения мы знаем, что существуют драйверы I2C и устройства I2C. Нам необходимо взаимодействовать с устройствами I2C через драйвер I2C, для которого требуется адаптер I2C. Адаптер I2C соответствует контроллеру I2C на SOC.
Ядро Linux абстрагирует адаптер I2C (контроллер) SOC в i2c_adapter. Структура i2c_adapter определяется в файле include/linux/i2c.h. Содержимое структуры следующее:
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
*/
struct i2c_adapter {
struct module *owner;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access the bus *//* Алгоритм доступа к шине */
void *algo_data;
/* data fields that are valid for all devices */
struct rt_mutex bus_lock;
int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */
int nr;
char name[48];
struct completion dev_released;
struct mutex userspace_clients_lock;
struct list_head userspace_clients;
struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
};
Ключевые члены:
const struct i2c_algorithm *algo
Метод, с помощью которого адаптер I2C взаимодействует с устройством IIC.
Структура i2c_algorithm определена в файле include/linux/i2c.h и имеет следующее содержимое:
struct i2c_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 (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
#endif
};
Ключевые члены:
Основная задача драйвера адаптера I2C — инициализировать структурную переменную i2c_adapter, а затем установить функцию master_xfer в i2c_algorithm. После завершения зарегистрируйте набор i2c_adapter в системе с помощью двух функций i2c_add_numbered_adapter или i2c_add_adapter.
Разница между этими двумя функциями заключается в том, что i2c_add_adapter использует динамический номер шины, а i2c_add_numbered_adapter использует статический номер шины.
5. Резюме
Драйвер I2C имеет четыре важные вещи: шина I2C, драйвер I2C, устройство I2C и устройство I2C.
Механизм работы шины Linux I2C:
Простой процесс написания драйвера I2C
Как правило, драйверы шины I2C SOC написаны производителями полупроводников, и пользователям не нужно это писать. Таким образом, драйвер шины I2C защищен для пользователей SOC, и нам нужно сосредоточиться только на драйвере устройства I2C. Если вы не работаете в полупроводниковой компании, ваша работа — писать драйверы адаптера I2C.
i2c_driver аналогичен Platform_driver. Он предназначен для написания драйверов устройств I2C. Конкретное содержимое структуры i2c_driver было представлено выше.
Для нас, разработчиков драйверов устройств I2C, ключевой задачей является сборка i2c_driver. После завершения построения нам необходимо зарегистрировать этот i2c_driver в ядре Linux.
Итак, как зарегистрироваться?
Используйте эту функцию ниже:
int i2c_register_driver(struct module *owner,struct i2c_driver *driver)
Значения параметров функции и возвращаемых значений следующие:
Кроме того, i2c_add_driver часто используется для регистрации i2c_driver — это макроса, определяемого следующим образом:
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
i2c_add_driver — это простая инкапсуляция i2c_register_driver только с одним параметром — регистрируемым i2c_driver.
При управлении устройством необходимо отменить регистрацию ранее зарегистрированного i2c_driver в ядре Linux. Необходимо использовать функцию i2c_del_driver. Прототип этой функции следующий:
void i2c_del_driver(struct i2c_driver *driver);
Значения параметров функции и возвращаемых значений следующие:
Регулярные рамки:
/* i2c водитель probe функция */
static int xxx_probe(struct i2c_client *client,
{
/* Функция Специальные процедуры */
return 0;
}
/* i2c водитель remove функция */
static int xxx_remove(struct i2c_client *client)
{
/* Функция Специальные процедуры */
return 0;
}
/* Традиционный метод сопоставления ID список */
static const struct i2c_device_id xxx_id[] = {
{"xxx", 0},
{}
};
/* Соответствие дерева устройств списку */
static const struct of_device_id xxx_of_match[] = {
{ .compatible = "xxx" },
{ /* Sentinel */ }
};
/* i2c структура драйвера */
static struct i2c_driver xxx_driver = {
.probe = xxx_probe,
.remove = xxx_remove,
.driver = {
.owner = THIS_MODULE,
.name = "xxx",
.of_match_table = xxx_of_match,
},
.id_table = xxx_id,
};
/* Функция входа в привод */
static int __init xxx_init(void)
{
int ret = 0;
ret = i2c_add_driver(&xxx_driver);
return ret;
}
/* Функция экспорта драйвера */
static void __exit xxx_exit(void)
{
i2c_del_driver(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);
Когда устройство I2C и драйвер I2C успешно сопоставлены, будет выполнена функция проверки. Это то же самое, что и драйвер платформы. Функция проверки в основном содержит стандартный драйвер символьного устройства.
Рекомендовано в прошлом
Linux — это система реального времени или операционная система с разделением времени?
Правила расширения вложенных макросов языка C
Поделитесь осциллографом с последовательным портом QT с открытым исходным кодом
Функция обратного вызова языка C, необходимая для улучшения навыков C.