1 /*
2 * Copyright (c) 2017-2019 Phytec Messtechnik GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT panasonic_amg88xx
8
9 #include <string.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/drivers/sensor.h>
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/logging/log.h>
19
20 #include "amg88xx.h"
21
22 LOG_MODULE_REGISTER(AMG88XX, CONFIG_SENSOR_LOG_LEVEL);
23
amg88xx_sample_fetch(const struct device * dev,enum sensor_channel chan)24 static int amg88xx_sample_fetch(const struct device *dev,
25 enum sensor_channel chan)
26 {
27 struct amg88xx_data *drv_data = dev->data;
28 const struct amg88xx_config *config = dev->config;
29
30 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP);
31
32 if (i2c_burst_read_dt(&config->i2c,
33 AMG88XX_OUTPUT_BASE,
34 (uint8_t *)drv_data->sample,
35 sizeof(drv_data->sample))) {
36 return -EIO;
37 }
38
39 return 0;
40 }
41
amg88xx_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)42 static int amg88xx_channel_get(const struct device *dev,
43 enum sensor_channel chan,
44 struct sensor_value *val)
45 {
46 struct amg88xx_data *drv_data = dev->data;
47 size_t len = ARRAY_SIZE(drv_data->sample);
48
49 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
50 return -ENOTSUP;
51 }
52
53 for (size_t idx = 0; idx < len; idx++) {
54 /* fix negative values */
55 if (drv_data->sample[idx] & (1 << 11)) {
56 drv_data->sample[idx] |= 0xF000;
57 }
58 val[idx].val1 = (((int32_t)drv_data->sample[idx]) *
59 AMG88XX_TREG_LSB_SCALING) / 1000000;
60 val[idx].val2 = (((int32_t)drv_data->sample[idx]) *
61 AMG88XX_TREG_LSB_SCALING) % 1000000;
62 }
63
64 return 0;
65 }
66
amg88xx_init_device(const struct device * dev)67 static int amg88xx_init_device(const struct device *dev)
68 {
69 const struct amg88xx_config *config = dev->config;
70 uint8_t tmp;
71
72 if (i2c_reg_read_byte_dt(&config->i2c,
73 AMG88XX_PCLT, &tmp)) {
74 LOG_ERR("Failed to read Power mode");
75 return -EIO;
76 }
77
78 LOG_DBG("Power mode 0x%02x", tmp);
79 if (tmp != AMG88XX_PCLT_NORMAL_MODE) {
80 if (i2c_reg_write_byte_dt(&config->i2c,
81 AMG88XX_PCLT,
82 AMG88XX_PCLT_NORMAL_MODE)) {
83 return -EIO;
84 }
85 k_busy_wait(AMG88XX_WAIT_MODE_CHANGE_US);
86 }
87
88 if (i2c_reg_write_byte_dt(&config->i2c,
89 AMG88XX_RST, AMG88XX_RST_INITIAL_RST)) {
90 return -EIO;
91 }
92
93 k_busy_wait(AMG88XX_WAIT_INITIAL_RESET_US);
94
95 if (i2c_reg_write_byte_dt(&config->i2c,
96 AMG88XX_FPSC, AMG88XX_FPSC_10FPS)) {
97 return -EIO;
98 }
99
100 LOG_DBG("");
101
102 return 0;
103 }
104
amg88xx_init(const struct device * dev)105 int amg88xx_init(const struct device *dev)
106 {
107 const struct amg88xx_config *config = dev->config;
108
109 if (!device_is_ready(config->i2c.bus)) {
110 LOG_ERR("Bus device is not ready");
111 return -EINVAL;
112 }
113
114 if (amg88xx_init_device(dev) < 0) {
115 LOG_ERR("Failed to initialize device!");
116 return -EIO;
117 }
118
119
120 #ifdef CONFIG_AMG88XX_TRIGGER
121 if (amg88xx_init_interrupt(dev) < 0) {
122 LOG_ERR("Failed to initialize interrupt!");
123 return -EIO;
124 }
125 #endif
126
127 return 0;
128 }
129
130 static DEVICE_API(sensor, amg88xx_driver_api) = {
131 #ifdef CONFIG_AMG88XX_TRIGGER
132 .attr_set = amg88xx_attr_set,
133 .trigger_set = amg88xx_trigger_set,
134 #endif
135 .sample_fetch = amg88xx_sample_fetch,
136 .channel_get = amg88xx_channel_get,
137 };
138
139 #define AMG88XX_DEFINE(inst) \
140 static struct amg88xx_data amg88xx_data_##inst; \
141 \
142 static const struct amg88xx_config amg88xx_config_##inst = { \
143 .i2c = I2C_DT_SPEC_INST_GET(inst), \
144 IF_ENABLED(CONFIG_AMG88XX_TRIGGER, \
145 (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),)) \
146 }; \
147 \
148 SENSOR_DEVICE_DT_INST_DEFINE(inst, amg88xx_init, NULL, \
149 &amg88xx_data_##inst, &amg88xx_config_##inst, POST_KERNEL, \
150 CONFIG_SENSOR_INIT_PRIORITY, &amg88xx_driver_api); \
151
152 DT_INST_FOREACH_STATUS_OKAY(AMG88XX_DEFINE)
153