Запись отладки драйвера 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 ############!