Files
mr-library/device/adc/adc.c
MacRsh d4bdfd2ade 1.CH32-V307串口驱动适配DMA。
2.路径移动。
2024-05-08 23:55:02 +08:00

251 lines
7.0 KiB
C

/*
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-11-06 MacRsh First version
*/
#include "../mr-library/include/device/mr_adc.h"
#ifdef MR_USE_ADC
#define _ADC_CHANNEL_IS_VALID(_adc, _channel) \
(((_channel) >= 0) && ((_channel) < (sizeof((_adc)->channels) * 8)))
#define _ADC_CHANNEL_IS_EXISTED(_data, _channel) \
(((_data)->channels & (1 << (_channel))) != 0)
#define _ADC_CHANNEL_IS_ENABLED(_adc, _channel) \
(MR_BIT_IS_SET((_adc)->channels, (1 << (_channel))))
MR_INLINE int _adc_channel_configure_set(struct mr_adc *adc, int channel,
struct mr_adc_config *config)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)adc);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
struct mr_adc_driver_data *data = _MR_DRIVER_DATA_GET(driver);
/* Check if the channel is valid */
if (_ADC_CHANNEL_IS_VALID(adc, channel) == false)
{
return MR_EINVAL;
}
/* Check if the channel is existed */
if ((data != NULL) && (_ADC_CHANNEL_IS_EXISTED(data, channel) == false))
{
return MR_EINVAL;
}
/* Check if the channel is already configured */
if (config->channel_state == _ADC_CHANNEL_IS_ENABLED(adc, channel))
{
return MR_EOK;
}
/* Configure the channel */
int ret = ops->channel_configure(driver, channel, config->channel_state);
if (ret < 0)
{
return ret;
}
/* Enable or disable the channel */
if (config->channel_state == true)
{
MR_BIT_SET(adc->channels, (1 << channel));
} else
{
MR_BIT_CLR(adc->channels, (1 << channel));
}
return MR_EOK;
}
MR_INLINE int _adc_channel_configure_get(struct mr_adc *adc, int channel,
struct mr_adc_config *config)
{
/* Check if the channel is valid */
if (_ADC_CHANNEL_IS_VALID(adc, channel) == false)
{
return MR_EINVAL;
}
/* Get the channel configure */
config->channel_state = _ADC_CHANNEL_IS_ENABLED(adc, channel);
return MR_EOK;
}
static int adc_open(struct mr_device *device)
{
struct mr_adc *adc = (struct mr_adc *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Recover all enabled channels */
for (uint32_t i = 0; i < (sizeof(adc->channels) * 8); i++)
{
if (_ADC_CHANNEL_IS_ENABLED(adc, i) == true)
{
ops->channel_configure(driver, i, true);
}
}
/* Enable ADC */
return ops->configure(driver, true);
}
static int adc_close(struct mr_device *device)
{
struct mr_adc *adc = (struct mr_adc *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Disable all enabled channels */
for (uint32_t i = 0; i < (sizeof(adc->channels) * 8); i++)
{
if (_ADC_CHANNEL_IS_ENABLED(adc, i) == true)
{
/* Just close the channel, without clearing the channel mask, and
* the channel will be restored when opened */
ops->channel_configure(driver, i, false);
}
}
/* Disable ADC */
return ops->configure(driver, false);
}
static ssize_t adc_read(struct mr_device *device, int pos, void *buf,
size_t count)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t *rbuf = (uint32_t *)buf;
ssize_t rcount;
#ifdef MR_USE_ADC_CHECK
struct mr_adc *adc = (struct mr_adc *)device;
/* Check if the channel is enabled */
if ((_ADC_CHANNEL_IS_VALID(adc, pos) == false) ||
(_ADC_CHANNEL_IS_ENABLED(adc, pos) == false))
{
return MR_EINVAL;
}
#endif /* MR_USE_ADC_CHECK */
/* Read data */
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, sizeof(*rbuf));
rcount += sizeof(*rbuf))
{
int ret = ops->read(driver, pos, rbuf);
if (ret < 0)
{
/* If no data is read, return the error code */
return (rcount == 0) ? ret : rcount;
}
rbuf++;
}
/* Return the number of bytes read */
return rcount;
}
static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
{
struct mr_adc *adc = (struct mr_adc *)device;
switch (cmd)
{
case MR_CTRL_SET(MR_CMD_ADC_CHANNEL_STATE):
{
struct mr_adc_config *config = (struct mr_adc_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Set the channel configure */
int ret = _adc_channel_configure_set(adc, pos, config);
if (ret < 0)
{
return ret;
}
return sizeof(*config);
}
case MR_CTRL_GET(MR_CMD_ADC_CHANNEL_STATE):
{
struct mr_adc_config *config = (struct mr_adc_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Get the channel configure */
int ret = _adc_channel_configure_get(adc, pos, config);
if (ret < 0)
{
return ret;
}
return sizeof(*config);
}
case MR_CTRL_GET(MR_CMD_ADC_RESOLUTION):
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_adc_driver_data *data = _MR_DRIVER_DATA_GET(driver);
uint32_t *resolution = (uint32_t *)args;
if (resolution == NULL)
{
return MR_EINVAL;
}
/* Driver does not provide the corresponding information */
if (data == NULL)
{
return MR_EPERM;
}
/* Get the resolution */
*resolution = data->resolution;
return sizeof(*resolution);
}
default:
{
return MR_EPERM;
}
}
}
/**
* @brief This function register an adc.
*
* @param adc The adc.
* @param path The path of the adc.
* @param driver The driver of the adc.
*
* @return The error code.
*/
int mr_adc_register(struct mr_adc *adc, const char *path,
struct mr_driver *driver)
{
MR_ASSERT(adc != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL));
static struct mr_device_ops ops = {.open = adc_open,
.close = adc_close,
.read = adc_read,
.ioctl = adc_ioctl};
/* Initialize the adc */
adc->channels = 0;
/* Register the adc device */
return mr_device_register((struct mr_device *)adc, path, MR_DEVICE_TYPE_ADC,
&ops, driver);
}
#endif /* MR_USE_ADC */