110 lines
3.7 KiB
C
110 lines
3.7 KiB
C
/*
|
|
* Copyright (c) 2024 Renato Soma <renatoys08@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT lm35
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/drivers/adc.h>
|
|
#include <zephyr/drivers/sensor.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/logging/log.h>
|
|
|
|
#define LM35_GAIN ADC_GAIN_1
|
|
#define LM35_REF ADC_REF_INTERNAL
|
|
|
|
LOG_MODULE_REGISTER(LM35, CONFIG_SENSOR_LOG_LEVEL);
|
|
|
|
struct lm35_data {
|
|
uint16_t raw;
|
|
};
|
|
|
|
struct lm35_config {
|
|
const struct device *adc;
|
|
uint8_t adc_channel;
|
|
struct adc_sequence adc_seq;
|
|
struct adc_channel_cfg ch_cfg;
|
|
};
|
|
|
|
static int lm35_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
|
{
|
|
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
const struct lm35_config *cfg = dev->config;
|
|
|
|
return adc_read(cfg->adc, &cfg->adc_seq);
|
|
}
|
|
|
|
static int lm35_channel_get(const struct device *dev, enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
int err;
|
|
struct lm35_data *data = dev->data;
|
|
const struct lm35_config *cfg = dev->config;
|
|
int32_t mv = data->raw;
|
|
|
|
err = adc_raw_to_millivolts(adc_ref_internal(cfg->adc), cfg->ch_cfg.gain,
|
|
cfg->adc_seq.resolution, &mv);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
/* LM35 computes linearly 10mV per 1 degree C */
|
|
val->val1 = mv / 10;
|
|
val->val2 = (mv % 10) * 100000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct sensor_driver_api lm35_driver_api = {
|
|
.sample_fetch = lm35_sample_fetch,
|
|
.channel_get = lm35_channel_get,
|
|
};
|
|
|
|
static int lm35_init(const struct device *dev)
|
|
{
|
|
const struct lm35_config *cfg = dev->config;
|
|
|
|
if (!device_is_ready(cfg->adc)) {
|
|
LOG_ERR("ADC device is not ready.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
adc_channel_setup(cfg->adc, &cfg->ch_cfg);
|
|
return 0;
|
|
}
|
|
|
|
#define LM35_INST(inst) \
|
|
static struct lm35_data lm35_data_##inst; \
|
|
\
|
|
static const struct lm35_config lm35_cfg_##inst = { \
|
|
.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \
|
|
.adc_channel = DT_INST_IO_CHANNELS_INPUT(inst), \
|
|
.adc_seq = \
|
|
{ \
|
|
.channels = BIT(DT_INST_IO_CHANNELS_INPUT(inst)), \
|
|
.buffer = &lm35_data_##inst.raw, \
|
|
.buffer_size = sizeof(lm35_data_##inst.raw), \
|
|
.resolution = DT_INST_PROP(inst, resolution), \
|
|
}, \
|
|
.ch_cfg = { \
|
|
.gain = LM35_GAIN, \
|
|
.reference = LM35_REF, \
|
|
.acquisition_time = ADC_ACQ_TIME_DEFAULT, \
|
|
.channel_id = DT_INST_IO_CHANNELS_INPUT(inst), \
|
|
}}; \
|
|
\
|
|
SENSOR_DEVICE_DT_INST_DEFINE(inst, lm35_init, NULL, &lm35_data_##inst, &lm35_cfg_##inst, \
|
|
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &lm35_driver_api);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(LM35_INST)
|