全智V5+AXP233电源管理芯片调试

简介: 全智V5+AXP233电源管理芯片调试

AXP233驱动调试记录

问题描述

遇到的最关键的问题就是:

AXP233是挂在了I2C-0的设备节点上,因为现在的V5的限制,I2C-0这个设备节点,无法在应用层直接操作。

解决办法:

只能开发一个内核驱动,在驱动中抛出应用层可以操作的接口,应用层调用这个接口,这样就可以曲线救国进行控制AXP233了。

具体修改方案

linux-4.4内核的power相关的驱动位置: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手册里描述,关机调用需要给寄存器REG32H[7]写入1,即可操作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 ############!
目录
相关文章
|
4月前
|
存储 NoSQL Linux
OpenOCD(一):什么是OpenOCD&调试适配器硬件
OpenOCD(一):什么是OpenOCD&调试适配器硬件
123 0
|
10月前
|
Linux 测试技术 Windows
可编程 USB 转串口适配器开发板应用于电子设备开发测试
可编程 USB 转串口适配器开发板应用于电子设备开发测试
可编程 USB 转串口适配器开发板应用于电子设备开发测试
|
8月前
|
Python
MicroPython 玩转硬件系列4:串口小实验
MicroPython 玩转硬件系列4:串口小实验
|
8月前
|
存储 Linux Android开发
会C/C++就可以开发Linux/Android应用程序?替代传统串口屏的Yoxios了解一下!
会C/C++就可以开发Linux/Android应用程序?替代传统串口屏的Yoxios了解一下!
153 0
|
XML 测试技术 网络安全
开发调试工具:可编程 USB 转串口适配器开发板
首先声明一下,大家都是搞硬件开发的,这几种接口当然是很简单的事,但有些时候对于一个新的设备或者芯片的测试,有个现成的工具当然更顺手,节省时间,也更可靠嘛。
|
开发工具
RK3399平台开发系列讲解(内核驱动外设篇)6.19、摄像头OV4689模组驱动代码分析
RK3399平台开发系列讲解(内核驱动外设篇)6.19、摄像头OV4689模组驱动代码分析
137 0
 RK3399平台开发系列讲解(内核驱动外设篇)6.19、摄像头OV4689模组驱动代码分析
|
数据采集 Shell 芯片
vxworks的pci设备驱动调试
vxworks的pci设备驱动调试
609 0
vxworks的pci设备驱动调试
西门子S7-200 SMART如何用存储卡复位CPU出厂设置、固件升级、程序传输
上篇文章中我们学习了西门子S7-200 SMART的全局变量和局部变量以及如何编写带参数子程序并调用,本篇我们来介绍西门子S7-200 SMART使用存储卡复位CPU到出厂设置、固件升级和程序传输。S7-200 SMART CPU使用FAT32文件系统格式,支持容量为4G至32G范围内的标准商用MicroSD HC卡。
西门子S7-200 SMART如何用存储卡复位CPU出厂设置、固件升级、程序传输
|
NoSQL 芯片
RISC-V MCU开发 (五):调试配置
在嵌入式开发中,除了编译配置外,工程的调试配置也需要关注。针对内置芯片工程模板创建的项目,MounRiver® Studio(MRS)会自动配置好相关调试参数,而导入的外部项目则需要进行部分调试配置项的手动指定。MRS支持指定GD-Link、WCH-Link、JLink等在线调试仿真器,设置预设断点、配置文件、OpenOCD工具、GDB工具...等调试参数。
RISC-V MCU开发 (五):调试配置
|
Java 数据库连接 测试技术
嵌入式系统的省电模式
电源管理一直是一个热门话题,是近年来的嵌入式开发人员遇到的“一个很酷的话题”。其重要性在很大程度上取决于延长手持设备电池寿命的要求,但环境危害,散热等引起了人们的关注。嵌入式软件可以实现三种节电程序:使用动态电压和频率调整(DVFS)来根据当前需要调整CPU性能。
1218 0