1 /*
2 * Copyright 2023 Daniel DeGrasse <daniel@degrasse.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT microchip_tcn75a
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(tcn75a, CONFIG_SENSOR_LOG_LEVEL);
11
12 #include "tcn75a.h"
13
tcn75a_sample_fetch(const struct device * dev,enum sensor_channel chan)14 int tcn75a_sample_fetch(const struct device *dev, enum sensor_channel chan)
15 {
16 const struct tcn75a_config *config = dev->config;
17 struct tcn75a_data *data = dev->data;
18 int ret;
19 uint8_t temp_reg = TCN75A_TEMP_REG;
20 uint8_t rx_buf[2];
21 uint8_t adc_conf[2] = {TCN75A_CONFIG_REG, 0x0};
22 /* This sensor only supports ambient temperature */
23 if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_AMBIENT_TEMP)) {
24 return -ENOTSUP;
25 }
26
27 if (config->oneshot_mode) {
28 /* Oneshot mode, requires one shot bit to be set in config register */
29 adc_conf[1] = TCN75A_CONFIG_ONEDOWN;
30 ret = i2c_write_dt(&config->i2c_spec, adc_conf, 2);
31 if (ret < 0) {
32 return ret;
33 }
34 }
35
36 /* Fetch a sample from the 2 byte ambient temperature register */
37 ret = i2c_write_read_dt(&config->i2c_spec, &temp_reg, sizeof(temp_reg),
38 rx_buf, sizeof(rx_buf));
39 if (ret < 0) {
40 return ret;
41 }
42
43 data->temp_sample = sys_get_be16(rx_buf);
44 LOG_DBG("Raw sample: 0x%04x", data->temp_sample);
45
46 return ret;
47 }
48
tcn75a_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)49 static int tcn75a_channel_get(const struct device *dev, enum sensor_channel chan,
50 struct sensor_value *val)
51 {
52 struct tcn75a_data *data = dev->data;
53 uint32_t temp_lsb;
54
55 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
56 return -ENOTSUP;
57 }
58
59 /* Convert fixed point to sensor value */
60 val->val1 = data->temp_sample >> TCN75A_TEMP_MSB_POS;
61 temp_lsb = (data->temp_sample & TCN75A_TEMP_LSB_MASK);
62 val->val2 = TCN75A_FIXED_PT_TO_SENSOR(temp_lsb);
63 return 0;
64 }
65
66 static const struct sensor_driver_api tcn75a_api = {
67 .sample_fetch = &tcn75a_sample_fetch,
68 .channel_get = &tcn75a_channel_get,
69 #ifdef CONFIG_TCN75A_TRIGGER
70 .attr_get = &tcn75a_attr_get,
71 .attr_set = &tcn75a_attr_set,
72 .trigger_set = &tcn75a_trigger_set,
73 #endif
74 };
75
tcn75a_init(const struct device * dev)76 static int tcn75a_init(const struct device *dev)
77 {
78 const struct tcn75a_config *config = dev->config;
79 uint8_t adc_conf[2] = {TCN75A_CONFIG_REG, 0x0};
80
81 if (!i2c_is_ready_dt(&config->i2c_spec)) {
82 LOG_ERR("I2C bus is not ready");
83 return -ENODEV;
84 }
85
86 /* Set user selected resolution */
87 adc_conf[1] |= TCN75A_CONFIG_RES(config->resolution);
88
89 if (config->oneshot_mode) {
90 if (adc_conf[1] != 0) {
91 /* Oneshot mode only supports 9 bit resolution */
92 LOG_ERR("Oneshot mode requires 9 bit resolution");
93 return -ENODEV;
94 }
95 adc_conf[1] |= TCN75A_CONFIG_SHUTDOWN;
96 }
97
98 #ifdef CONFIG_TCN75A_TRIGGER
99 /* If user supplies an ALERT gpio, assume they want trigger support. */
100 if (config->alert_gpios.port != NULL) {
101 int ret;
102
103 if (config->oneshot_mode) {
104 LOG_ERR("Oneshot mode not supported with trigger");
105 return -ENODEV;
106 }
107
108 ret = tcn75a_trigger_init(dev);
109 if (ret < 0) {
110 return ret;
111 }
112 }
113 #endif
114
115 return i2c_write_dt(&config->i2c_spec, adc_conf, 2);
116 }
117
118 #ifdef CONFIG_TCN75A_TRIGGER
119 #define TCN75A_TRIGGER(n) .alert_gpios = GPIO_DT_SPEC_INST_GET_OR(n, alert_gpios, {}),
120 #else
121 #define TCN75A_TRIGGER(n)
122 #endif
123
124 #define TCN75A_INIT(n) \
125 static struct tcn75a_data tcn75a_data_##n; \
126 static const struct tcn75a_config tcn75a_config_##n = { \
127 .i2c_spec = I2C_DT_SPEC_INST_GET(n), \
128 .resolution = DT_INST_ENUM_IDX(n, resolution), \
129 .oneshot_mode = DT_INST_PROP(n, oneshot_mode), \
130 TCN75A_TRIGGER(n) \
131 }; \
132 SENSOR_DEVICE_DT_INST_DEFINE(n, &tcn75a_init, NULL, &tcn75a_data_##n, &tcn75a_config_##n, \
133 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &tcn75a_api);
134
135 DT_INST_FOREACH_STATUS_OKAY(TCN75A_INIT)
136