1 /* ist8310.c - Driver for Isentek IST8310 Geomagnetic Sensor */
2 
3 /*
4  * Copyright (c) 2023 NXP Semiconductors
5  * Copyright (c) 2023 Cognipilot Foundation
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/sys/byteorder.h>
11 #include <zephyr/logging/log.h>
12 #include "ist8310.h"
13 
14 LOG_MODULE_REGISTER(IST8310, CONFIG_SENSOR_LOG_LEVEL);
15 
ist8310_bus_check(const struct device * dev)16 static inline int ist8310_bus_check(const struct device *dev)
17 {
18 	const struct ist8310_config *cfg = dev->config;
19 
20 	return cfg->bus_io->check(&cfg->bus);
21 }
22 
ist8310_reg_read(const struct device * dev,uint8_t start,uint8_t * buf,int size)23 static inline int ist8310_reg_read(const struct device *dev, uint8_t start, uint8_t *buf, int size)
24 {
25 	const struct ist8310_config *cfg = dev->config;
26 
27 	return cfg->bus_io->read(&cfg->bus, start, buf, size);
28 }
29 
ist8310_reg_write(const struct device * dev,uint8_t reg,uint8_t val)30 static inline int ist8310_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
31 {
32 	const struct ist8310_config *cfg = dev->config;
33 
34 	return cfg->bus_io->write(&cfg->bus, reg, val);
35 }
36 
ist8310_sample_fetch(const struct device * dev,enum sensor_channel chan)37 static int ist8310_sample_fetch(const struct device *dev, enum sensor_channel chan)
38 {
39 
40 	struct ist8310_data *drv_data = dev->data;
41 	uint8_t buff[6];
42 
43 	if (ist8310_reg_read(dev, IST8310_STATUS_REGISTER1, (uint8_t *)buff, 1) < 0) {
44 		LOG_ERR("failed to read status register 1");
45 		return -EIO;
46 	}
47 
48 	if ((buff[0] & STAT1_DRDY) == 0) {
49 		LOG_ERR("Data not ready");
50 		if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
51 			LOG_ERR("failed to set single");
52 			return -EIO;
53 		}
54 		return -EIO;
55 	}
56 
57 	if (ist8310_reg_read(dev, IST8310_OUTPUT_VALUE_X_L, (uint8_t *)buff, 6) < 0) {
58 		LOG_ERR("failed to read mag values");
59 		return -EIO;
60 	}
61 
62 	drv_data->sample_x = (sys_le16_to_cpu(*(uint16_t *)&buff[0]));
63 	drv_data->sample_y = (sys_le16_to_cpu(*(uint16_t *)&buff[2]));
64 	drv_data->sample_z = (sys_le16_to_cpu(*(uint16_t *)&buff[4]));
65 
66 	if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
67 		LOG_ERR("failed to set single");
68 		return -EIO;
69 	}
70 
71 	return 0;
72 }
73 
ist8310_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)74 static int ist8310_channel_get(const struct device *dev, enum sensor_channel chan,
75 			       struct sensor_value *val)
76 {
77 	struct ist8310_data *drv_data = dev->data;
78 
79 	switch (chan) {
80 	case SENSOR_CHAN_MAGN_X:
81 		sensor_value_from_float(val, drv_data->sample_x * (1.0f / 1320));
82 		break;
83 	case SENSOR_CHAN_MAGN_Y:
84 		sensor_value_from_float(val, drv_data->sample_y * (1.0f / 1320));
85 		break;
86 	case SENSOR_CHAN_MAGN_Z:
87 		sensor_value_from_float(val, drv_data->sample_z * (1.0f / 1320));
88 		break;
89 	case SENSOR_CHAN_MAGN_XYZ:
90 		sensor_value_from_float(val, drv_data->sample_x * (1.0f / 1320));
91 		sensor_value_from_float(val + 1, drv_data->sample_y * (1.0f / 1320));
92 		sensor_value_from_float(val + 2, drv_data->sample_z * (1.0f / 1320));
93 		break;
94 	default:
95 		return -EINVAL;
96 	}
97 
98 	return 0;
99 }
100 
101 static const struct sensor_driver_api ist8310_api_funcs = {
102 	.sample_fetch = ist8310_sample_fetch,
103 	.channel_get = ist8310_channel_get,
104 };
105 
ist8310_init_chip(const struct device * dev)106 static int ist8310_init_chip(const struct device *dev)
107 {
108 	uint8_t reg;
109 
110 	/* Read chip ID (can only be read in sleep mode)*/
111 	if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
112 		LOG_ERR("failed reading chip id");
113 		return -EIO;
114 	}
115 
116 	if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
117 		LOG_ERR("failed reading chip id");
118 		return -EIO;
119 	}
120 
121 	if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
122 		LOG_ERR("failed reading chip id");
123 		return -EIO;
124 	}
125 
126 	if (reg != IST8310_WHO_AM_I_VALUE) {
127 		LOG_ERR("invalid chip id 0x%x", reg);
128 		return -EIO;
129 	}
130 
131 	if (ist8310_reg_read(dev, IST8310_CONTROL_REGISTER2, &reg, 1) < 0) {
132 		LOG_ERR("failed reading chip reg2");
133 		return -EIO;
134 	}
135 
136 	reg &= ~CTRL2_SRST;
137 
138 	if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER2, reg) < 0) {
139 		LOG_ERR("failed to set REG2 to %d", reg);
140 		return -EIO;
141 	}
142 
143 	k_sleep(K_MSEC(3));
144 
145 	if (ist8310_reg_read(dev, IST8310_CONTROL_REGISTER3, &reg, 1) < 0) {
146 		LOG_ERR("failed reading chip reg3");
147 		return -EIO;
148 	}
149 
150 	reg |= X_16BIT | Y_16BIT | Z_16BIT;
151 
152 	if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER3, reg) < 0) {
153 		LOG_ERR("failed to set REG3 to %d", reg);
154 		return -EIO;
155 	}
156 
157 	if (ist8310_reg_write(dev, IST8310_AVG_REGISTER, XZ_16TIMES_CLEAR | Y_16TIMES_CLEAR) < 0) {
158 		LOG_ERR("failed to set AVG");
159 		return -EIO;
160 	}
161 
162 	if (ist8310_reg_write(dev, IST8310_AVG_REGISTER, XZ_16TIMES_SET | Y_16TIMES_SET) < 0) {
163 		LOG_ERR("failed to set AVG");
164 		return -EIO;
165 	}
166 
167 	if (ist8310_reg_write(dev, IST8310_PDCNTL_REGISTER, PULSE_NORMAL) < 0) {
168 		LOG_ERR("failed to set AVG");
169 		return -EIO;
170 	}
171 
172 	k_sleep(K_MSEC(3));
173 
174 	if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
175 		LOG_ERR("failed to set single");
176 		return -EIO;
177 	}
178 
179 	return 0;
180 }
181 
ist8310_init(const struct device * dev)182 static int ist8310_init(const struct device *dev)
183 {
184 	int err = 0;
185 
186 	err = ist8310_bus_check(dev);
187 	if (err < 0) {
188 		LOG_DBG("bus check failed: %d", err);
189 		return err;
190 	}
191 
192 	if (ist8310_init_chip(dev) < 0) {
193 		LOG_ERR("failed to initialize chip");
194 		return -EIO;
195 	}
196 
197 	return 0;
198 }
199 
200 /* Initializes a struct ist8310_config for an instance on an I2C bus. */
201 #define IST8310_CONFIG_I2C(inst)                                                                   \
202 	.bus.i2c = I2C_DT_SPEC_INST_GET(inst), .bus_io = &ist8310_bus_io_i2c,
203 
204 #define IST8310_BUS_CFG(inst)                                                                      \
205 	COND_CODE_1(DT_INST_ON_BUS(inst, i2c), (IST8310_CONFIG_I2C(inst)),                         \
206 		    (IST8310_CONFIG_SPI(inst)))
207 
208 /*
209  * Main instantiation macro, which selects the correct bus-specific
210  * instantiation macros for the instance.
211  */
212 #define IST8310_DEFINE(inst)                                                                       \
213 	static struct ist8310_data ist8310_data_##inst;                                            \
214 	static const struct ist8310_config ist8310_config_##inst = {IST8310_BUS_CFG(inst)};        \
215                                                                                                    \
216 	SENSOR_DEVICE_DT_INST_DEFINE(inst, ist8310_init, NULL, &ist8310_data_##inst,               \
217 				     &ist8310_config_##inst, POST_KERNEL,                          \
218 				     CONFIG_SENSOR_INIT_PRIORITY, &ist8310_api_funcs);
219 
220 /* Create the struct device for every status "okay" node in the devicetree. */
221 DT_INST_FOREACH_STATUS_OKAY(IST8310_DEFINE)
222