读取mx31-pdk板voltage

 

想自己读取mx31-pdk板子的电压值,以便能进行电压的显示。

    该板子的电源控制芯片为飞思卡尔自己的13783,其开发包中已带了电源管理的驱动,这里首先略微分析一下该驱动代码,然后搞明白应该如何来读取该电压值。

    首先要找到关于电压控制的驱动代码,经过寻找发现有关电压控制的驱动代码的存放路径为/drivers/mxc/pmic/mc13783/pmic_battery.c,浏览该代码可以发现

一.关于驱动的注册的代码

pmic_battery.c的最底部有以下代码:

static int __init pmic_battery_init(void)

{

   pr_debug("PMIC Battery driver loading.../n");

   return platform_driver_register(&pmic_battery_driver_ldm);

}

 

static void __exit pmic_battery_exit(void)

{

   platform_driver_unregister(&pmic_battery_driver_ldm);

   pr_debug("PMIC Battery driver successfully unloaded/n");

}

module_init(pmic_battery_init);

module_exit(pmic_battery_exit);

 

MODULE_DESCRIPTION("pmic_battery driver");

从以上代码可看出这里进行了电源管理驱动pmic_battery_driver_ldm的注册,而关于这个驱动的定义同样在该文件中,定义为:

static struct platform_driver pmic_battery_driver_ldm = {

   .driver = {

             .name = "pmic_battery",

             .bus = &platform_bus_type,

             },

   .suspend = pmic_battery_suspend,

   .resume = pmic_battery_resume,

   .probe = pmic_battery_probe,

   .remove = pmic_battery_remove,

};

其中pmic_battery_probe是该驱动注册时要调用的回调函数,这个函数很重要,在这个函数里可以进行设备device的保存,以及资源的获得,以及其他的。

二.Driver驱动pmic_battery_probe回调函数阅读

    static int pmic_battery_probe(struct platform_device *pdev)

{

       int ret = 0;

       struct class_device *temp_class;

       pmic_battery_major = register_chrdev(0, PMIC_BATTERY_STRING,

                                        &pmic_battery_fops);

       if (pmic_battery_major < 0) {

              printk(KERN_ERR "Unable to get a major for pmic_battery/n");

              return pmic_battery_major;

       }

       init_waitqueue_head(&suspendq);

       pmic_battery_class = class_create(THIS_MODULE, PMIC_BATTERY_STRING);

       if (IS_ERR(pmic_battery_class)) {

              printk(KERN_ERR "Error creating PMIC battery class./n");

              ret = PTR_ERR(pmic_battery_class);

              goto err_out1;

       }

       temp_class = class_device_create(pmic_battery_class, NULL,

                                    MKDEV(pmic_battery_major, 0),

                                    NULL, PMIC_BATTERY_STRING);

       if (IS_ERR(temp_class)) {

              printk(KERN_ERR "Error creating PMIC battery class device./n");

              ret = PTR_ERR(temp_class);

              goto err_out2;

       }

       pmic_batt_led_control(true);

       pmic_batt_set_5k_pull(true);

       printk(KERN_INFO "PMIC Battery successfully probed/n");

       return ret;

      err_out2:

       class_destroy(pmic_battery_class);

      err_out1:

       unregister_chrdev(pmic_battery_major, PMIC_BATTERY_STRING);

       return ret;

}

其中在mc13783/pmic_battery_defs.h有关于字符串的定义:

#define         PMIC_BATTERY_STRING    "pmic_battery"

可以看出,register_chrdev(0, PMIC_BATTERY_STRING, &pmic_battery_fops);注册了一个字符设备,名字为pmic_battery,同时指定了它的fileoperations结构体为pmic_battery_fops,关于该结构体定义同样子该c文件中,如下:

 static struct file_operations pmic_battery_fops = {

       .owner = THIS_MODULE,

       .ioctl = pmic_battery_ioctl,

       .open = pmic_battery_open,

       .release = pmic_battery_release,

};

可以看出该设备驱动的用户层操作接口只有三个,还包括打开和关闭的两个必须函数,真正进行操作的函数只有pmic_battery_ioctl一个函数。

三.设备驱动pmic_battery_ioctl函数阅读

       static int pmic_battery_ioctl(struct inode *inode, struct file *file,

                           unsigned int cmd, unsigned long arg)

