Qcom 平台读取pmic上 adc电压值的方法
如下图,可以通过平台提供的节点(参考高通文档将mpp配置为adc功能) cat对应的节点获取结果;
也可以通过自行实现的驱动中调用相关接口并转化结果;
Kernel demo 参考代码:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/consumer.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/time.h>
static struct workqueue_struct *init_mpp2_adc_wq;
static struct delayed_work init_work;
static struct mpp2_adc_data
{
char name;
int major;
struct class *class;
struct platform_device *pdev;
struct qpnp_vadc_chip *vadc_dev;
}qm215_mpp2_adc;
ssize_t mpp2_adc_read (struct file *file, char __user *buf, size_t size, loff_t * loft)
{
int ret;
int adc_val = 0;
int i = 0;
char adc[16];
char count = 0;
struct qpnp_vadc_result result;
if(*loft)
return 0;
printk("qm215 mpp2_adc read adc\n");
ret = qpnp_vadc_read(qm215_mpp2_adc.vadc_dev,P_MUX2_1_1,&result);
if(ret < 0)
{
printk("qm215 mpp2_adc qpnp_vadc_read fail\n");
return size;
}
printk("qm215 mpp2_adc read adc end\n");
adc_val = (int)result.physical;
// adc_val = adc_val / 1000;
printk("qm215 mpp2_adc read adc_val: %d uv\n",adc_val);
memset(adc,0,sizeof(adc));
count = sprintf(adc,"%d", adc_val);
do
{
adc_val = adc_val / 10;
i++;
}
while(adc_val);
ret = copy_to_user(buf, adc, i+1);
*loft += (i+1);
return i+1;
}
static struct file_operations mpp2_adc_ops =
{
.owner = THIS_MODULE,
.read = mpp2_adc_read,
};
static void mpp2_adc_init_work(struct work_struct *work)
{
printk("qm215 mpp2_adc init work\n");
qm215_mpp2_adc.vadc_dev = qpnp_get_vadc(&qm215_mpp2_adc.pdev->dev,"test");
if(qm215_mpp2_adc.vadc_dev == NULL)
printk("qm215 qpnp_get_vadc fail \n ");
if( IS_ERR(qm215_mpp2_adc.vadc_dev))
printk("qm215 qpnp_get_vadc fail errno is %d\n", (int)PTR_ERR(qm215_mpp2_adc.vadc_dev));
}
static int mpp2_adc_platform_probe(struct platform_device *pdev)
{
int ret;
// struct device_node *np = pdev->dev.of_node;
printk("qm215 mpp2_adc_read probe \n");
qm215_mpp2_adc.pdev = pdev;
qm215_mpp2_adc.major = register_chrdev(0, "mpp2_adc", &mpp2_adc_ops);
qm215_mpp2_adc.class = class_create(THIS_MODULE, "mpp2_adc");
device_create(qm215_mpp2_adc.class, NULL, MKDEV(qm215_mpp2_adc.major, 0), NULL, "mpp2_adc");
INIT_DELAYED_WORK(&init_work, mpp2_adc_init_work);
init_mpp2_adc_wq = create_singlethread_workqueue("init_mpp2_adc_wq");
if (!init_mpp2_adc_wq) {
ret = -EINVAL;
}
queue_delayed_work(init_mpp2_adc_wq, &init_work, 10*HZ);
return 0;
}
static int mpp2_adc_platform_remove(struct platform_device *pdev)
{
device_destroy(qm215_mpp2_adc.class, MKDEV(qm215_mpp2_adc.major, 0));
class_destroy(qm215_mpp2_adc.class);
unregister_chrdev(qm215_mpp2_adc.major, "mpp2_adc");
return 0;
}
static struct of_device_id mpp2_adc_of_match[] = {
{ .compatible = "qm215,mpp2_adc", },
{},
};
static struct platform_driver mpp2_adc_platform_driver = {
.probe = mpp2_adc_platform_probe,
.remove = mpp2_adc_platform_remove,
.driver = {
.owner = THIS_MODULE,
.name = "qm215,mpp2_adc",
.of_match_table = of_match_ptr(mpp2_adc_of_match),
}
};
static int __init mpp2_adc_init(void)
{
int ret = 0;
printk("qm215 mpp2_adc init\n");
ret = platform_driver_register(&mpp2_adc_platform_driver);
if(ret< 0)
{
printk("qm215 mpp2_adc platform driver register fail\n");
return -1;
}
printk("qm215 mpp2_adc end\n");
return 0;
}
static void __exit mpp2_adc_exit(void)
{
platform_driver_unregister(&mpp2_adc_platform_driver);
}
module_init(mpp2_adc_init);
module_exit(mpp2_adc_exit);
MODULE_AUTHOR("xxx");
MODULE_DESCRIPTION("mpp2_adc");
MODULE_LICENSE("GPL");