1 /* ST Microelectronics IIS3DHHC accelerometer senor
2 *
3 * Copyright (c) 2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/iis3dhhc.pdf
9 */
10
11 #define DT_DRV_COMPAT st_iis3dhhc
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/device.h>
15 #include <zephyr/init.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/logging/log.h>
18
19 #include "iis3dhhc.h"
20
21 LOG_MODULE_REGISTER(IIS3DHHC, CONFIG_SENSOR_LOG_LEVEL);
22
iis3dhhc_sample_fetch(const struct device * dev,enum sensor_channel chan)23 static int iis3dhhc_sample_fetch(const struct device *dev,
24 enum sensor_channel chan)
25 {
26 struct iis3dhhc_data *data = dev->data;
27 int16_t raw_accel[3];
28
29 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
30
31 iis3dhhc_acceleration_raw_get(data->ctx, raw_accel);
32 data->acc[0] = raw_accel[0];
33 data->acc[1] = raw_accel[1];
34 data->acc[2] = raw_accel[2];
35
36 return 0;
37 }
38
iis3dhhc_convert(struct sensor_value * val,int16_t raw_val)39 static inline void iis3dhhc_convert(struct sensor_value *val,
40 int16_t raw_val)
41 {
42 int64_t micro_ms2;
43
44 /* Convert to m/s^2 */
45 micro_ms2 = ((iis3dhhc_from_lsb_to_mg(raw_val) * SENSOR_G) / 1000LL);
46 val->val1 = micro_ms2 / 1000000LL;
47 val->val2 = micro_ms2 % 1000000LL;
48 }
49
iis3dhhc_channel_get_acc(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)50 static inline void iis3dhhc_channel_get_acc(const struct device *dev,
51 enum sensor_channel chan,
52 struct sensor_value *val)
53 {
54 int i;
55 uint8_t ofs_start, ofs_stop;
56 struct iis3dhhc_data *iis3dhhc = dev->data;
57 struct sensor_value *pval = val;
58
59 switch (chan) {
60 case SENSOR_CHAN_ACCEL_X:
61 ofs_start = ofs_stop = 0U;
62 break;
63 case SENSOR_CHAN_ACCEL_Y:
64 ofs_start = ofs_stop = 1U;
65 break;
66 case SENSOR_CHAN_ACCEL_Z:
67 ofs_start = ofs_stop = 2U;
68 break;
69 default:
70 ofs_start = 0U; ofs_stop = 2U;
71 break;
72 }
73
74 for (i = ofs_start; i <= ofs_stop ; i++) {
75 iis3dhhc_convert(pval++, iis3dhhc->acc[i]);
76 }
77 }
78
iis3dhhc_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)79 static int iis3dhhc_channel_get(const struct device *dev,
80 enum sensor_channel chan,
81 struct sensor_value *val)
82 {
83 switch (chan) {
84 case SENSOR_CHAN_ACCEL_X:
85 case SENSOR_CHAN_ACCEL_Y:
86 case SENSOR_CHAN_ACCEL_Z:
87 case SENSOR_CHAN_ACCEL_XYZ:
88 iis3dhhc_channel_get_acc(dev, chan, val);
89 return 0;
90 default:
91 LOG_DBG("Channel not supported");
92 break;
93 }
94
95 return -ENOTSUP;
96 }
97
iis3dhhc_odr_set(const struct device * dev,const struct sensor_value * val)98 static int iis3dhhc_odr_set(const struct device *dev,
99 const struct sensor_value *val)
100 {
101 struct iis3dhhc_data *data = dev->data;
102 iis3dhhc_norm_mod_en_t en;
103
104 switch (val->val1) {
105 case 0:
106 en = IIS3DHHC_POWER_DOWN;
107 break;
108 case 1000:
109 en = IIS3DHHC_1kHz1;
110 break;
111 default:
112 return -EIO;
113 }
114
115 if (iis3dhhc_data_rate_set(data->ctx, en)) {
116 LOG_DBG("failed to set sampling rate");
117 return -EIO;
118 }
119
120 return 0;
121 }
122
iis3dhhc_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)123 static int iis3dhhc_attr_set(const struct device *dev,
124 enum sensor_channel chan,
125 enum sensor_attribute attr,
126 const struct sensor_value *val)
127 {
128 if (chan != SENSOR_CHAN_ALL) {
129 LOG_WRN("attr_set() not supported on this channel.");
130 return -ENOTSUP;
131 }
132
133 switch (attr) {
134 case SENSOR_ATTR_SAMPLING_FREQUENCY:
135 return iis3dhhc_odr_set(dev, val);
136 default:
137 LOG_DBG("operation not supported.");
138 return -ENOTSUP;
139 }
140
141 return 0;
142 }
143
144 static DEVICE_API(sensor, iis3dhhc_api_funcs) = {
145 .attr_set = iis3dhhc_attr_set,
146 .sample_fetch = iis3dhhc_sample_fetch,
147 .channel_get = iis3dhhc_channel_get,
148 #if CONFIG_IIS3DHHC_TRIGGER
149 .trigger_set = iis3dhhc_trigger_set,
150 #endif
151 };
152
iis3dhhc_init_chip(const struct device * dev)153 static int iis3dhhc_init_chip(const struct device *dev)
154 {
155 struct iis3dhhc_data *data = dev->data;
156 uint8_t chip_id, rst;
157
158 if (iis3dhhc_device_id_get(data->ctx, &chip_id) < 0) {
159 LOG_DBG("Failed reading chip id");
160 return -EIO;
161 }
162
163 if (chip_id != IIS3DHHC_ID) {
164 LOG_DBG("Invalid chip id 0x%x", chip_id);
165 return -EIO;
166 }
167
168 /*
169 * Restore default configuration
170 */
171 iis3dhhc_reset_set(data->ctx, PROPERTY_ENABLE);
172 do {
173 iis3dhhc_reset_get(data->ctx, &rst);
174 } while (rst);
175
176 /* Enable Block Data Update */
177 iis3dhhc_block_data_update_set(data->ctx, PROPERTY_ENABLE);
178
179 /* Set Output Data Rate */
180 #ifdef CONFIG_IIS3DHHC_NORM_MODE
181 iis3dhhc_data_rate_set(data->ctx, 1);
182 #else
183 iis3dhhc_data_rate_set(data->ctx, 0);
184 #endif
185
186 /* Enable temperature compensation */
187 iis3dhhc_offset_temp_comp_set(data->ctx, PROPERTY_ENABLE);
188
189 return 0;
190 }
191
iis3dhhc_init(const struct device * dev)192 static int iis3dhhc_init(const struct device *dev)
193 {
194 const struct iis3dhhc_config * const config = dev->config;
195
196 if (!spi_is_ready_dt(&config->spi)) {
197 LOG_ERR("SPI bus is not ready");
198 return -ENODEV;
199 }
200
201 config->bus_init(dev);
202
203 if (iis3dhhc_init_chip(dev) < 0) {
204 LOG_DBG("Failed to initialize chip");
205 return -EIO;
206 }
207
208 #ifdef CONFIG_IIS3DHHC_TRIGGER
209 if (config->int_gpio.port) {
210 if (iis3dhhc_init_interrupt(dev) < 0) {
211 LOG_ERR("Failed to initialize interrupt.");
212 return -EIO;
213 }
214 }
215 #endif
216
217 return 0;
218 }
219
220 #define IIS3DHHC_DEFINE(inst) \
221 static struct iis3dhhc_data iis3dhhc_data_##inst; \
222 \
223 static const struct iis3dhhc_config iis3dhhc_config_##inst = { \
224 IF_ENABLED(CONFIG_IIS3DHHC_TRIGGER, \
225 (COND_CODE_1(CONFIG_IIS3DHHC_DRDY_INT1, \
226 (.int_gpio = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, \
227 irq_gpios, \
228 0),), \
229 (.int_gpio = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, \
230 irq_gpios, \
231 1),)))) \
232 \
233 .bus_init = iis3dhhc_spi_init, \
234 .spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | \
235 SPI_MODE_CPOL | SPI_MODE_CPHA | \
236 SPI_WORD_SET(8), 0U), \
237 }; \
238 \
239 SENSOR_DEVICE_DT_INST_DEFINE(inst, iis3dhhc_init, NULL, \
240 &iis3dhhc_data_##inst, &iis3dhhc_config_##inst, POST_KERNEL, \
241 CONFIG_SENSOR_INIT_PRIORITY, &iis3dhhc_api_funcs); \
242
243 DT_INST_FOREACH_STATUS_OKAY(IIS3DHHC_DEFINE)
244