{

       t_charger_setting *chgr_setting = NULL;

       unsigned short c_current;

       unsigned int bc_info;

       t_eol_setting *eol_setting;

       if (_IOC_TYPE(cmd) != 'p')

              return -ENOTTY;

       switch (cmd) {

       case PMIC_BATT_CHARGER_CONTROL:

              if ((chgr_setting = kmalloc(sizeof(t_charger_setting),

                                       GFP_KERNEL)) == NULL) {

                     return -ENOMEM;

              }

              if (copy_from_user(chgr_setting, (t_charger_setting *) arg,

                               sizeof(t_charger_setting))) {

                     kfree(chgr_setting);

                     return -EFAULT;

              }

              if (chgr_setting->on != false) {

                     CHECK_ERROR_KFREE(pmic_batt_enable_charger

                                     (chgr_setting->chgr,

                                      chgr_setting->c_voltage,

                                      chgr_setting->c_current),

                                     (kfree(chgr_setting)));

              } else {

                     CHECK_ERROR(pmic_batt_disable_charger

                                (chgr_setting->chgr));

              }

              kfree(chgr_setting);

              break;

       case PMIC_BATT_SET_CHARGER:

              if ((chgr_setting = kmalloc(sizeof(t_charger_setting),

                                       GFP_KERNEL)) == NULL) {

                     return -ENOMEM;

              }

              if (copy_from_user(chgr_setting, (t_charger_setting *) arg,

                               sizeof(t_charger_setting))) {

                     kfree(chgr_setting);

                     return -EFAULT;

              }

              CHECK_ERROR_KFREE(pmic_batt_set_charger(chgr_setting->chgr,

                                                 chgr_setting->c_voltage,

                                                 chgr_setting->

                                                 c_current),

                              (kfree(chgr_setting)));

              kfree(chgr_setting);

              break;

       case PMIC_BATT_GET_CHARGER:

              if ((chgr_setting = kmalloc(sizeof(t_charger_setting),

                                       GFP_KERNEL)) == NULL) {

                     return -ENOMEM;

              }

              if (copy_from_user(chgr_setting, (t_charger_setting *) arg,

                               sizeof(t_charger_setting))) {

                     kfree(chgr_setting);

                     return -EFAULT;

              }

              CHECK_ERROR_KFREE(pmic_batt_get_charger_setting

                              (chgr_setting->chgr, &chgr_setting->c_voltage,

                               &chgr_setting->c_current),

                              (kfree(chgr_setting)));

              if (copy_to_user

                  ((t_charger_setting *) arg, chgr_setting,

                   sizeof(t_charger_setting))) {

                     return -EFAULT;

              }

              kfree(chgr_setting);

              break;

       case PMIC_BATT_GET_CHARGER_SENSOR:

              {

                     t_sensor_bits sensor;

                     pmic_get_sensors(&sensor);

                     if (copy_to_user

                         ((unsigned int *)arg, &sensor.sense_chgdets,

                          sizeof(unsigned int)))

                            return -EFAULT;

                     break;

              }

       case PMIC_BATT_GET_BATTERY_VOLTAGE:

              CHECK_ERROR(pmic_batt_get_batt_voltage(&c_current));

              bc_info = (unsigned int)c_current * 2300 / 1023 + 2400;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

       case PMIC_BATT_GET_BATTERY_CURRENT:

              CHECK_ERROR(pmic_batt_get_batt_current(&c_current));

              bc_info = (unsigned int)c_current * 5750 / 1023;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

       case PMIC_BATT_GET_BATTERY_TEMPERATURE:

              CHECK_ERROR(pmic_batt_get_batt_temperature(&c_current));

              bc_info = (unsigned int)c_current;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

       case PMIC_BATT_GET_CHARGER_VOLTAGE:

              CHECK_ERROR(pmic_batt_get_charge_voltage(&c_current));

              bc_info = (unsigned int)c_current * 23000 / 1023;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

       case PMIC_BATT_GET_CHARGER_CURRENT:

              CHECK_ERROR(pmic_batt_get_charge_current(&c_current));

              bc_info = (unsigned int)c_current * 5750 / 1023;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

       case PMIC_BATT_EOL_CONTROL:

              if ((eol_setting = kmalloc(sizeof(t_eol_setting), GFP_KERNEL))

                  == NULL) {

                     return -ENOMEM;

              }

              if (copy_from_user(eol_setting, (t_eol_setting *) arg,

                               sizeof(t_eol_setting))) {

                     kfree(eol_setting);

                     return -EFAULT;

              }

              if (eol_setting->enable != false) {

                     CHECK_ERROR_KFREE(pmic_batt_bp_enable_eol

                                     (eol_setting->typical),

                                     (kfree(chgr_setting)));

              } else {

                     CHECK_ERROR_KFREE(pmic_batt_disable_eol(),

                                     (kfree(chgr_setting)));

              }

              kfree(eol_setting);

              break;

       case PMIC_BATT_SET_OUT_CONTROL:

              CHECK_ERROR(pmic_batt_set_out_control((t_control) arg));

              break;

       case PMIC_BATT_SET_THRESHOLD:

              CHECK_ERROR(pmic_batt_set_threshold((int)arg));

              break;

       case PMIC_BATT_LED_CONTROL:

              CHECK_ERROR(pmic_batt_led_control((bool) arg));

              break;

       case PMIC_BATT_REV_SUPP_CONTROL:

              CHECK_ERROR(pmic_batt_set_reverse_supply((bool) arg));

              break;

       case PMIC_BATT_UNREG_CONTROL:

              CHECK_ERROR(pmic_batt_set_unregulated((bool) arg));

              break;

       default:

              return -EINVAL;

       }

       return 0;

}

