Драйвер ядра, объединяющий platform_driver с i2c_driver

Пишу драйвер ядра для LCD. Этот ЖК-дисплей использует восемь линий GPIO (d0 ... d7) для отправки данных на дисплей, некоторые управляющие сигналы gpio (включение / выключение, включение подсветки и r / w) и потенциометр для управления контрастностью дисплея, подключенный к шине I2C.

Я написал platform_driver, который использует зондирование и удаление обратных вызовов для регистрации / отмены регистрации разного устройства, которое создает символьное устройство / dev / lcd, с помощью которого можно использовать из пользовательского пространства для отправки буфера для печати на экране. Я могу читать GPIOS, правильно определенный в DTS, а также управлять этими GPIOS для печати строк на ЖК-дисплее. Это скелет:

#define MODULE_NAME     "lcd"
static void lcd_hw_setup(void)
{ ...  }
static int lcd_open(struct inode *inode, struct file *file)
{ ... }
static ssize_t lcd_write (struct file *file, const char *buf, size_t     count, loff_t *ppos)
{ ... }
static int lcd_close(struct inode *inode, struct file *file)
{ ... }
/* declare & initialize file_operations structure */
static const struct file_operations lcd_dev_fops = {
    .owner = THIS_MODULE,
    .open = lcd_open,
    .write = lcd_write,
    .release = lcd_close
};
/* declare & initialize miscdevice structure */
static struct miscdevice lcd_misc = {
    .minor = MISC_DYNAMIC_MINOR, /* major = 10 assigned by the misc framework */
    .name = MODULE_NAME, /* /dev/lcd */
    .fops = &lcd_dev_fops,
};
static int lcd_probe(struct platform_device *pdev)
{
    struct device *dev;
    pr_info(MODULE_NAME ": lcd_probe init\n");
    /* Register the misc device with the kernel */
    misc_register(&lcd_misc);
    dev = &pdev->dev;
    /* gpiod_get calls to get gpios from DTS */
    lcd_hw_setup();
    pr_info(MODULE_NAME ": lcd_probe ok\n");
    return 0;
}
static int lcd_remove(struct platform_device *pdev)
{
    pr_info(MODULE_NAME ": lcd_remove\n");
    /* Release gpio resources */
    ... 
    /* Unregister the device with the kernel */
    misc_deregister(&lcd_misc);
    return 0;
}
/* declare a list of devices supported by this driver */
static const struct of_device_id lcd_of_ids[] = {
    { .compatible = "my-lcd" },
    { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, lcd_of_ids);
/* declare & initialize platform_driver structure */
static struct platform_driver lcd_pdrv = {
    .probe = lcd_probe,
    .remove = lcd_remove,
    .driver = {
        .name = "my-lcd", /* match with compatible */
        .of_match_table = lcd_of_ids,
        .owner = THIS_MODULE,
    },
};
/* register platform driver */
module_platform_driver(lcd_pdrv);

Это действительно прекрасно работает.

Теперь мне нужно отправить потенциометру I2C значение инициализации, чтобы установить контрастность дисплея. Для этого необходимо вызвать i2c_smbus_write_byte_data. Для этого мне нужен доступ к структуре i2c_client.

Я нашел несколько примеров I2C, которые создают i2c_driver, который обеспечивает проверку и удаление обратных вызовов и получает указатель на эту структуру i2c_client в функции проверки. Но я не могу связать этот i2c_driver с моим platform_driver. Они кажутся полностью независимыми драйверами.

Мои вопросы:

  • Можно ли объединить platform_driver и i2c_driver в одном модуле ядра? Я имею в виду, могу ли я добавить вызовы module_platform_driver и module_i2c_driver в один модуль ядра?

  • Или, может быть, мне нужно создать второй драйвер только для управления потенциометром I2C. В этом конкретном случае существует зависимость между обоими модулями ядра. Как управлять этой зависимостью?

Пожалуйста, некоторая помощь с этим была бы действительно полезной. Большое спасибо!


person aicastell    schedule 18.12.2020    source источник
comment
Во-первых, драйвер, скорее всего, уже написан (см. Папку drivers / auxdisplay). Во-вторых, в Linux контрастирующая часть обычно является другим (или отдельным) драйвером.   -  person 0andriy    schedule 25.12.2020
comment
Я проверю указанный драйвер, чтобы убедиться, что он соответствует моим потребностям. В этом есть смысл. Ваш отзыв очень полезен, чтобы подтвердить, что я на правильном пути. Большое вам спасибо за ваше время! :)   -  person aicastell    schedule 26.12.2020


Ответы (1)


В качестве первоначальной работы я разработал второй драйвер (i2c_driver) только для вызова функции i2c_smbus_write_byte_data из обратного вызова зонда. Это работает, но я хотел бы знать, правильный ли способ решить эту проблему. Спасибо!

person aicastell    schedule 22.12.2020
comment
Да, смотрите мой комментарий к вашему сообщению. - person 0andriy; 25.12.2020