xref: /minix3/minix/drivers/sensors/sht21/sht21.c (revision 3f82ac6a4e188419336747098d0d6616cd2f3d3d)
1433d6423SLionel Sambuc /* Driver for the SHT21 Relative Humidity and Temperature Sensor */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include <minix/ds.h>
4433d6423SLionel Sambuc #include <minix/drivers.h>
5433d6423SLionel Sambuc #include <minix/i2c.h>
6433d6423SLionel Sambuc #include <minix/i2cdriver.h>
7433d6423SLionel Sambuc #include <minix/chardriver.h>
8433d6423SLionel Sambuc #include <minix/log.h>
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include <time.h>
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc /*
13433d6423SLionel Sambuc  * Device Commands
14433d6423SLionel Sambuc  */
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc /*
17433d6423SLionel Sambuc  * The trigger commands start a measurement. 'Hold' ties up the bus while the
18433d6423SLionel Sambuc  * measurement is being performed while 'no hold' requires the driver to poll
19433d6423SLionel Sambuc  * the chip until the data is ready. Hold is faster and requires less message
20433d6423SLionel Sambuc  * passing while no hold frees up the bus while the measurement is in progress.
21433d6423SLionel Sambuc  * The worst case conversion times are 85 ms for temperature and 29 ms for
22433d6423SLionel Sambuc  * humidity. Typical conversion times are about 75% of the worst case times.
23433d6423SLionel Sambuc  *
24433d6423SLionel Sambuc  * The driver uses the 'hold' versions of the trigger commands.
25433d6423SLionel Sambuc  */
26433d6423SLionel Sambuc #define CMD_TRIG_T_HOLD 0xe3
27433d6423SLionel Sambuc #define CMD_TRIG_RH_HOLD 0xe5
28433d6423SLionel Sambuc #define CMD_TRIG_T_NOHOLD 0xf3
29433d6423SLionel Sambuc #define CMD_TRIG_RH_NOHOLD 0xf5
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc /* Read and write the user register contents */
32433d6423SLionel Sambuc #define CMD_WR_USR_REG 0xe6
33433d6423SLionel Sambuc #define CMD_RD_USR_REG 0xe7
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc /* Resets the chip */
36433d6423SLionel Sambuc #define CMD_SOFT_RESET 0xfe
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc /* Status bits included in the measurement need to be masked in calculation */
39433d6423SLionel Sambuc #define STATUS_BITS_MASK 0x0003
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc /*
42433d6423SLionel Sambuc  * The user register has some reserved bits that the device changes over
43433d6423SLionel Sambuc  * time. The driver must preserve the value of those bits when writing to
44433d6423SLionel Sambuc  * the user register.
45433d6423SLionel Sambuc  */
46433d6423SLionel Sambuc #define USR_REG_RESERVED_MASK ((1<<3)|(1<<4)|(1<<5))
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc /* End of Battery flag is set when the voltage drops below 2.25V. */
49433d6423SLionel Sambuc #define USR_REG_EOB_MASK (1<<6)
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc /* When powered up and communicating, the register should have only the
52433d6423SLionel Sambuc  * 'Disable OTP Reload' bit set
53433d6423SLionel Sambuc  */
54433d6423SLionel Sambuc #define EXPECTED_PWR_UP_TEST_VAL (1<<1)
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc /* Define some constants for the different sensor types on the chip. */
57433d6423SLionel Sambuc enum sht21_sensors
58433d6423SLionel Sambuc { SHT21_T, SHT21_RH };
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
61433d6423SLionel Sambuc static struct log log = {
62433d6423SLionel Sambuc 	.name = "sht21",
63433d6423SLionel Sambuc 	.log_level = LEVEL_INFO,
64433d6423SLionel Sambuc 	.log_func = default_log
65433d6423SLionel Sambuc };
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc /* device slave address is fixed at 0x40 */
68433d6423SLionel Sambuc static i2c_addr_t valid_addrs[2] = {
69433d6423SLionel Sambuc 	0x40, 0x00
70433d6423SLionel Sambuc };
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc /* Buffer to store output string returned when reading from device file. */
73433d6423SLionel Sambuc #define BUFFER_LEN 64
74433d6423SLionel Sambuc char buffer[BUFFER_LEN + 1];
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc /* the bus that this device is on (counting starting at 1) */
77433d6423SLionel Sambuc static uint32_t bus;
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc /* slave address of the device */
80433d6423SLionel Sambuc static i2c_addr_t address;
81433d6423SLionel Sambuc 
82433d6423SLionel Sambuc /* endpoint for the driver for the bus itself. */
83433d6423SLionel Sambuc static endpoint_t bus_endpoint;
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc /* Sampling causes self-heating. To limit the self-heating to < 0.1C, the
86433d6423SLionel Sambuc  * data sheet suggests limiting sampling to 2 samples per second. Since
87433d6423SLionel Sambuc  * the driver samples temperature and relative humidity at the same time,
88433d6423SLionel Sambuc  * it's measure function does at most 1 pair of samples per second. It uses
89433d6423SLionel Sambuc  * this timestamp to see if a measurement was taken less than 1 second ago.
90433d6423SLionel Sambuc  */
91433d6423SLionel Sambuc static time_t last_sample_time = 0;
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc /*
94433d6423SLionel Sambuc  * Cache temperature and relative humidity readings. These values are returned
95433d6423SLionel Sambuc  * when the last_sample_time == current_time to keep the chip activity below
96433d6423SLionel Sambuc  * 10% to help prevent self-heating.
97433d6423SLionel Sambuc  */
98433d6423SLionel Sambuc static int32_t cached_t = 0.0;
99433d6423SLionel Sambuc static int32_t cached_rh = 0.0;
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc /*
102433d6423SLionel Sambuc  * An 8-bit CRC is used to validate the readings.
103433d6423SLionel Sambuc  */
104433d6423SLionel Sambuc #define CRC8_POLYNOMIAL 0x131
105433d6423SLionel Sambuc #define CRC8_INITIAL_CRC 0x00
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc /* main driver functions */
108433d6423SLionel Sambuc static int sht21_init(void);
109433d6423SLionel Sambuc static int sensor_read(enum sht21_sensors sensor, int32_t * measurement);
110433d6423SLionel Sambuc static int measure(void);
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /* CRC functions */
113433d6423SLionel Sambuc static uint8_t crc8(uint8_t crc, uint8_t byte);
114433d6423SLionel Sambuc static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc);
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc /* libchardriver callbacks */
117433d6423SLionel Sambuc static ssize_t sht21_read(devminor_t minor, u64_t position, endpoint_t endpt,
118433d6423SLionel Sambuc     cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
119433d6423SLionel Sambuc static void sht21_other(message * m, int ipc_status);
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc /* Entry points to this driver from libchardriver. */
122433d6423SLionel Sambuc static struct chardriver sht21_tab = {
123433d6423SLionel Sambuc 	.cdr_read	= sht21_read,
124433d6423SLionel Sambuc 	.cdr_other	= sht21_other
125433d6423SLionel Sambuc };
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc /*
128433d6423SLionel Sambuc  * Performs a soft reset and reads the contents of the user register to ensure
129433d6423SLionel Sambuc  * that the chip is in a good state and working properly.
130433d6423SLionel Sambuc  */
131433d6423SLionel Sambuc static int
sht21_init(void)132433d6423SLionel Sambuc sht21_init(void)
133433d6423SLionel Sambuc {
134433d6423SLionel Sambuc 	int r;
135433d6423SLionel Sambuc 	uint8_t usr_reg_val;
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc 	/* Perform a soft-reset */
138433d6423SLionel Sambuc 	r = i2creg_raw_write8(bus_endpoint, address, CMD_SOFT_RESET);
139433d6423SLionel Sambuc 	if (r != OK) {
140433d6423SLionel Sambuc 		return -1;
141433d6423SLionel Sambuc 	}
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc 	/* soft reset takes up to 15 ms to complete. */
144433d6423SLionel Sambuc 	micro_delay(15000);
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	log_debug(&log, "Soft Reset Complete\n");
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	r = i2creg_read8(bus_endpoint, address, CMD_RD_USR_REG, &usr_reg_val);
149433d6423SLionel Sambuc 	if (r != OK) {
150433d6423SLionel Sambuc 		return -1;
151433d6423SLionel Sambuc 	}
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 	/* Check for End of Battery flag. */
154433d6423SLionel Sambuc 	if ((usr_reg_val & USR_REG_EOB_MASK) == USR_REG_EOB_MASK) {
155433d6423SLionel Sambuc 		log_warn(&log, "End of Battery Alarm\n");
156433d6423SLionel Sambuc 		return -1;
157433d6423SLionel Sambuc 	}
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc 	/* Check that the non-reserved bits are in the default state. */
160433d6423SLionel Sambuc 	if ((usr_reg_val & ~USR_REG_RESERVED_MASK) != EXPECTED_PWR_UP_TEST_VAL) {
161433d6423SLionel Sambuc 		log_warn(&log, "USR_REG has non-default values after reset\n");
162433d6423SLionel Sambuc 		log_warn(&log, "Expected 0x%x | Actual 0x%x",
163433d6423SLionel Sambuc 		    EXPECTED_PWR_UP_TEST_VAL,
164433d6423SLionel Sambuc 		    (usr_reg_val & ~USR_REG_RESERVED_MASK));
165433d6423SLionel Sambuc 		return -1;
166433d6423SLionel Sambuc 	}
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc 	return OK;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc /*
172433d6423SLionel Sambuc  * Read from the sensor, check the CRC, convert the ADC value into the final
173433d6423SLionel Sambuc  * representation, and store the result in measurement.
174433d6423SLionel Sambuc  */
175433d6423SLionel Sambuc static int
sensor_read(enum sht21_sensors sensor,int32_t * measurement)176433d6423SLionel Sambuc sensor_read(enum sht21_sensors sensor, int32_t * measurement)
177433d6423SLionel Sambuc {
178433d6423SLionel Sambuc 	int r;
179433d6423SLionel Sambuc 	uint8_t cmd;
180433d6423SLionel Sambuc 	uint16_t val;
181433d6423SLionel Sambuc 	uint8_t bytes[2];
182433d6423SLionel Sambuc 	uint32_t val32;
183433d6423SLionel Sambuc 	uint8_t expected_crc;
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc 	switch (sensor) {
186433d6423SLionel Sambuc 	case SHT21_T:
187433d6423SLionel Sambuc 		cmd = CMD_TRIG_T_HOLD;
188433d6423SLionel Sambuc 		break;
189433d6423SLionel Sambuc 	case SHT21_RH:
190433d6423SLionel Sambuc 		cmd = CMD_TRIG_RH_HOLD;
191433d6423SLionel Sambuc 		break;
192433d6423SLionel Sambuc 	default:
193433d6423SLionel Sambuc 		log_warn(&log, "sensor_read() called with bad sensor type.\n");
194433d6423SLionel Sambuc 		return -1;
195433d6423SLionel Sambuc 	}
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc 	if (measurement == NULL) {
198433d6423SLionel Sambuc 		log_warn(&log, "sensor_read() called with NULL pointer\n");
199433d6423SLionel Sambuc 		return -1;
200433d6423SLionel Sambuc 	}
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc 	r = i2creg_read24(bus_endpoint, address, cmd, &val32);
203433d6423SLionel Sambuc 	if (r != OK) {
204433d6423SLionel Sambuc 		log_warn(&log, "sensor_read() failed (r=%d)\n", r);
205433d6423SLionel Sambuc 		return -1;
206433d6423SLionel Sambuc 	}
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	expected_crc = val32 & 0xff;
209433d6423SLionel Sambuc 	val = (val32 >> 8) & 0xffff;
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc 	bytes[0] = (val >> 8) & 0xff;
212433d6423SLionel Sambuc 	bytes[1] = val & 0xff;
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc 	r = checksum(bytes, 2, expected_crc);
215433d6423SLionel Sambuc 	if (r != OK) {
216433d6423SLionel Sambuc 		return -1;
217433d6423SLionel Sambuc 	}
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc 	val &= ~STATUS_BITS_MASK;	/* clear status bits */
220433d6423SLionel Sambuc 
221433d6423SLionel Sambuc 	log_debug(&log, "Read VAL:0x%x CRC:0x%x\n", val, expected_crc);
222433d6423SLionel Sambuc 
223433d6423SLionel Sambuc 	/* Convert the ADC value to the actual value. */
224433d6423SLionel Sambuc 	if (cmd == CMD_TRIG_T_HOLD) {
225433d6423SLionel Sambuc 		*measurement = (int32_t)
226433d6423SLionel Sambuc 		    ((-46.85 + ((175.72 / 65536) * ((float) val))) * 1000.0);
227433d6423SLionel Sambuc 		log_debug(&log, "Measured Temperature %d mC\n", *measurement);
228433d6423SLionel Sambuc 	} else if (cmd == CMD_TRIG_RH_HOLD) {
229433d6423SLionel Sambuc 		*measurement =
230433d6423SLionel Sambuc 		    (int32_t) ((-6.0 +
231433d6423SLionel Sambuc 			((125.0 / 65536) * ((float) val))) * 1000.0);
232433d6423SLionel Sambuc 		log_debug(&log, "Measured Humidity %d m%%\n", *measurement);
233433d6423SLionel Sambuc 	}
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc 	return OK;
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc static int
measure(void)239433d6423SLionel Sambuc measure(void)
240433d6423SLionel Sambuc {
241433d6423SLionel Sambuc 	int r;
242433d6423SLionel Sambuc 	time_t sample_time;
243433d6423SLionel Sambuc 	int32_t t, rh;
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc 	log_debug(&log, "Taking a measurement...");
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 	sample_time = time(NULL);
248433d6423SLionel Sambuc 	if (sample_time == last_sample_time) {
249433d6423SLionel Sambuc 		log_debug(&log, "measure() called too soon, using cache.\n");
250433d6423SLionel Sambuc 		return OK;
251433d6423SLionel Sambuc 	}
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 	r = sensor_read(SHT21_T, &t);
254433d6423SLionel Sambuc 	if (r != OK) {
255433d6423SLionel Sambuc 		return -1;
256433d6423SLionel Sambuc 	}
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 	r = sensor_read(SHT21_RH, &rh);
259433d6423SLionel Sambuc 	if (r != OK) {
260433d6423SLionel Sambuc 		return -1;
261433d6423SLionel Sambuc 	}
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	/* save measured values */
264433d6423SLionel Sambuc 	cached_t = t;
265433d6423SLionel Sambuc 	cached_rh = rh;
266433d6423SLionel Sambuc 	last_sample_time = time(NULL);
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc 	log_debug(&log, "Measurement completed\n");
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc 	return OK;
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc /*
274433d6423SLionel Sambuc  * Return an updated checksum for the given crc and byte.
275433d6423SLionel Sambuc  */
276433d6423SLionel Sambuc static uint8_t
crc8(uint8_t crc,uint8_t byte)277433d6423SLionel Sambuc crc8(uint8_t crc, uint8_t byte)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc 	int i;
280433d6423SLionel Sambuc 
281433d6423SLionel Sambuc 	crc ^= byte;
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	for (i = 0; i < 8; i++) {
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc 		if ((crc & 0x80) == 0x80) {
286433d6423SLionel Sambuc 			crc = (crc << 1) ^ CRC8_POLYNOMIAL;
287433d6423SLionel Sambuc 		} else {
288433d6423SLionel Sambuc 			crc <<= 1;
289433d6423SLionel Sambuc 		}
290433d6423SLionel Sambuc 	}
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 	return crc;
293433d6423SLionel Sambuc }
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc /*
296433d6423SLionel Sambuc  * Compute the CRC of an array of bytes and compare it to expected_crc.
297433d6423SLionel Sambuc  * If the computed CRC matches expected_crc, then return OK, otherwise EINVAL.
298433d6423SLionel Sambuc  */
299433d6423SLionel Sambuc static int
checksum(uint8_t * bytes,int nbytes,uint8_t expected_crc)300433d6423SLionel Sambuc checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc)
301433d6423SLionel Sambuc {
302433d6423SLionel Sambuc 	int i;
303433d6423SLionel Sambuc 	uint8_t crc;
304433d6423SLionel Sambuc 
305433d6423SLionel Sambuc 	crc = CRC8_INITIAL_CRC;
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc 	log_debug(&log, "Checking CRC\n");
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc 	for (i = 0; i < nbytes; i++) {
310433d6423SLionel Sambuc 		crc = crc8(crc, bytes[i]);
311433d6423SLionel Sambuc 	}
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 	if (crc == expected_crc) {
314433d6423SLionel Sambuc 		log_debug(&log, "CRC OK\n");
315433d6423SLionel Sambuc 		return OK;
316433d6423SLionel Sambuc 	} else {
317433d6423SLionel Sambuc 		log_warn(&log,
318433d6423SLionel Sambuc 		    "Bad CRC -- Computed CRC: 0x%x | Expected CRC: 0x%x\n",
319433d6423SLionel Sambuc 		    crc, expected_crc);
320433d6423SLionel Sambuc 		return EINVAL;
321433d6423SLionel Sambuc 	}
322433d6423SLionel Sambuc }
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc static ssize_t
sht21_read(devminor_t UNUSED (minor),u64_t position,endpoint_t endpt,cp_grant_id_t grant,size_t size,int UNUSED (flags),cdev_id_t UNUSED (id))325433d6423SLionel Sambuc sht21_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
326433d6423SLionel Sambuc     cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
327433d6423SLionel Sambuc {
328433d6423SLionel Sambuc 	u64_t dev_size;
329433d6423SLionel Sambuc 	int bytes, r;
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 	r = measure();
332433d6423SLionel Sambuc 	if (r != OK) {
333433d6423SLionel Sambuc 		return EIO;
334433d6423SLionel Sambuc 	}
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	memset(buffer, '\0', BUFFER_LEN + 1);
337433d6423SLionel Sambuc 	snprintf(buffer, BUFFER_LEN, "%-16s: %d.%03d\n%-16s: %d.%03d\n",
338433d6423SLionel Sambuc 	    "TEMPERATURE", cached_t / 1000, cached_t % 1000, "HUMIDITY",
339433d6423SLionel Sambuc 	    cached_rh / 1000, cached_rh % 1000);
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc 	log_trace(&log, "%s", buffer);
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc 	dev_size = (u64_t)strlen(buffer);
344433d6423SLionel Sambuc 	if (position >= dev_size) return 0;
345433d6423SLionel Sambuc 	if (position + size > dev_size)
346433d6423SLionel Sambuc 		size = (size_t)(dev_size - position);
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc 	r = sys_safecopyto(endpt, grant, 0,
349433d6423SLionel Sambuc 	    (vir_bytes)(buffer + (size_t)position), size);
350433d6423SLionel Sambuc 
351433d6423SLionel Sambuc 	return (r != OK) ? r : size;
352433d6423SLionel Sambuc }
353433d6423SLionel Sambuc 
354433d6423SLionel Sambuc static void
sht21_other(message * m,int ipc_status)355433d6423SLionel Sambuc sht21_other(message * m, int ipc_status)
356433d6423SLionel Sambuc {
357433d6423SLionel Sambuc 	int r;
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	if (is_ipc_notify(ipc_status)) {
360433d6423SLionel Sambuc 		if (m->m_source == DS_PROC_NR) {
361433d6423SLionel Sambuc 			log_debug(&log,
362433d6423SLionel Sambuc 			    "bus driver changed state, update endpoint\n");
363433d6423SLionel Sambuc 			i2cdriver_handle_bus_update(&bus_endpoint, bus,
364433d6423SLionel Sambuc 			    address);
365433d6423SLionel Sambuc 		}
366433d6423SLionel Sambuc 		return;
367433d6423SLionel Sambuc 	}
368433d6423SLionel Sambuc 
369433d6423SLionel Sambuc 	log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
370433d6423SLionel Sambuc }
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc static int
sef_cb_lu_state_save(int UNUSED (result),int UNUSED (flags))373*e1f889d2SCristiano Giuffrida sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
374433d6423SLionel Sambuc {
375433d6423SLionel Sambuc 	ds_publish_u32("bus", bus, DSF_OVERWRITE);
376433d6423SLionel Sambuc 	ds_publish_u32("address", address, DSF_OVERWRITE);
377433d6423SLionel Sambuc 	return OK;
378433d6423SLionel Sambuc }
379433d6423SLionel Sambuc 
380433d6423SLionel Sambuc static int
lu_state_restore(void)381433d6423SLionel Sambuc lu_state_restore(void)
382433d6423SLionel Sambuc {
383433d6423SLionel Sambuc 	/* Restore the state. */
384433d6423SLionel Sambuc 	u32_t value;
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc 	ds_retrieve_u32("bus", &value);
387433d6423SLionel Sambuc 	ds_delete_u32("bus");
388433d6423SLionel Sambuc 	bus = (int) value;
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc 	ds_retrieve_u32("address", &value);
391433d6423SLionel Sambuc 	ds_delete_u32("address");
392433d6423SLionel Sambuc 	address = (int) value;
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc 	return OK;
395433d6423SLionel Sambuc }
396433d6423SLionel Sambuc 
397433d6423SLionel Sambuc static int
sef_cb_init(int type,sef_init_info_t * UNUSED (info))398433d6423SLionel Sambuc sef_cb_init(int type, sef_init_info_t * UNUSED(info))
399433d6423SLionel Sambuc {
400433d6423SLionel Sambuc 	int r;
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc 	if (type == SEF_INIT_LU) {
403433d6423SLionel Sambuc 		/* Restore the state. */
404433d6423SLionel Sambuc 		lu_state_restore();
405433d6423SLionel Sambuc 	}
406433d6423SLionel Sambuc 
407433d6423SLionel Sambuc 	/* look-up the endpoint for the bus driver */
408433d6423SLionel Sambuc 	bus_endpoint = i2cdriver_bus_endpoint(bus);
409433d6423SLionel Sambuc 	if (bus_endpoint == 0) {
410433d6423SLionel Sambuc 		log_warn(&log, "Couldn't find bus driver.\n");
411433d6423SLionel Sambuc 		return EXIT_FAILURE;
412433d6423SLionel Sambuc 	}
413433d6423SLionel Sambuc 
414433d6423SLionel Sambuc 	/* claim the device */
415433d6423SLionel Sambuc 	r = i2cdriver_reserve_device(bus_endpoint, address);
416433d6423SLionel Sambuc 	if (r != OK) {
417433d6423SLionel Sambuc 		log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
418433d6423SLionel Sambuc 		    address, r);
419433d6423SLionel Sambuc 		return EXIT_FAILURE;
420433d6423SLionel Sambuc 	}
421433d6423SLionel Sambuc 
422433d6423SLionel Sambuc 	r = sht21_init();
423433d6423SLionel Sambuc 	if (r != OK) {
424433d6423SLionel Sambuc 		log_warn(&log, "Device Init Failed\n");
425433d6423SLionel Sambuc 		return EXIT_FAILURE;
426433d6423SLionel Sambuc 	}
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc 	if (type != SEF_INIT_LU) {
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc 		/* sign up for updates about the i2c bus going down/up */
431433d6423SLionel Sambuc 		r = i2cdriver_subscribe_bus_updates(bus);
432433d6423SLionel Sambuc 		if (r != OK) {
433433d6423SLionel Sambuc 			log_warn(&log, "Couldn't subscribe to bus updates\n");
434433d6423SLionel Sambuc 			return EXIT_FAILURE;
435433d6423SLionel Sambuc 		}
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc 		i2cdriver_announce(bus);
438433d6423SLionel Sambuc 		log_debug(&log, "announced\n");
439433d6423SLionel Sambuc 	}
440433d6423SLionel Sambuc 
441433d6423SLionel Sambuc 	return OK;
442433d6423SLionel Sambuc }
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc static void
sef_local_startup(void)445433d6423SLionel Sambuc sef_local_startup(void)
446433d6423SLionel Sambuc {
447433d6423SLionel Sambuc 	/*
448433d6423SLionel Sambuc 	 * Register init callbacks. Use the same function for all event types
449433d6423SLionel Sambuc 	 */
450433d6423SLionel Sambuc 	sef_setcb_init_fresh(sef_cb_init);
451433d6423SLionel Sambuc 	sef_setcb_init_lu(sef_cb_init);
452433d6423SLionel Sambuc 	sef_setcb_init_restart(sef_cb_init);
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc 	/*
455433d6423SLionel Sambuc 	 * Register live update callbacks.
456433d6423SLionel Sambuc 	 */
457433d6423SLionel Sambuc 	sef_setcb_lu_state_save(sef_cb_lu_state_save);
458433d6423SLionel Sambuc 
459433d6423SLionel Sambuc 	/* Let SEF perform startup. */
460433d6423SLionel Sambuc 	sef_startup();
461433d6423SLionel Sambuc }
462433d6423SLionel Sambuc 
463433d6423SLionel Sambuc int
main(int argc,char * argv[])464433d6423SLionel Sambuc main(int argc, char *argv[])
465433d6423SLionel Sambuc {
466433d6423SLionel Sambuc 	int r;
467433d6423SLionel Sambuc 
468433d6423SLionel Sambuc 	env_setargs(argc, argv);
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	r = i2cdriver_env_parse(&bus, &address, valid_addrs);
471433d6423SLionel Sambuc 	if (r < 0) {
472433d6423SLionel Sambuc 		log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
473433d6423SLionel Sambuc 		log_warn(&log, "Example -args 'bus=1 address=0x40'\n");
474433d6423SLionel Sambuc 		return EXIT_FAILURE;
475433d6423SLionel Sambuc 	} else if (r > 0) {
476433d6423SLionel Sambuc 		log_warn(&log,
477433d6423SLionel Sambuc 		    "Invalid slave address for device, expecting 0x40\n");
478433d6423SLionel Sambuc 		return EXIT_FAILURE;
479433d6423SLionel Sambuc 	}
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc 	sef_local_startup();
482433d6423SLionel Sambuc 
483433d6423SLionel Sambuc 	chardriver_task(&sht21_tab);
484433d6423SLionel Sambuc 
485433d6423SLionel Sambuc 	return 0;
486433d6423SLionel Sambuc }
487