这是标准的设备驱动函数,而用户的ioctl函数原型为int ioctl(int fd, ind cmd, …);适合对设备的一些特性进行控制,其中fd就是用户程序打开设备时使用open函数返回的文件描述符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。当需要这个参数时,把该参数的地址传递给static int pmic_battery_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)arg,以便进行数据的回传(感觉是这样)。所以应用层只用调用标准的函数ioctl(int fd, ind cmd, …)并传递正确的cmd参数就可以了。这里就又有一个重要的事,就是分析以上代码,找出传递读出电压voltage的正确的cmd参数。

查看代码发现有如下一段:

       case PMIC_BATT_GET_BATTERY_VOLTAGE:

              CHECK_ERROR(pmic_batt_get_batt_voltage(&c_current));

              bc_info = (unsigned int)c_current * 2300 / 1023 + 2400;

              if (copy_to_user((unsigned int *)arg, &bc_info,

                             sizeof(unsigned int)))

                     return -EFAULT;

              break;

其中有一函数pmic_batt_get_batt_voltage(&c_current),查看后原型如下:

 

PMIC_STATUS pmic_batt_get_batt_voltage(unsigned short *b_voltage)

{

       t_channel channel;

       unsigned short result[8];

       if (suspend_flag == 1)

              return PMIC_ERROR;

       channel = BATTERY_VOLTAGE;

       CHECK_ERROR(pmic_adc_convert(channel, result));

       *b_voltage = result[0];

       return PMIC_SUCCESS;

}

   通过以上函数可以得出传递对了PMIC_BATT_GET_BATTERY_VOLTAGE这个cmd参数,驱动会把电压值bc_info传递给用户地址空间的(unsigned int *)arg,从而获得电压数据。

四.参数PMIC_BATT_GET_BATTERY_VOLTAGE的定义

       通过查看代码,在 <asm/arch/pmic_battery.h>中有如下定义:

#define PMIC_BATT_GET_BATTERY_VOLTAGE     _IOR('p', 0xcb, int)

而在/include/asm-generic/ioctl.h中有如下定义:

#define _IOC_NRBITS  8

#define _IOC_TYPEBITS     8

#define _IOC_SIZEBITS       14

#define _IOC_DIRBITS 2

 

#define _IOC_NRMASK       ((1 << _IOC_NRBITS)-1)

#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)

#define _IOC_SIZEMASK     ((1 << _IOC_SIZEBITS)-1)

#define _IOC_DIRMASK      ((1 << _IOC_DIRBITS)-1)

 

#define _IOC_NRSHIFT       0

#define _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)

#define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)

#define _IOC_DIRSHIFT      (_IOC_SIZESHIFT+_IOC_SIZEBITS)

 

#define _IOC_NONE     0U

#define _IOC_WRITE   1U

#define _IOC_READ     2U

 

#define _IOC(dir,type,nr,size) /

        (((dir)  << _IOC_DIRSHIFT) | /

         ((type) << _IOC_TYPESHIFT) | /

         ((nr)   << _IOC_NRSHIFT) | /

         ((size) << _IOC_SIZESHIFT))

#define _IOR(type,nr,size)      _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

 

以上宏定义完成的对cnd参数PMIC_BATT_GET_BATTERY_VOLTAGE的定义,至此也就完成了用户空间读取电压值的所有必须元素,可以开始进行用户空间程序的编写。

五.编写程序读取电量voltage

编写一函数voltage-read.c如下:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <linux/wait.h>

 

//#include <asm/arch/pmic_status.h>

///#include <asm/arch/pmic_battery.h>

 

#define _IOC_NRBITS  8

#define _IOC_TYPEBITS     8

#define _IOC_SIZEBITS      14

#define _IOC_DIRBITS 2

 

#define _IOC_NRMASK       ((1 << _IOC_NRBITS)-1)

#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)

#define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)

#define _IOC_DIRMASK      ((1 << _IOC_DIRBITS)-1)

 

#define _IOC_NRSHIFT       0

#define _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)

#define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)

#define _IOC_DIRSHIFT     (_IOC_SIZESHIFT+_IOC_SIZEBITS)

 

 

#define _IOC_NONE     0U

#define _IOC_WRITE   1U

#define _IOC_READ     2U

 

#define _IOC(dir,type,nr,size) /

        (((dir)  << _IOC_DIRSHIFT) | /

         ((type) << _IOC_TYPESHIFT) | /

         ((nr)   << _IOC_NRSHIFT) | /

         ((size) << _IOC_SIZESHIFT))

 

#define  _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

#define PMIC_BATT_GET_BATTERY_VOLTAGE           _IOR('p', 0xcb, int)

main()

{

  unsigned int c_voltage;

int fd,status;

  fd = open("/dev/pmic_battery", O_RDWR);

      if (fd < 0) {                         

     printf("/dev/pmic_battery  open error!!");

     return -1;

     }

     status = ioctl(fd, PMIC_BATT_GET_BATTERY_VOLTAGE, &c_voltage);

     if (status < 0) {                         

     printf("/dev/pmic_battery  read error!!");

     return -1;

     }

      printf("/dev/pmic_battery  voltage is  %d!!",c_voltage);

    return 1; 

}

交叉编译之后,在板子上就可以运行,并获得了int型的ad数据,经过转换就可以获得电池的电压值。

你可能感兴趣的:(struct,String,cmd,user,IOC,Class)