查看: 1474|回复: 3

[hi3516] hi3516 adc源码

[复制链接]
发表于 2018-5-2 18:22:59 | 显示全部楼层 |阅读模式
hi3516夜视功能中,需要使用3516的adc功能,但官方SDK中并未提供相应的用例。于是,自己编写了一个,提供给大家参考学习。其中包含adc驱动和测试代码。

  1. /* hi_adc.c
  2. *[code]#include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/printk.h>
  5. #include <linux/version.h>
  6. #include <linux/of_platform.h>

  7. #define OSDRV_MODULE_VERSION_STRING "HISI_adc @HiMPP"

  8. extern int adc_init(void);
  9. extern void adc_exit(void);

  10. extern unsigned int adc_irq;
  11. extern volatile void *pAdcRegBase;

  12. static int hi_adc_probe(struct platform_device *pdev)
  13. {   
  14.     struct resource *mem;
  15.     adc_irq = platform_get_irq(pdev, 0);
  16.     if (adc_irq <= 0) {
  17.             dev_err(&pdev->dev, "cannot find adc IRQ\n");
  18.     }
  19.    
  20.     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  21.     /* 物理地址映射为虚拟地址 */
  22.     pAdcRegBase = devm_ioremap_resource(&pdev->dev, mem);
  23.     if (IS_ERR((const void*)pAdcRegBase))
  24.     {
  25.         return PTR_ERR((const void*)pAdcRegBase);
  26.     }

  27.     return adc_init();
  28. }

  29. static int hi_adc_remove(struct platform_device *pdev)
  30. {
  31.     adc_exit();
  32.     return 0;
  33. }

  34. static const struct of_device_id hi_adc_match[] = {
  35.     { .compatible = "hisilicon,hi_adc" },
  36.     {},
  37. };

  38. static struct platform_driver hi_adc_driver = {
  39.     .probe  = hi_adc_probe,
  40.     .remove = hi_adc_remove,
  41.     .driver =  { .name = "hi_adc",
  42.                 .of_match_table = hi_adc_match,
  43.                },
  44. };
  45. module_platform_driver(hi_adc_driver);

  46. MODULE_LICENSE("GPL");
  47. MODULE_AUTHOR("Hisilicon/Cmiot");
  48. MODULE_DESCRIPTION("Hisilicon Infrared remoter(HIIR11) Device Driver");
  49. MODULE_VERSION("HI_VERSION=" OSDRV_MODULE_VERSION_STRING);

  50. [code]#include <stdio.h>
  51. #include <fcntl.h>
  52. #include <unistd.h>
  53. #include <stdlib.h>
  54. #include <ctype.h>
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #include <sys/ioctl.h>
  58. #include <string.h>
  59. #include <errno.h>
  60. int main(int argc, char *argv)
  61. {
  62.         int fd  = -1;
  63.         const char *dev_name = "/dev/adc";
  64.     int len;
  65.     char buffer[4]= {0};
  66.    
  67.     fd = open("/dev/adc", 0);
  68.     if (fd < 0)
  69.     {
  70.                 perror("open ADC device:");
  71.                 return -1;
  72.         }

  73.         for(;;)
  74.     {
  75.             len = read(fd, buffer, sizeof(buffer));
  76.             if (len > 0)
  77.         {
  78.                     buffer[len] = '\0';
  79.                     int value = -1;
  80.                     sscanf(buffer, "%d", &value);
  81.                     printf("ADC Value: %d\n", value);
  82.             }
  83.         else
  84.         {
  85.                     perror("read ADC device:");
  86.                     return 1;
  87.             }
  88.             usleep(500* 1000);
  89.    }
  90.        
  91.         close(fd);
  92.     return 0;
  93. }

复制代码
[/code]
* Copyright (c) 2012 Hisilicon Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program;
*
* History:
*      2012.05.15 create this file <pengkang@huawei.com>
*      2012.11.20 add temp select method  <sunny.liucan@huawei.com>
*/

#include "hi_osal.h"
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/sched.h>
#define HIADC_DEVICE_NAME "adc"
//#define HIDEBUG
#define ADC_IRQ                (19)

#ifndef NULL
#define NULL  ((void *)0)
#endif
#define ADC_TIME_OUT  HZ * 5    // 队列等待时间

#define OSDRV_MODULE_VERSION_STRING "HISI_ADC @Hi3516CV100"

#define LSADC_REG_BASE_ADDR             0x120E0000
#define LSADC_CTRL0              0x0000
#define LSADC_CTRL4              0x0010    /* 中断控制寄存器 */
#define LSADC_CTRL5              0x0014    /* 中断状态寄存器 */
#define LSADC_CTRL6              0x0018    /* 中断清除寄存器 */
#define LSADC_CTRL7              0x001C    /* start配置寄存器 */
#define LSADC_CTRL9              0x0024    /* 精度控制寄存器,初始值为3ff,10位 */
#define LSADC_CTRL11             0x002C    /* LSADC数据保存寄存器1 */

static osal_spinlock_t adc_spin_lock;
static osal_mutex_t hiadc_lock;
static osal_dev_t *adc_dev  = 0;
static int flag = 0;
volatile void *pAdcRegBase = NULL;
unsigned int adc_irq = 0;
osal_wait_t adc_irq_wait;

#define HIADC_REG(x)        (LSADC_REG_BASE_ADDR + (x))
#define IO_ADC_ADDRESS(x)   ((unsigned long)(pAdcRegBase) + ((x)-(LSADC_REG_BASE_ADDR)))
#define hiadc_readl(x)      osal_readl(IO_ADC_ADDRESS(HIADC_REG(x)))
#define hiadc_writel(v,x)   osal_writel(v, IO_ADC_ADDRESS(HIADC_REG(x)))

