| /* |
| * Copyright (c) 2022, Maxmillion McLaughlin |
| * Copyright (c) 2020, SER Consulting LLC / Steven Riedl |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT microchip_mcp9600 |
| |
| #include <zephyr/device.h> |
| #include <zephyr/drivers/i2c.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/logging/log.h> |
| |
| LOG_MODULE_REGISTER(MCP9600, CONFIG_SENSOR_LOG_LEVEL); |
| |
| #define MCP9600_REG_TEMP_HOT 0x00 |
| |
| #define MCP9600_REG_TEMP_DIFF 0x01 |
| #define MCP9600_REG_TEMP_COLD 0x02 |
| #define MCP9600_REG_RAW_ADC 0x03 |
| |
| #define MCP9600_REG_STATUS 0x04 |
| |
| #define MCP9600_REG_TC_CONFIG 0x05 |
| #define MCP9600_REG_DEV_CONFIG 0x06 |
| |
| #define MCP9600_REG_A1_CONFIG 0x08 |
| #define MCP9600_REG_A2_CONFIG 0x09 |
| #define MCP9600_REG_A3_CONFIG 0x0A |
| #define MCP9600_REG_A4_CONFIG 0x0B |
| |
| #define MCP9600_A1_HYST 0x0C |
| #define MCP9600_A2_HYST 0x0D |
| #define MCP9600_A3_HYST 0x0E |
| #define MCP9600_A4_HYST 0x0F |
| |
| #define MCP9600_A1_LIMIT 0x10 |
| #define MCP9600_A2_LIMIT 0x11 |
| #define MCP9600_A3_LIMIT 0x12 |
| #define MCP9600_A4_LIMIT 0x13 |
| |
| #define MCP9600_REG_ID_REVISION 0x20 |
| |
| struct mcp9600_data { |
| int32_t temp; |
| }; |
| |
| struct mcp9600_config { |
| const struct i2c_dt_spec bus; |
| }; |
| |
| static int mcp9600_reg_read(const struct device *dev, uint8_t start, uint8_t *buf, int size) |
| { |
| const struct mcp9600_config *cfg = dev->config; |
| |
| return i2c_burst_read_dt(&cfg->bus, start, buf, size); |
| } |
| |
| static int mcp9600_sample_fetch(const struct device *dev, enum sensor_channel chan) |
| { |
| struct mcp9600_data *data = dev->data; |
| uint8_t buf[2]; |
| int ret; |
| |
| if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) { |
| LOG_ERR("Unsupported sensor channel"); |
| return -ENOTSUP; |
| } |
| |
| /* read signed 16 bit double-buffered register value */ |
| ret = mcp9600_reg_read(dev, MCP9600_REG_TEMP_HOT, buf, sizeof(buf)); |
| if (ret < 0) { |
| data->temp = 1; |
| return ret; |
| } |
| |
| /* device's hot junction register is a signed int */ |
| data->temp = (int32_t)(int16_t)(buf[0] << 8) | buf[1]; |
| |
| /* 0.0625C resolution per LSB */ |
| data->temp *= 62500; |
| |
| return 0; |
| } |
| |
| static int mcp9600_channel_get(const struct device *dev, enum sensor_channel chan, |
| struct sensor_value *val) |
| { |
| struct mcp9600_data *data = dev->data; |
| |
| if (chan != SENSOR_CHAN_AMBIENT_TEMP) { |
| return -ENOTSUP; |
| } |
| |
| if (data->temp == 1) { |
| return -EINVAL; |
| } |
| |
| val->val1 = data->temp / 1000000; |
| val->val2 = data->temp % 1000000; |
| |
| return 0; |
| } |
| |
| static const struct sensor_driver_api mcp9600_api = { |
| .sample_fetch = mcp9600_sample_fetch, |
| .channel_get = mcp9600_channel_get, |
| }; |
| |
| static int mcp9600_init(const struct device *dev) |
| { |
| const struct mcp9600_config *cfg = dev->config; |
| uint8_t buf[2]; |
| int ret; |
| |
| if (!i2c_is_ready_dt(&cfg->bus)) { |
| LOG_ERR("mcp9600 i2c bus %s not ready", cfg->bus.bus->name); |
| return -ENODEV; |
| } |
| |
| ret = mcp9600_reg_read(dev, MCP9600_REG_ID_REVISION, buf, sizeof(buf)); |
| LOG_DBG("id: 0x%02x version: 0x%02x", buf[0], buf[1]); |
| |
| return ret; |
| } |
| |
| #define MCP9600_DEFINE(id) \ |
| static struct mcp9600_data mcp9600_data_##id; \ |
| \ |
| static const struct mcp9600_config mcp9600_config_##id = { \ |
| .bus = I2C_DT_SPEC_INST_GET(id), \ |
| }; \ |
| \ |
| SENSOR_DEVICE_DT_INST_DEFINE(id, mcp9600_init, NULL, &mcp9600_data_##id, \ |
| &mcp9600_config_##id, POST_KERNEL, \ |
| CONFIG_SENSOR_INIT_PRIORITY, &mcp9600_api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(MCP9600_DEFINE) |