feat:adc adapts to linux iio framework

Signed-off-by: zhangyalei <zhangyalei7@huawei.com>
This commit is contained in:
zhangyalei
2022-03-30 04:03:31 -07:00
parent 42684532df
commit cf98dec7cb
2 changed files with 236 additions and 5 deletions
+18 -5
View File
@@ -75,12 +75,8 @@ struct AdcTester *AdcTesterGet(void)
{
int32_t ret;
static struct AdcTester tester;
static bool hasInit = false;
HDF_LOGE("%s: enter", __func__);
if (hasInit) {
return &tester;
}
ret = AdcTestGetConfig(&tester.config);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read config failed:%d", __func__, ret);
@@ -91,11 +87,20 @@ struct AdcTester *AdcTesterGet(void)
HDF_LOGE("%s: open adc device:%u failed", __func__, tester.config.devNum);
return NULL;
}
hasInit = true;
HDF_LOGI("%s: done", __func__);
return &tester;
}
static void AdcTesterPut(struct AdcTester *tester)
{
if (tester == NULL) {
HDF_LOGE("%s: tester is NULL", __func__);
return;
}
AdcClose(tester->handle);
tester->handle = NULL;
}
int32_t AdcTestRead(void)
{
struct AdcTester *tester = NULL;
@@ -113,11 +118,13 @@ int32_t AdcTestRead(void)
value[i] = 0;
ret = AdcRead(tester->handle, tester->config.channel, &value[i]);
if (ret != HDF_SUCCESS || value[i] >= (1U << tester->config.dataWidth)) {
AdcTesterPut(tester);
HDF_LOGE("%s: read value failed, ret:%d", __func__, ret);
return HDF_ERR_IO;
}
}
AdcTesterPut(tester);
HDF_LOGI("%s: done", __func__);
return HDF_SUCCESS;
}
@@ -142,11 +149,13 @@ static int AdcTestThreadFunc(void *param)
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: AdcRead failed, ret:%d", __func__, ret);
*((int32_t *)param) = 1;
AdcTesterPut(tester);
return HDF_ERR_IO;
}
}
*((int32_t *)param) = 1;
AdcTesterPut(tester);
HDF_LOGI("%s: done", __func__);
return val;
}
@@ -217,6 +226,7 @@ int32_t AdcTestReliability(void)
(void)AdcRead(tester->handle, tester->config.maxChannel + 1, &val);
// invalid val pointer
(void)AdcRead(tester->handle, tester->config.channel, NULL);
AdcTesterPut(tester);
HDF_LOGI("%s: done", __func__);
return HDF_SUCCESS;
}
@@ -247,7 +257,10 @@ static int32_t AdcIfPerformanceTest(void)
useTime = endMs - startMs;
HDF_LOGI("----->interface performance test:[start:%lld(ms) - end:%lld(ms) = %lld (ms)] < 1ms[%d]\r\n",
startMs, endMs, useTime, useTime < 1 ? true : false);
AdcTesterPut(tester);
return HDF_SUCCESS;
}
AdcTesterPut(tester);
return HDF_FAILURE;
}
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "hdf_log.h"
#include "hdf_base.h"
#define ADC_SCALE 32680000
#define ADC_SCALE_DATA 100000
#define ADC_VIRTUAL_RAW_DATA 119
#define REAL_BITS 16
#define STORAGE_BITS 16
#define SHIFT_BITS 0
#define SCAN_MASKS 0xF
#define BUS_NUM 2
enum AdcScanIndex {
ADC_SCAN_VOLTAGE_1,
ADC_SCAN_VOLTAGE_2,
};
struct VirtualAdcDev {
char *name;
int BusNum;
struct mutex lock;
};
static int AdcReadChannelData(struct iio_dev *indioDev, struct iio_chan_spec const *chan, int *val)
{
if (val == NULL) {
HDF_LOGE("%s: val is NULL", __func__);
return -EINVAL;
}
(void)indioDev;
(void)chan;
*val = ADC_VIRTUAL_RAW_DATA;
return IIO_VAL_INT;
}
/*
* val : The value written by the application, val is the integer part if it is a fractional value.
* val2 : The value written by the application, if it is a fractional value, val2 is the fractional part.
*/
static int AdcReadRaw(struct iio_dev *indioDev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct VirtualAdcDev *dev = NULL;
int ret;
if (indioDev == NULL || chan == NULL || val == NULL || val2 == NULL) {
HDF_LOGE("%s: Illegal parameter", __func__);
return -EINVAL;
}
if (ADC_SCALE_DATA == 0) {
HDF_LOGE("%s: ADC_SCALE_DATA is Illegal", __func__);
return -EINVAL;
}
dev = iio_priv(indioDev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
iio_device_claim_direct_mode(indioDev);
mutex_lock(&dev->lock);
ret = AdcReadChannelData(indioDev, chan, val);
mutex_unlock(&dev->lock);
iio_device_release_direct_mode(indioDev);
break;
case IIO_CHAN_INFO_SCALE:
*val = ADC_SCALE / ADC_SCALE_DATA;
*val2 = ADC_SCALE % ADC_SCALE_DATA;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
HDF_LOGE("%s: mask is Illegal", __func__);
ret = -EINVAL;
break;
}
return ret;
}
static const struct iio_chan_spec AdcChannels[] = {
{
.type = IIO_VOLTAGE,
.differential = 1,
.indexed = 1,
.channel = ADC_SCAN_VOLTAGE_1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = ADC_SCAN_VOLTAGE_1,
.scan_type = {
.sign = 's',
.realbits = REAL_BITS,
.storagebits = STORAGE_BITS,
.shift = SHIFT_BITS,
.endianness = IIO_BE,
},
},
{
.type = IIO_VOLTAGE,
.differential = 1,
.indexed = 1,
.channel = ADC_SCAN_VOLTAGE_2,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = ADC_SCAN_VOLTAGE_2,
.scan_type = {
.sign = 's',
.realbits = REAL_BITS,
.storagebits = STORAGE_BITS,
.shift = SHIFT_BITS,
.endianness = IIO_BE,
},
},
};
static const struct iio_info AdcIioInfo = {
.read_raw = AdcReadRaw,
};
static void VirtualAdcDevRelease(struct device *dev)
{
(void)dev;
}
static struct platform_device g_virtualAdcPlatformDevice = {
.name = "virtual_adc_dev",
.id = -1,
.dev = {
.release = VirtualAdcDevRelease,
}
};
static int VirtualAdcPlatformProbe(struct platform_device *pdev)
{
struct VirtualAdcDev *adcInfo = NULL;
struct iio_dev *indioDev = NULL;
int ret;
indioDev = devm_iio_device_alloc(&pdev->dev, sizeof(*adcInfo));
if (!indioDev) {
HDF_LOGE("%s: malloc iio_dev fail", __func__);
return -ENOMEM;
}
adcInfo = iio_priv(indioDev);
adcInfo->name = "virtual-adc-3516";
adcInfo->BusNum = BUS_NUM;
indioDev->name = KBUILD_MODNAME;
indioDev->channels = AdcChannels;
indioDev->num_channels = ARRAY_SIZE(AdcChannels);
indioDev->available_scan_masks = SCAN_MASKS;
indioDev->info = &AdcIioInfo;
indioDev->modes = INDIO_DIRECT_MODE;
platform_set_drvdata(pdev, indioDev);
ret = iio_device_register(indioDev);
if (ret < 0) {
HDF_LOGE("%s: iio device register fail", __func__);
return ret;
}
return HDF_SUCCESS;
}
static int VirtualAdcPlatformRemove(struct platform_device *pdev)
{
struct iio_dev *indioDev = NULL;
indioDev = platform_get_drvdata(pdev);
if (indioDev == NULL) {
HDF_LOGE("%s: iio device is NULL", __func__);
return -EINVAL;
}
iio_device_unregister(indioDev);
platform_set_drvdata(pdev, NULL);
return HDF_SUCCESS;
}
static struct platform_driver g_virtualAdcPlatformDriver = {
.driver = {
.name = "virtual_adc_dev",
.owner = THIS_MODULE,
},
.probe = VirtualAdcPlatformProbe,
.remove = VirtualAdcPlatformRemove,
};
static int __init VirtualAdcInit(void)
{
int ret;
ret = platform_device_register(&g_virtualAdcPlatformDevice);
if (ret == 0) {
ret = platform_driver_register(&g_virtualAdcPlatformDriver);
}
return ret;
}
static void __exit VirtualAdcExit(void)
{
platform_device_unregister(&g_virtualAdcPlatformDevice);
platform_driver_unregister(&g_virtualAdcPlatformDriver);
}
module_init(VirtualAdcInit);
module_exit(VirtualAdcExit);