static int hi_adc_open(void *private_data)
{
    osal_wait_init(&adc_irq_wait);
    /* 设置扫描精度10位,单通道 */
    hiadc_writel(0xff0201ff, LSADC_CTRL0);
    /* 使能中断adc中断       */
    hiadc_writel(0x1, LSADC_CTRL4);
        return 0;
}

static int hi_adc_close(void *private_data)
{
    osal_wait_destory(&adc_irq_wait);
        return 0;
}

int hiadc_WaitConditionCallBack(void *pParam)
{
    return (flag == 1);
}

static int hi_adc_read(char *buf, int count, long *f_pos, void *private_data)
{
    int adc_value = 0;
    int result = 0;
    int len = 0;
    char adc_str[20];

    /* 开始转换 */
    hiadc_writel(0xf, LSADC_CTRL7);
   
    /* 等待转换完成 */
    result = osal_wait_event(&adc_irq_wait,hiadc_WaitConditionCallBack, NULL);
    if (result != 0)
    {
        osal_printk("convert timeout. \n");
        return -EFAULT;
    }
    /* 读取保存adc结果 */
    adc_value = hiadc_readl(LSADC_CTRL11);
    osal_printk("adc value is:%d.\n", adc_value);

    len = sprintf(adc_str, "%d\n", adc_value);
    osal_memcpy((void*)buf, (void*)adc_str, len);

    /* 清中断 */
    hiadc_writel(0x1, LSADC_CTRL6);
    flag = 0;
    return len;
   
}

static struct osal_fileops hi_adc_fops =
{
    .read = hi_adc_read,
    .open = hi_adc_open,
    .release = hi_adc_close,
};

static int sar_adc_interrupt(int irq, void *dev_id)
{
    /* 读取一次中断标志 */
    flag = hiadc_readl(LSADC_CTRL5) | (1 << 0);
    osal_printk("adc convert finish,flag is %d. \n", flag);

    /* 清中断 */
    hiadc_writel(0x1, LSADC_CTRL6);

    /* 唤醒读操作 */
    osal_wakeup(&adc_irq_wait);
    return OSAL_IRQ_HANDLED;
}

int adc_init(void)
{
    int ret = 0;
    /* 如果未定义中断号,直接使用默认LSADC中断 */
    if (adc_irq <= 0)
    {
        adc_irq = ADC_IRQ;   
    }

    /* 如果未设置物理地址,则直接映射IO端口 */
    if (pAdcRegBase == NULL)
    {
        pAdcRegBase = (volatile void *)osal_ioremap_nocache(LSADC_REG_BASE_ADDR, 0x100);
        if (!pAdcRegBase)
        {
            osal_printk("osal_ioremap_nocache err. \n");
            return -1;
        }
    }

    ret = osal_spin_lock_init(&adc_spin_lock);
        if (0 != ret)
        {
                osal_printk("failed to init spin lock.\n");
        return -1;
    }

        ret = osal_mutex_init(&hiadc_lock);
        if (0 != ret)
        {
                osal_printk("failed to init mutex.\n");
        goto ADC_INIT_FAIL0;
    }

    /* 分配设备节点内存 */
    adc_dev = osal_createdev(HIADC_DEVICE_NAME);
    if (NULL == adc_dev)
        {
            osal_printk("cretate adc device failed.\n");
        goto ADC_INIT_FAIL1;
        }

    /* 注册设备 */
        adc_dev->fops = &hi_adc_fops;
    adc_dev->minor = 255;
        ret = osal_registerdevice(adc_dev);
        if (0 != ret)
        {
                osal_printk("adc device register failed!\n");
        goto ADC_INIT_FAIL2;
    }

    /* 申请adc中断 */
        ret = osal_request_irq(adc_irq, sar_adc_interrupt, NULL, HIADC_DEVICE_NAME,  &sar_adc_interrupt);
        if (ret != 0)
        {
                osal_printk("hi3516CV300 adc: failed to register irq %d, (ret %d)\n", adc_irq, ret);
                goto ADC_INIT_FAIL3;
        }
        osal_printk("hi_adc init sucess, adc irq is:%d\n", adc_irq);
    return 0;
       
ADC_INIT_FAIL3:
        osal_deregisterdevice(adc_dev);
       
ADC_INIT_FAIL2:
    osal_destroydev(adc_dev);

ADC_INIT_FAIL1:
    osal_mutex_destory(&hiadc_lock);

ADC_INIT_FAIL0:
    osal_spin_lock_destory(&adc_spin_lock);
    return -1;
}

void adc_exit(void)
{
    osal_free_irq(adc_irq, &sar_adc_interrupt);
        osal_deregisterdevice(adc_dev);
        osal_destroydev(adc_dev);
        osal_mutex_destory(&hiadc_lock);
        osal_spin_lock_destory(&adc_spin_lock);
    osal_printk("hi_adc exit sucess.\n");
    return;
}

[/code]
发表于 2018-5-8 22:06:56 | 显示全部楼层
我帮不上忙,但是多谢分享
发表于 2018-10-23 13:30:28 | 显示全部楼层
非常感谢分享
发表于 2018-12-10 17:29:45 | 显示全部楼层
非常感谢,学习了!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

© 2008-2017 当前位置 易百纳技术社区论坛 返回 易百纳技术社区 ( 苏ICP备14036084 )   Powered by Discuz! X3.1
快速回复 返回顶部 返回列表