#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
//#include <asm/arch/hardware.h>
#include <linux/kthread.h>
//#include <asm/arch/clock.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/irqreturn.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#define OSDRV_MODULE_VERSION_STRING "HIHU_LSADC @Hi3516dv300"
#define GETREGISTERBIT(x, b) ((x >> b) & 0x1)
#define LSADC_CRTL_BASE (0x120E0000)
#define LSADC_CRTL_SIZE (0x40) // 64B
#define LSADC_CTRL0_OFF (0x0000)
#define LSADC_CTRL1_OFF (0x0004)
#define LSADC_CTRL2_OFF (0x0008)
#define LSADC_CTRL3_OFF (0x000C)
#define LSADC_CTRL4_OFF (0x0010) //中断使能
#define LSADC_CTRL5_OFF (0x0014) //中断状态寄存器
#define LSADC_CTRL6_OFF (0x0018)
#define LSADC_CTRL7_OFF (0x001C) //start
#define LSADC_CTRL8_OFF (0x0020) //stop
#define LSADC_CTRL9_OFF (0x0024) // bit width
#define LSADC_CTRL11_OFF (0x002C) // ch0 data
#define LSADC_CTRL12_OFF (0x0030) // ch1 data
#define DRV_MUXCTRL_REG63 (0x111F0030)
#define LSADC_AUTO_BUSY (4)
#define LSADC_IRQ (97)
#define LSADC_MINOR (210)
#define DEVICE_NAME "lsadc"
static unsigned char s_adc_data = 0;
static void __iomem *s_lsadc_base_vir = NULL; //ADC基址的虚拟地址
#define IO_ADDRESS_DEF(off) ((void __iomem *)((unsigned char __iomem *)s_lsadc_base_vir + off))
#define LSADC_READW(addr, ret) (ret = (*(volatile unsigned int *)(addr)))
#define LSADC_WRITEW(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
static int lsadc_open(struct inode *inode, struct file *file)
{
int ret = 0;
return ret;
}
static ssize_t lsadc_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
{
int ret = 0;
ret = __copy_to_user(buf, (void *)&s_adc_data, len);
return ret;
}
static int lsadc_release(struct inode *inode, struct file *file)
{
return 0;
}
static long lsadc_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
{
return 0;
}
static struct file_operations lsadc_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = lsadc_ioctl,
.open = lsadc_open,
.release = lsadc_release,
.read = lsadc_read,
};
static struct miscdevice lsadc_miscdev = {
.minor = LSADC_MINOR,
.name = "lsadc",
.fops = &lsadc_fops,
};
static int __init adc_start(void)
{
unsigned int reg = 0x01;
//writel(reg, IO_ADDRESS(LSADC_CTRL7_OFF));
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL7_OFF), reg);
//reg = readl(IO_ADDRESS(LSADC_CTRL7_OFF));
reg = 0;
LSADC_READW(IO_ADDRESS_DEF(LSADC_CTRL7_OFF), reg);
//printk(KERN_INFO "adc_start addr: 0x200B001C, value: 0x%x", reg);
return 0;
}
static int __init adc_stop(void)
{
unsigned int reg = 0x01;
//writel(reg, IO_ADDRESS(LSADC_CTRL8_OFF));
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL8_OFF), reg);
//reg = readl(IO_ADDRESS(LSADC_CTRL8_OFF));
reg = 0;
LSADC_READW(IO_ADDRESS_DEF(LSADC_CTRL8_OFF), reg);
//printk(KERN_INFO "adc_stop addr: 0x200B0020, value: 0x%x", reg);
return 0;
}
void tglitch_set(void)
{
unsigned int reg = 0x00;
reg = 0x0F;
//writel(reg, IO_ADDRESS(LSADC_CTRL1_OFF)); //滤毛刺配置寄存器
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL1_OFF), reg); //滤毛刺配置寄存器
}
static void bitwidth_set(void)
{
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL9_OFF), 0x3FF); //10bit精度
}
static void tscan_set(void)
{
unsigned int reg = 0x00;
reg = 1500000; /* 间隔时间约0.5S */ //0xFF;
//writel(reg, IO_ADDRESS(LSADC_CTRL2_OFF)); //扫描间隔配置寄存器
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL2_OFF), reg); //扫描间隔配置寄存器
}
static irqreturn_t adc_irq_handle(int irq, void *dev_id)
{
unsigned int reg = 0;
unsigned int data_reg = 0;
/* 清除中断 */
reg = 3;
//writel(reg, IO_ADDRESS(LSADC_CTRL6_OFF));
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL6_OFF), reg);
//printk(KERN_INFO "adc_irq_handle coming...\n");
//reg = readl(IO_ADDRESS(LSADC_CTRL5_OFF));
LSADC_READW(IO_ADDRESS_DEF(LSADC_CTRL5_OFF), reg);
reg = GETREGISTERBIT(reg, LSADC_AUTO_BUSY);
//printk(KERN_INFO "reg: 0x200B0014 -->bit 4 , value: 0x%x\n", reg);
if (reg == 1)
{
//s_adc_data = readl(IO_ADDRESS(LSADC_CTRL3_OFF)) & 0xff;
LSADC_READW(IO_ADDRESS_DEF(LSADC_CTRL11_OFF), data_reg); // 16dv300中改成CTRL11
s_adc_data = data_reg & 0x3ff;
//wake_up_interruptible(&adc_waitq); 读完以后通知应用程序读取数据
}
//adc_stop();
// printk(KERN_INFO "enter interrupt,adc data = %d\n", s_adc_data);
//msleep_interruptible(3000);
//adc_start();
return IRQ_HANDLED;
}
static int __init adc_init(void)
{
unsigned int reg = 0x00;
int ret = 0;
void __iomem *mctrl_vir = NULL;
mctrl_vir = ioremap_nocache((unsigned long)DRV_MUXCTRL_REG63, 4);
if (NULL == mctrl_vir)
{
printk(KERN_ERR "%s, %d, ioremap_nocache 0x%x fail\n", __func__, __LINE__, DRV_MUXCTRL_REG63);
return -1;
}
//writel(reg, IO_ADDRESS(DRV_MUXCTRL_REG63)); //管脚复用设置为ADC
LSADC_READW(mctrl_vir, reg); //管脚复用设置为ADC
reg &= 0xFFFFFFF0;
LSADC_WRITEW(mctrl_vir, reg);
iounmap((void *)mctrl_vir);
s_lsadc_base_vir = ioremap_nocache((unsigned long)LSADC_CRTL_BASE, LSADC_CRTL_SIZE);
if (NULL == s_lsadc_base_vir)
{
printk(KERN_ERR "%s, %d, ioremap_nocache lsadc base reg 0x%x fail\n", __func__, __LINE__, LSADC_CRTL_BASE);
return -1;
}
reg = 0x000080FF;
//writel(reg, IO_ADDRESS(LSADC_CTRL0_OFF)); //LSADC_CTRL配置寄存器
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL0_OFF), reg);
msleep_interruptible(2000);
reg = 0xFC0021FF;
//writel(reg, IO_ADDRESS(LSADC_CTRL0_OFF)); //LSADC_CTRL配置寄存器 8bit mode=连续 ch_vld=A
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL0_OFF), reg);
reg = 0x01;
//writel(reg, IO_ADDRESS(LSADC_CTRL4_OFF)); //使能中断
LSADC_WRITEW(IO_ADDRESS_DEF(LSADC_CTRL4_OFF), reg);
bitwidth_set(); // 精度位宽设置
// tglitch_set();
tscan_set();
adc_start();
//注册中断
ret = request_irq(LSADC_IRQ, adc_irq_handle, IRQF_SHARED, DEVICE_NAME, (void *)&adc_irq_handle);
if (ret)
{
printk(KERN_ERR "IRQ%d error %d\n", LSADC_IRQ, ret);
return ret;
}
return ret;
}
static int __init lsadc_init(void)
{
int ret = 0;
ret = misc_register(&lsadc_miscdev);
if (ret)
{
printk(KERN_ERR "cannot register miscdev on minor=%d (err=%d)\n", LSADC_MINOR, ret);
return ret;
}
if (0 != adc_init())
{
printk(KERN_ERR "adc init fail on minor=%d (err=%d)\n", LSADC_MINOR, ret);
return -1;
}
printk("lsadc driver init successful!\n");
return ret;
}
static void __exit lsadc_exit(void)
{
misc_deregister(&lsadc_miscdev);
adc_stop();
//释放中断
free_irq(LSADC_IRQ, (void *)&adc_irq_handle);
if (NULL != s_lsadc_base_vir)
{
iounmap((void *)s_lsadc_base_vir);
}
printk("lsadc dev exit success!\n");
}
module_init(lsadc_init);
module_exit(lsadc_exit);
MODULE_AUTHOR("Hisilicon");
MODULE_DESCRIPTION("Hisilicon LSAdc Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(LSADC_MINOR);
MODULE_VERSION("HI_VERSION=" OSDRV_MODULE_VERSION_STRING);