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