#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");