/dev/下创建可操作文件


#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/mtd/partitions.h>
#include <linux/gpio.h>
#include <mtd/mtd-abi.h>
#include <mach-anyka/nand_list.h>
#include <mach-anyka/fha.h>
#include <plat-anyka/notify.h>
#include <linux/platform_device.h>
#include <mach/adc.h>
#include <linux/proc_fs.h>




#define GET_AIN_MAJOR                 177
#define AK_GET_BAT _IO('H',  0)
#define EFUSE_CTRL_REG                      (AK_VA_SYSCTRL + 0x48)
#define ANALOG_CTRL_REG3                    (AK_VA_SYSCTRL + 0x9C)
#define ANALOG_CTRL_REG4                    (AK_VA_SYSCTRL + 0xA0)


#define DBG(fmt...) printk(fmt)




static int akget_ain_open(struct inode *inode, struct file *filp);
static int akget_ain_close(struct inode *inode, struct file *filp);
static int get_ain_voltage(unsigned long arg);
static long akget_ain_ioctl(/*struct inode *inode, */struct file *filp, unsigned int cmd, unsigned long arg);
static int get_ain_major = GET_AIN_MAJOR;


static struct akget_ain_dev
{
    struct cdev c_dev;
    
} getain_c_dev;


static const struct file_operations akget_ain_fops =
{
    .owner   = THIS_MODULE,
    .open    = akget_ain_open,
    .release = akget_ain_close,
    .unlocked_ioctl   = akget_ain_ioctl,
};


static int akget_ain_open(struct inode *inode, struct file *filp)
{

/**
* @retval    1) "0" : read fail, other value :  read success.
* @          2) "bit7=1 (the first bit is bit0)" means that fuse has not been burnt. 
* @          3) other values meaning adjust voltage  successfully.
*/

int rTmp = 0x0;
//pull down VP 
REG32(ANALOG_CTRL_REG3) |= (1 << 3);
REG32(ANALOG_CTRL_REG4) |= ((1 << 0) | (1 << 25));
msleep(200);   //wait for VP pull down, (>150 ms)
REG32(EFUSE_CTRL_REG) = 0x00000002;//set read mode
REG32(EFUSE_CTRL_REG) |= 0x00000001;//start to read 
msleep(15);  //(10); //wait for read finish ( > 2us ) 
REG32(EFUSE_CTRL_REG) &= (~0x00000001); //clear efuse_cfg_rdy bit for next operate
rTmp = REG32(EFUSE_CTRL_REG); 
//if(((rTmp >> 8)&0xff)< 8)
// DBG("open get ain device failure.:%d\n",rTmp);
  //else
DBG("open get ain device success:%d.\n",rTmp);
return 0;
}


static int akget_ain_close(struct inode *inode, struct file *filp)
{
/* do nothing, return correct */
DBG("close get ain device success.\n");
return 0;
}


/*
*
*由于采用1.5v基准电压,三分频,因此最高电池电压为4.5v,实际电压值应该为 voltage*4.5/1024
*
*/
static int get_ain_voltage(unsigned long arg)
{
int voltage;
DBG("\n###############%s; \n",__func__);
// read voltage sample
voltage = (int)adc1_read_bat();
DBG("ad4_value = %d:\n",voltage);
  copy_to_user((void __user *)arg, &voltage, sizeof(int));
return 1;
}


static long akget_ain_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret = 0;
    
switch(cmd)
{
case AK_GET_BAT:
{
ret = get_ain_voltage(arg);
break;
}
default:
{
return -EINVAL;
}


}
    return ret;
}


static struct class *akgetbat_class;


static void getain_setup_cdev(void)
{
    int err = 0;
    dev_t devno = MKDEV(get_ain_major, 0);
printk("%s,%d\n",__func__,__LINE__);
    cdev_init(&(getain_c_dev.c_dev), &akget_ain_fops);
    getain_c_dev.c_dev.owner = THIS_MODULE;
    getain_c_dev.c_dev.ops = &akget_ain_fops;
    err = cdev_add(&(getain_c_dev.c_dev), devno, 1);
    if(err)
    {
        printk(KERN_NOTICE "Error %d ain char dev\n", err);
    }

//automatic mknod device node
akgetbat_class = class_create(THIS_MODULE, "akgetbat_class");
device_create(akgetbat_class, NULL, devno, &getain_c_dev, "akget_ain");
printk("%s,%d\n",__func__,__LINE__);
}
static int akget_ain_probe(struct platform_device *pdev)
{
int result = 0;
dev_t devno;
devno = MKDEV(get_ain_major, 0);
printk("%s,%d\n",__func__,__LINE__);
if(get_ain_major)
{
result = register_chrdev_region(devno, 1, "anyka get ain char dev");
}
else
{
result = alloc_chrdev_region(&devno, 0, 1, "anyka get ain char dev");
}
if(result < 0)
{
printk("%s,%d\n",__func__,__LINE__);
return result;
}
printk("%s,%d\n",__func__,__LINE__);
getain_setup_cdev();
    
DBG(KERN_INFO "akfha Char Device Initialize Successed!\n");
return 0;
}
static int akget_ain_remove(struct platform_device *pdev)
{
dev_t devno = MKDEV(get_ain_major, 0);

//destroy device node
device_destroy(akgetbat_class, devno);
class_destroy(akgetbat_class); 

//delete char device
    cdev_del(&(getain_c_dev.c_dev));
    unregister_chrdev_region(devno, 1);

return 0;
}


/* device driver for platform bus bits */
static struct platform_driver akget_ain_driver = {
.probe = akget_ain_probe,
.remove = akget_ain_remove,
.driver = {
.owner = THIS_MODULE,
.name = "ak-getain",
.pm = NULL,
},
};
static int __init akget_ain_init(void)
{
printk("*********akget_ain init\n");
return platform_driver_register(&akget_ain_driver);
}
                      
static void __exit akget_ain_exit(void)
{
platform_driver_unregister(&akget_ain_driver);
printk("*******akget_ain_exit");
}
                      
subsys_initcall(akget_ain_init);
module_exit(akget_ain_exit);            
MODULE_LICENSE("GPL");
MODULE_AUTHOR("************");
MODULE_DESCRIPTION("get ain voltage");

Guess you like

Origin blog.csdn.net/harhy/article/details/50373215