/* * Copyright (c) 2023 TOKITA Hiroshi * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include LOG_MODULE_REGISTER(rpi_pico_temp, CONFIG_SENSOR_LOG_LEVEL); #define DT_DRV_COMPAT raspberrypi_pico_temp struct rpi_pico_temp_config { const struct device *adc; const struct adc_channel_cfg ch_cfg; const int32_t vbe; const int32_t vbe_slope; }; struct rpi_pico_temp_data { struct adc_sequence adc_seq; int16_t sample; }; static int rpi_pico_temp_sample_fetch(const struct device *dev, enum sensor_channel chan) { const struct rpi_pico_temp_config *cfg = dev->config; struct rpi_pico_temp_data *data = dev->data; int rc; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { return -ENOTSUP; } rc = adc_channel_setup(cfg->adc, &cfg->ch_cfg); if (rc) { LOG_DBG("Setup ADC channel %u failed with %d", cfg->ch_cfg.channel_id, rc); return rc; } rc = adc_read(cfg->adc, &data->adc_seq); return rc; } static int rpi_pico_temp_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { const struct rpi_pico_temp_config *cfg = dev->config; struct rpi_pico_temp_data *data = dev->data; int32_t mv = 0; int32_t work; int rc; if (chan != SENSOR_CHAN_DIE_TEMP) { return -ENOTSUP; } mv = data->sample; rc = adc_raw_to_millivolts(adc_ref_internal(cfg->adc), cfg->ch_cfg.gain, data->adc_seq.resolution, &mv); if (rc) { LOG_DBG("adc_raw_to_millivolts() failed %d", rc); return rc; } /* * Calculate CPU temperature from voltage by the equation: * T = 27 - (ADC_Voltage - 0.706)/0.001721 */ work = ((27 * (-cfg->vbe_slope)) - (mv * 1000 - cfg->vbe)); val->val1 = work / (-cfg->vbe_slope); work -= val->val1 * (-cfg->vbe_slope); val->val2 = work * 1000000 / (-cfg->vbe_slope); return 0; } static DEVICE_API(sensor, rpi_pico_temp_driver_api) = { .sample_fetch = rpi_pico_temp_sample_fetch, .channel_get = rpi_pico_temp_channel_get, }; static int rpi_pico_temp_init(const struct device *dev) { const struct rpi_pico_temp_config *cfg = dev->config; if (!device_is_ready(cfg->adc)) { LOG_ERR("Device %s is not ready", cfg->adc->name); return -ENODEV; } adc_set_temp_sensor_enabled(true); return 0; } #define RPI_PICO_TEMP_DEFINE(inst) \ static const struct rpi_pico_temp_config rpi_pico_temp_config_##inst = { \ .adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \ .vbe = DT_INST_PROP(inst, vbe), \ .vbe_slope = DT_INST_PROP(inst, vbe_slope), \ .ch_cfg = \ { \ .gain = ADC_GAIN_1, \ .reference = ADC_REF_INTERNAL, \ .acquisition_time = ADC_ACQ_TIME_DEFAULT, \ .channel_id = DT_INST_IO_CHANNELS_INPUT(inst), \ .differential = 0, \ }, \ }; \ static struct rpi_pico_temp_data rpi_pico_temp_dev_data_##inst = { \ .adc_seq = \ { \ .channels = BIT(DT_INST_IO_CHANNELS_INPUT(inst)), \ .buffer = &rpi_pico_temp_dev_data_##inst.sample, \ .buffer_size = sizeof(rpi_pico_temp_dev_data_##inst.sample), \ .resolution = 12U, \ }, \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, rpi_pico_temp_init, NULL, \ &rpi_pico_temp_dev_data_##inst, &rpi_pico_temp_config_##inst, \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ &rpi_pico_temp_driver_api); DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_TEMP_DEFINE)