rt-thread-official/bsp/gkipc/drivers/drv_adc.c

238 lines
5.9 KiB
C

/*
* File : drv_adc.c
* This file is part of GK710X BSP for RT-Thread distribution.
*
* Copyright (c) 2017 GOKE Microelectronics Co., Ltd.
* All rights reserved
*
* 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; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Visit http://www.goke.com to get contact with Goke.
*
* Change Logs:
* Date Author Notes
*/
#include "drv_adc.h"
#ifdef RT_USING_ADC
#include "gtypes.h"
#include "gd_adc.h"
#include "platform.h"
#include <rtdef.h>
#include <rtthread.h>
#define GK_TEST_ADC
#define IOCTL_GET_ADC_DATA 1
#define IOCTL_ADC_POWER_DOWN 0xff
#define ADC_WRAP_BASE (0xf1200000)
#define ADC_IRQn (23)
#define ADC_MAX_CONTROLLER (1)
#define ADC_STATUS_COLESD (0)
#define ADC_STATUS_OPEN (1)
static rt_err_t gk_adc_read_data(struct wrap_adc_obj *adc, rt_uint32_t channel,
rt_uint32_t *buf)
{
rt_err_t ret = RT_EOK;
ret = GD_ADC_Read((GD_HANDLE*)&(adc->handle), buf);
return ret;
}
static rt_err_t gk_adc_init(rt_device_t dev)
{
rt_err_t ret = RT_EOK;
ret = (rt_err_t)GD_ADC_Init();
return ret;
}
static rt_err_t gk_adc_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_err_t ret = RT_EOK;
GD_ADC_OPEN_PARAMS_S openParams;
struct wrap_adc_obj *adc_pri = (struct wrap_adc_obj *)dev->user_data;
rt_memset(&openParams, 0, sizeof(GD_ADC_OPEN_PARAMS_S));
openParams.channel = adc_pri->active_channel_no;
ret = (rt_err_t)GD_ADC_Open(&openParams, (GD_HANDLE*)&(adc_pri->handle));
return ret;
}
static rt_err_t gk_adc_close(rt_device_t dev)
{
rt_err_t ret = RT_EOK;
struct wrap_adc_obj *adc_pri = (struct wrap_adc_obj *)dev->user_data;
ret = (rt_err_t)GD_ADC_Close((GD_HANDLE*)(adc_pri->handle));
return ret;
}
static rt_err_t gk_adc_ioctl(rt_device_t dev, int cmd, void *arg)
{
rt_uint32_t control_reg;
struct wrap_adc_obj *adc_pri = (struct wrap_adc_obj *)dev->user_data;
rt_uint32_t ad_data;
ADC_INFO *adc_info = (ADC_INFO *)arg;
rt_err_t ret;
switch (cmd)
{
case ADC_CMD_READ_RAW_DATA:
ret = gk_adc_read_data(adc_pri, adc_info->channel, &ad_data);
if (ret != RT_EOK)
{
return ret;
}
adc_info->adc_data = ad_data;
break;
case ADC_CMD_DISABLE:
gk_adc_close(dev);
break;
default:
rt_kprintf("wrong para...\n");
return RT_EIO;
}
return RT_EOK;
}
int gk_adc_probe(void *priv_data)
{
rt_device_t adc_dev;
// check if the hw is init already...
// caution this is a read only data...if the driver want to use.malloc and
// copy it..
struct wrap_adc_obj *adc_obj = (struct wrap_adc_obj *)priv_data;
if (adc_obj->init_flag == ADC_INIT_ALREADY) return RT_EFULL;
// malloc a rt device..
adc_dev = RT_KERNEL_MALLOC(sizeof(struct rt_device));
if (!adc_dev)
{
return RT_ENOMEM;
}
rt_memset(adc_dev, 0, sizeof(struct rt_device));
rt_kprintf("id:%d\n", adc_obj->id);
// bind rtdev to obj data...
// caution ...this is used to free mem when exit....
// free step:1:get adc obj...2:free adc_obj->rt_dev->user_data..3:free
// adc_obj->rt_dev 4:adc_obj->rt_dev = NULL
adc_obj->rt_dev = adc_dev;
// malloc a private data adc use only...copy data from platform...
struct wrap_adc_obj *adc_pri =
RT_KERNEL_MALLOC(sizeof(struct wrap_adc_obj));
if (!adc_pri)
{
RT_KERNEL_FREE(adc_dev);
return RT_ENOMEM;
}
// copy platform data to pri data..
rt_memcpy(adc_pri, adc_obj, sizeof(struct wrap_adc_obj));
rt_kprintf("id:%d\n", adc_pri->id);
// bind pri data to rt_adc_dev...
adc_dev->user_data = (void *)adc_pri;
adc_dev->open = gk_adc_open;
adc_dev->close = gk_adc_close;
adc_dev->control = gk_adc_ioctl;
adc_dev->init = gk_adc_init;
adc_dev->type = RT_Device_Class_Miscellaneous;
rt_device_register(adc_dev, "adc", RT_DEVICE_FLAG_RDWR);
adc_obj->init_flag = ADC_INIT_ALREADY;
return RT_EOK;
}
int gk_adc_exit(void *priv_data)
{
struct wrap_adc_obj *adc_obj = (struct wrap_adc_obj *)priv_data;
struct wrap_adc_obj *adc_pri = adc_obj->rt_dev->user_data;
RT_KERNEL_FREE(adc_obj->rt_dev->user_data);
adc_obj->rt_dev->user_data = RT_NULL;
RT_KERNEL_FREE(adc_obj->rt_dev);
adc_obj->rt_dev = RT_NULL;
GD_ADC_Exit();
return 0;
}
struct gk_platform_driver adc_driver_ops = {
.name = "adc", .probe = gk_adc_probe, .remove = gk_adc_exit,
};
void rt_hw_adc_init(void)
{
gk_platform_driver_init(&adc_driver_ops);
}
#ifdef GK_TEST_ADC
int gk_adc_test(void)
{
rt_device_t adc_dev;
ADC_INFO info;
info.channel = 0;
info.adc_data = 0;
adc_dev = rt_device_find("adc");
if (!adc_dev)
{
rt_kprintf("cann't find the adc dev\n");
return -1;
}
adc_dev->init(adc_dev);
adc_dev->open(adc_dev, 0);
while (1)
{
adc_dev->control(adc_dev, ADC_CMD_READ_RAW_DATA, &info);
rt_kprintf("channel:%d, data:0x%x\n", info.channel, info.adc_data);
}
return 0;
}
#endif
#ifdef RT_USING_FINSH
#include <finsh.h>
#ifdef GK_TEST_ADC
FINSH_FUNCTION_EXPORT(gk_adc_test, gk_adc_test);
#endif
#endif
#endif