| /* |
| * Copyright (c) 2023 Google LLC |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/drivers/adc.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/pm/device.h> |
| #include <zephyr/pm/device_runtime.h> |
| #include <zephyr/logging/log.h> |
| #include "ntc_thermistor.h" |
| |
| LOG_MODULE_REGISTER(NTC_THERMISTOR, CONFIG_SENSOR_LOG_LEVEL); |
| |
| struct ntc_thermistor_data { |
| struct k_mutex mutex; |
| int16_t raw; |
| int16_t sample_val; |
| }; |
| |
| struct ntc_thermistor_config { |
| const struct adc_dt_spec adc_channel; |
| const struct ntc_config ntc_cfg; |
| }; |
| |
| static int ntc_thermistor_sample_fetch(const struct device *dev, enum sensor_channel chan) |
| { |
| struct ntc_thermistor_data *data = dev->data; |
| const struct ntc_thermistor_config *cfg = dev->config; |
| enum pm_device_state pm_state; |
| int32_t val_mv; |
| int res; |
| struct adc_sequence sequence = { |
| .options = NULL, |
| .buffer = &data->raw, |
| .buffer_size = sizeof(data->raw), |
| .calibrate = false, |
| }; |
| |
| (void)pm_device_state_get(dev, &pm_state); |
| if (pm_state != PM_DEVICE_STATE_ACTIVE) { |
| return -EIO; |
| } |
| |
| k_mutex_lock(&data->mutex, K_FOREVER); |
| |
| adc_sequence_init_dt(&cfg->adc_channel, &sequence); |
| res = adc_read(cfg->adc_channel.dev, &sequence); |
| if (!res) { |
| val_mv = data->raw; |
| res = adc_raw_to_millivolts_dt(&cfg->adc_channel, &val_mv); |
| data->sample_val = val_mv; |
| } |
| |
| k_mutex_unlock(&data->mutex); |
| |
| return res; |
| } |
| |
| static int ntc_thermistor_channel_get(const struct device *dev, enum sensor_channel chan, |
| struct sensor_value *val) |
| { |
| struct ntc_thermistor_data *data = dev->data; |
| const struct ntc_thermistor_config *cfg = dev->config; |
| uint32_t ohm; |
| int32_t temp; |
| |
| switch (chan) { |
| case SENSOR_CHAN_AMBIENT_TEMP: |
| ohm = ntc_get_ohm_of_thermistor(&cfg->ntc_cfg, data->sample_val); |
| temp = ntc_get_temp_mc(&cfg->ntc_cfg.type, ohm); |
| val->val1 = temp / 1000; |
| val->val2 = (temp % 1000) * 1000; |
| break; |
| default: |
| return -ENOTSUP; |
| } |
| return 0; |
| } |
| |
| static const struct sensor_driver_api ntc_thermistor_driver_api = { |
| .sample_fetch = ntc_thermistor_sample_fetch, |
| .channel_get = ntc_thermistor_channel_get, |
| }; |
| |
| static int ntc_thermistor_init(const struct device *dev) |
| { |
| const struct ntc_thermistor_config *cfg = dev->config; |
| int err; |
| |
| if (!adc_is_ready_dt(&cfg->adc_channel)) { |
| LOG_ERR("ADC controller device is not ready\n"); |
| return -ENODEV; |
| } |
| |
| err = adc_channel_setup_dt(&cfg->adc_channel); |
| if (err < 0) { |
| LOG_ERR("Could not setup channel err(%d)\n", err); |
| return err; |
| } |
| |
| #ifdef CONFIG_PM_DEVICE_RUNTIME |
| pm_device_init_suspended(dev); |
| |
| err = pm_device_runtime_enable(dev); |
| if (err) { |
| LOG_ERR("Failed to enable runtime power management"); |
| return err; |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| #ifdef CONFIG_PM_DEVICE |
| static int ntc_thermistor_pm_action(const struct device *dev, enum pm_device_action action) |
| { |
| switch (action) { |
| case PM_DEVICE_ACTION_TURN_ON: |
| case PM_DEVICE_ACTION_RESUME: |
| case PM_DEVICE_ACTION_TURN_OFF: |
| case PM_DEVICE_ACTION_SUSPEND: |
| return 0; |
| default: |
| return -ENOTSUP; |
| } |
| } |
| #endif |
| |
| #define NTC_THERMISTOR_DEFINE0(inst, id, _comp, _n_comp) \ |
| static struct ntc_thermistor_data ntc_thermistor_driver_##id##inst; \ |
| \ |
| static const struct ntc_thermistor_config ntc_thermistor_cfg_##id##inst = { \ |
| .adc_channel = ADC_DT_SPEC_INST_GET(inst), \ |
| .ntc_cfg = \ |
| { \ |
| .pullup_uv = DT_INST_PROP(inst, pullup_uv), \ |
| .pullup_ohm = DT_INST_PROP(inst, pullup_ohm), \ |
| .pulldown_ohm = DT_INST_PROP(inst, pulldown_ohm), \ |
| .connected_positive = DT_INST_PROP(inst, connected_positive), \ |
| .type = { \ |
| .comp = _comp, \ |
| .n_comp = _n_comp, \ |
| }, \ |
| }, \ |
| }; \ |
| \ |
| PM_DEVICE_DT_INST_DEFINE(inst, ntc_thermistor_pm_action); \ |
| \ |
| SENSOR_DEVICE_DT_INST_DEFINE( \ |
| inst, ntc_thermistor_init, PM_DEVICE_DT_INST_GET(inst), \ |
| &ntc_thermistor_driver_##id##inst, &ntc_thermistor_cfg_##id##inst, POST_KERNEL, \ |
| CONFIG_SENSOR_INIT_PRIORITY, &ntc_thermistor_driver_api); |
| |
| #define NTC_THERMISTOR_DEFINE(inst, id, comp) \ |
| NTC_THERMISTOR_DEFINE0(inst, id, comp, ARRAY_SIZE(comp)) |
| |
| /* ntc-thermistor-generic */ |
| #define DT_DRV_COMPAT ntc_thermistor_generic |
| |
| #define NTC_THERMISTOR_GENERIC_DEFINE(inst) \ |
| static const uint32_t comp_##inst[] = DT_INST_PROP(inst, zephyr_compensation_table); \ |
| NTC_THERMISTOR_DEFINE0(inst, DT_DRV_COMPAT, (struct ntc_compensation *)comp_##inst, \ |
| ARRAY_SIZE(comp_##inst) / 2) |
| |
| DT_INST_FOREACH_STATUS_OKAY(NTC_THERMISTOR_GENERIC_DEFINE) |
| |
| /* epcos,b57861s0103a039 */ |
| #undef DT_DRV_COMPAT |
| #define DT_DRV_COMPAT epcos_b57861s0103a039 |
| |
| static __unused const struct ntc_compensation comp_epcos_b57861s0103a039[] = { |
| { -25, 146676 }, |
| { -15, 78875 }, |
| { -5, 44424 }, |
| { 5, 26075 }, |
| { 15, 15881 }, |
| { 25, 10000 }, |
| { 35, 6488 }, |
| { 45, 4326 }, |
| { 55, 2956 }, |
| { 65, 2066 }, |
| { 75, 1474 }, |
| { 85, 1072 }, |
| { 95, 793 }, |
| { 105, 596 }, |
| { 115, 454 }, |
| { 125, 351 }, |
| }; |
| |
| DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, |
| comp_epcos_b57861s0103a039) |
| |
| /* murata,ncp15wb473 */ |
| #undef DT_DRV_COMPAT |
| #define DT_DRV_COMPAT murata_ncp15wb473 |
| |
| static __unused const struct ntc_compensation comp_murata_ncp15wb473[] = { |
| { -25, 655802 }, |
| { -15, 360850 }, |
| { -5, 206463 }, |
| { 5, 122259 }, |
| { 15, 74730 }, |
| { 25, 47000 }, |
| { 35, 30334 }, |
| { 45, 20048 }, |
| { 55, 13539 }, |
| { 65, 9328 }, |
| { 75, 6544 }, |
| { 85, 4674 }, |
| { 95, 3388 }, |
| { 105, 2494 }, |
| { 115, 1860 }, |
| { 125, 1406 }, |
| }; |
| |
| DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, |
| comp_murata_ncp15wb473) |
| |
| /* tdk,ntcg163jf103ft1 */ |
| #undef DT_DRV_COMPAT |
| #define DT_DRV_COMPAT tdk_ntcg163jf103ft1 |
| |
| static __unused const struct ntc_compensation comp_tdk_ntcg163jf103ft1[] = { |
| { -25, 86560 }, |
| { -15, 53460 }, |
| { -5, 33930 }, |
| { 5, 22070 }, |
| { 15, 14700 }, |
| { 25, 10000 }, |
| { 35, 6942 }, |
| { 45, 4911 }, |
| { 55, 3536 }, |
| { 65, 2588 }, |
| { 75, 1924 }, |
| { 85, 1451 }, |
| { 95, 1110 }, |
| { 105, 860 }, |
| { 115, 674 }, |
| { 125, 534 }, |
| }; |
| |
| DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, |
| comp_tdk_ntcg163jf103ft1) |