Отладка микросхемы управления питанием Quanzhi V5 + AXP233

Запись отладки драйвера AXP233

описание проблемы

Наиболее критическая проблема, с которой пришлось столкнуться:

AXP233 висит на узле устройства I2C-0.Из-за текущих ограничений V5 узлом устройства I2C-0 нельзя напрямую управлять на уровне приложения.

Решение:

Можно только разработать драйвер ядра, прокинуть в драйвере интерфейс, которым может работать прикладной уровень, а прикладной уровень вызывает этот интерфейс, чтобы можно было управлять AXP233.

Конкретный план модификации

Расположение драйвера, связанного с питанием, ядра linux-4.4: linux-4.4\drivers\power.

В каталоге power есть каталог axp. Видно, что в этом каталоге размещены драйверы блоков питания серии axpXXX.

После открытия вы увидите, что в каталоге axp есть каталог axp22x.

Расположение: linux-4.4\drivers\power\axp\axp22x.

В этом каталоге axp22x хранится весь исходный код axp22x.

axp22x.h и axp22x.c — это исходные коды, которые вам нужно просмотреть в первую очередь.

На данный момент в axp22x реализованы драйверы трех микросхем управления питанием: axp221s, axp227 и axp223. Это большая коллекция.

Тогда можно поработать на этой основе:

1. Используйте misc_register, чтобы зарегистрировать устройство специального символа и передать работоспособный интерфейс на уровень приложения.

misc_device — это специальное символьное устройство. При регистрации драйвера используйте для регистрации функцию misc_register, в этой функции автоматически будет создан узел устройства, то есть файл устройства. Для создания файлов устройств директива mknod не требуется. Потому что misc_register() вызовет class_device_creat или device_creat().

https://www.cnblogs.com/ggzhangxiaochao/p/12894883.html Это хорошее объяснение.

Основной код, который я добавил:



/*********************************************************
 * 20230920 zh add 
 * 控制AXP233电源管理芯片,为应用层程序提供控制接口
 **********************************************************/ 

static ssize_t axp233_ctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    
    
    char my_data[] = "Hello from Kernel!\n";
    size_t len = strlen(my_data);
    
    if (*ppos >= len)
        return 0;

    if (count > len - *ppos)
        count = len - *ppos;

    if (copy_to_user(buf, my_data + *ppos, count)) {
    
    
        return -EFAULT;
    }

    *ppos += count;
    return count;
}

static ssize_t axp233_ctrl_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    
    
    char user_data[256];
    
    if (count >= sizeof(user_data)) {
    
    
        return -EINVAL;
    }

    if (copy_from_user(user_data, buf, count)) {
    
    
        return -EFAULT;
    }

    user_data[count] = '\0';
    printk("[zh] recv from User user_data: %s\n", user_data);
    printk("[zh] recv from User count: %d\n", count);

    if(strcasecmp(user_data, "power_off") == 0){
    
    
        printk("[zh] 关机 \n");
        // axp22x_power_off();

		pr_info("[axp] off zhenghui ############!\n");
		axp_regmap_set_bits(axp22x_pm_power->regmap, AXP22X_OFF_CTL, 0x80);
    }

    return count;
}

static const struct file_operations axp233_ctrl_fops = {
    
    
    .owner = THIS_MODULE,
    .read = axp233_ctrl_read,
    .write = axp233_ctrl_write,
};

static struct miscdevice axp233_misc_device = {
    
    
    .minor = MISC_DYNAMIC_MINOR,
    .name = "axp233_misc_device",
    .fops = &axp233_ctrl_fops,
};

static int axp233_ctrl_init(void)
{
    
    
    int ret = misc_register(&axp233_misc_device);
    if (ret) {
    
    
        pr_err("[zh]Failed to register misc device\n");
        return ret;
    }
    
    pr_info("[zh]Misc device registered: %s\n", axp233_misc_device.name);
    return 0;
}

static void axp233_ctrl_exit(void)
{
    
    
    misc_deregister(&axp233_misc_device);
    pr_info("[zh]Misc device unregistered\n");
}


// end

Согласно описанию в руководстве AXP233, вызов завершения работы должен записать 1 в регистр REG32H[7], чтобы заставить AXP233 выключиться.

В соответствии со стилем кода axp22x.c функция axp_regmap_set_bits используется для записи, а функция axp_regmap_read используется для чтения данных.

И это определено в заголовочном файле axp22x.h:

#define AXP22X_OFF_CTL             (0x32)

Итак, вы можете подражать и писать, то есть:

axp_regmap_set_bits(axp22x_pm_power->regmap, AXP22X_OFF_CTL, 0x80);

===== Прикладной уровень =====

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    
    
    int fd;
    char buffer[256];
    ssize_t bytes_read;

    fd = open("/dev/axp233_misc_device", O_RDWR);
    if (fd == -1) {
    
    
        perror("打开 axp233_misc_device 失败 \n");
        return 1;
    }

    printf("######## #### #### #### ####  \n");
    printf("正在读数据:\n");
    bytes_read = read(fd, buffer, sizeof(buffer));
    if (bytes_read == -1) {
    
    
        perror("读数据失败 \n");
        close(fd);
        return 1;
    }

    buffer[bytes_read] = '\0';
    printf("读取到的数据: %s\n", buffer);
    printf("######## #### #### #### ####  \n");

    printf("######## #### #### #### ####  \n");

    printf("正在写数据:\n");
    const char *data_to_send = "power_off";
    ssize_t bytes_written = write(fd, data_to_send, strlen(data_to_send));
    if (bytes_written == -1) {
    
    
        perror("写数据失败 \n");
    } else {
    
    
        printf("写数据: %s \n", data_to_send);
    }

    close(fd);
    printf("######## #### #### #### ####  \n");

    return 0;
}

===== Тогда можно взаимодействовать =====

root@xxx:/mnt/appslog# 
root@xxxx:/mnt/appslog# ./my_app 
######## #### #### #### ####  

正在读数据:
读取到的数据: Hello from Kernel!

######## #### #### #### ####  
######## #### #### #### ####  87.297512] [zh] recv from User user_data: power_off
[   87.316995] [zh] recv from User count: 9
据:
[   87.321409] sunxi_i2s_preapre,SNDRV_PCM_STATE_XRUN:playback xrun.
[   87.321409] [zh] 关机 
[   87.332323] [axp] off zhenghui ############!

рекомендация

отblog.csdn.net/qq_17623363/article/details/133088629