1433d6423SLionel Sambuc /* Driver for the BMP085 Preassure 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 /* Control Register for triggering a measurement */
11433d6423SLionel Sambuc #define CTRL_REG 0xf4
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc /* temperature sensor - it only has one 'mode' - conversion time 4.5 ms */
14433d6423SLionel Sambuc #define CMD_TRIG_T 0x2e
15433d6423SLionel Sambuc #define UDELAY_T (4500)
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc /* pressure sensor - ultra low power mode - conversion time 4.5 ms */
18433d6423SLionel Sambuc #define CMD_TRIG_P_ULP 0x34
19433d6423SLionel Sambuc #define MODE_ULP 0x00
20433d6423SLionel Sambuc #define UDELAY_ULP (4500)
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc /* pressure sensor - standard mode - conversion time 7.5 ms */
23433d6423SLionel Sambuc #define CMD_TRIG_P_STD 0x74
24433d6423SLionel Sambuc #define MODE_STD 0x01
25433d6423SLionel Sambuc #define UDELAY_STD (7500)
26433d6423SLionel Sambuc
27433d6423SLionel Sambuc /* pressure sensor - high resolution mode - conversion time 13.5 ms */
28433d6423SLionel Sambuc #define CMD_TRIG_P_HR 0xb4
29433d6423SLionel Sambuc #define MODE_HR 0x02
30433d6423SLionel Sambuc #define UDELAY_HR (13500)
31433d6423SLionel Sambuc
32433d6423SLionel Sambuc /* pressure sensor - ultra high resolution mode - conversion time 25.5 ms */
33433d6423SLionel Sambuc #define CMD_TRIG_P_UHR 0xf4
34433d6423SLionel Sambuc #define MODE_UHR 0x03
35433d6423SLionel Sambuc #define UDELAY_UHR (25500)
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc /* Values for the different modes of operation */
38433d6423SLionel Sambuc struct pressure_cmd
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc uint8_t cmd;
41433d6423SLionel Sambuc uint8_t mode;
42433d6423SLionel Sambuc uint16_t udelay;
43433d6423SLionel Sambuc };
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc /* Table of available modes and their parameters. */
46433d6423SLionel Sambuc static struct pressure_cmd pressure_cmds[4] = {
47433d6423SLionel Sambuc {CMD_TRIG_P_ULP, MODE_ULP, UDELAY_ULP},
48433d6423SLionel Sambuc {CMD_TRIG_P_STD, MODE_STD, UDELAY_STD},
49433d6423SLionel Sambuc {CMD_TRIG_P_HR, MODE_HR, UDELAY_HR},
50433d6423SLionel Sambuc {CMD_TRIG_P_UHR, MODE_UHR, UDELAY_UHR}
51433d6423SLionel Sambuc };
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc /* Default to standard mode.
54433d6423SLionel Sambuc * There isn't code to configure the resolution at runtime, but it should
55433d6423SLionel Sambuc * easy to implement by setting p_cmd to the right element of pressure_cmds.
56433d6423SLionel Sambuc */
57433d6423SLionel Sambuc static struct pressure_cmd *p_cmd = &pressure_cmds[MODE_STD];
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc /* Chip Identification */
60433d6423SLionel Sambuc #define CHIPID_REG 0xd0
61433d6423SLionel Sambuc #define BMP085_CHIPID 0x55
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc /*
64433d6423SLionel Sambuc * There is also a version register at 0xd1, but documentation seems to be
65433d6423SLionel Sambuc * lacking. The sample code says high 4 bytes are AL version and low 4 are ML.
66433d6423SLionel Sambuc */
67433d6423SLionel Sambuc
68433d6423SLionel Sambuc /* Calibration coefficients
69433d6423SLionel Sambuc *
70433d6423SLionel Sambuc * These are unique to each chip and must be read when starting the driver.
71433d6423SLionel Sambuc * Validate them by checking that none are 0x0000 nor 0xffff. Types and
72433d6423SLionel Sambuc * names are from the datasheet.
73433d6423SLionel Sambuc */
74433d6423SLionel Sambuc struct calibration
75433d6423SLionel Sambuc {
76433d6423SLionel Sambuc int16_t ac1;
77433d6423SLionel Sambuc int16_t ac2;
78433d6423SLionel Sambuc int16_t ac3;
79433d6423SLionel Sambuc uint16_t ac4;
80433d6423SLionel Sambuc uint16_t ac5;
81433d6423SLionel Sambuc uint16_t ac6;
82433d6423SLionel Sambuc int16_t b1;
83433d6423SLionel Sambuc int16_t b2;
84433d6423SLionel Sambuc int16_t mb;
85433d6423SLionel Sambuc int16_t mc;
86433d6423SLionel Sambuc int16_t md;
87433d6423SLionel Sambuc } cal;
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc /* Register locations for calibration coefficients */
90433d6423SLionel Sambuc #define AC1_MSB_REG 0xaa
91433d6423SLionel Sambuc #define AC1_LSB_REG 0xab
92433d6423SLionel Sambuc #define AC2_MSB_REG 0xac
93433d6423SLionel Sambuc #define AC2_LSB_REG 0xad
94433d6423SLionel Sambuc #define AC3_MSB_REG 0xae
95433d6423SLionel Sambuc #define AC3_LSB_REG 0xaf
96433d6423SLionel Sambuc #define AC4_MSB_REG 0xb0
97433d6423SLionel Sambuc #define AC4_LSB_REG 0xb1
98433d6423SLionel Sambuc #define AC5_MSB_REG 0xb2
99433d6423SLionel Sambuc #define AC5_LSB_REG 0xb3
100433d6423SLionel Sambuc #define AC6_MSB_REG 0xb4
101433d6423SLionel Sambuc #define AC6_LSB_REG 0xb5
102433d6423SLionel Sambuc #define B1_MSB_REG 0xb6
103433d6423SLionel Sambuc #define B1_LSB_REG 0xb7
104433d6423SLionel Sambuc #define B2_MSB_REG 0xb8
105433d6423SLionel Sambuc #define B2_LSB_REG 0xb9
106433d6423SLionel Sambuc #define MB_MSB_REG 0xba
107433d6423SLionel Sambuc #define MB_LSB_REG 0xbb
108433d6423SLionel Sambuc #define MC_MSB_REG 0xbc
109433d6423SLionel Sambuc #define MC_LSB_REG 0xbd
110433d6423SLionel Sambuc #define MD_MSB_REG 0xbe
111433d6423SLionel Sambuc #define MD_LSB_REG 0xbf
112433d6423SLionel Sambuc
113433d6423SLionel Sambuc #define CAL_COEF_FIRST AC1_MSB_REG
114433d6423SLionel Sambuc #define CAL_COEF_LAST MD_LSB_REG
115433d6423SLionel Sambuc
116*7c48de6cSDavid van Moolenbroek #define CAL_COEF_IS_VALID(x) (x != 0x0000 && (uint16_t)x != 0xffff)
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc #define SENSOR_VAL_MSB_REG 0xf6
119433d6423SLionel Sambuc #define SENSOR_VAL_LSB_REG 0xf7
120433d6423SLionel Sambuc #define SENSOR_VAL_XLSB_REG 0xf8
121433d6423SLionel Sambuc
122433d6423SLionel Sambuc /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
123433d6423SLionel Sambuc static struct log log = {
124433d6423SLionel Sambuc .name = "bmp085",
125433d6423SLionel Sambuc .log_level = LEVEL_INFO,
126433d6423SLionel Sambuc .log_func = default_log
127433d6423SLionel Sambuc };
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc /* Only one valid slave address. It isn't configurable. */
130433d6423SLionel Sambuc static i2c_addr_t valid_addrs[5] = {
131433d6423SLionel Sambuc 0x77, 0x00
132433d6423SLionel Sambuc };
133433d6423SLionel Sambuc
134433d6423SLionel Sambuc /* Buffer to store output string returned when reading from device file. */
135433d6423SLionel Sambuc #define BUFFER_LEN 64
136433d6423SLionel Sambuc char buffer[BUFFER_LEN + 1];
137433d6423SLionel Sambuc
138433d6423SLionel Sambuc /* the bus that this device is on (counting starting at 1) */
139433d6423SLionel Sambuc static uint32_t bus;
140433d6423SLionel Sambuc
141433d6423SLionel Sambuc /* slave address of the device */
142433d6423SLionel Sambuc static i2c_addr_t address;
143433d6423SLionel Sambuc
144433d6423SLionel Sambuc /* endpoint for the driver for the bus itself. */
145433d6423SLionel Sambuc static endpoint_t bus_endpoint;
146433d6423SLionel Sambuc
147433d6423SLionel Sambuc /* main device functions */
148433d6423SLionel Sambuc static int bmp085_init(void);
149433d6423SLionel Sambuc static int version_check(void);
150433d6423SLionel Sambuc static int read_cal_coef(void);
151433d6423SLionel Sambuc static int measure(int32_t * temperature, int32_t * pressure);
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /* libchardriver callbacks */
154433d6423SLionel Sambuc static ssize_t bmp085_read(devminor_t minor, u64_t position, endpoint_t endpt,
155433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
156433d6423SLionel Sambuc static void bmp085_other(message * m, int ipc_status);
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc /* Entry points to this driver from libchardriver. */
159433d6423SLionel Sambuc static struct chardriver bmp085_tab = {
160433d6423SLionel Sambuc .cdr_read = bmp085_read,
161433d6423SLionel Sambuc .cdr_other = bmp085_other
162433d6423SLionel Sambuc };
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc /*
165433d6423SLionel Sambuc * Initialize the driver. Checks the CHIPID against a known value and
166433d6423SLionel Sambuc * reads the calibration coefficients.
167433d6423SLionel Sambuc *
168433d6423SLionel Sambuc * The chip does have a soft reset register (0xe0), but there
169433d6423SLionel Sambuc * doesn't appear to be any documentation or example usage for it.
170433d6423SLionel Sambuc */
171433d6423SLionel Sambuc static int
bmp085_init(void)172433d6423SLionel Sambuc bmp085_init(void)
173433d6423SLionel Sambuc {
174433d6423SLionel Sambuc int r;
175433d6423SLionel Sambuc int32_t t, p;
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc r = version_check();
178433d6423SLionel Sambuc if (r != OK) {
179433d6423SLionel Sambuc return EXIT_FAILURE;
180433d6423SLionel Sambuc }
181433d6423SLionel Sambuc
182433d6423SLionel Sambuc r = read_cal_coef();
183433d6423SLionel Sambuc if (r != OK) {
184433d6423SLionel Sambuc return EXIT_FAILURE;
185433d6423SLionel Sambuc }
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc return OK;
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190433d6423SLionel Sambuc static int
version_check(void)191433d6423SLionel Sambuc version_check(void)
192433d6423SLionel Sambuc {
193433d6423SLionel Sambuc int r;
194433d6423SLionel Sambuc uint8_t chipid;
195433d6423SLionel Sambuc
196433d6423SLionel Sambuc r = i2creg_read8(bus_endpoint, address, CHIPID_REG, &chipid);
197433d6423SLionel Sambuc if (r != OK) {
198433d6423SLionel Sambuc log_warn(&log, "Couldn't read CHIPID\n");
199433d6423SLionel Sambuc return -1;
200433d6423SLionel Sambuc }
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc if (chipid != BMP085_CHIPID) {
203433d6423SLionel Sambuc log_warn(&log, "Bad CHIPID\n");
204433d6423SLionel Sambuc return -1;
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc
207433d6423SLionel Sambuc log_debug(&log, "CHIPID OK\n");
208433d6423SLionel Sambuc
209433d6423SLionel Sambuc return OK;
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc
212433d6423SLionel Sambuc /*
213433d6423SLionel Sambuc * Read the calibration data from the chip. Each individual chip has a unique
214433d6423SLionel Sambuc * set of calibration parameters that get used to compute the true temperature
215433d6423SLionel Sambuc * and pressure.
216433d6423SLionel Sambuc */
217433d6423SLionel Sambuc static int
read_cal_coef(void)218433d6423SLionel Sambuc read_cal_coef(void)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc int r;
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc /* Populate the calibration struct with values */
223433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC1_MSB_REG, &cal.ac1);
224433d6423SLionel Sambuc if (r != OK) {
225433d6423SLionel Sambuc return -1;
226433d6423SLionel Sambuc }
227433d6423SLionel Sambuc log_debug(&log, "cal.ac1 = %d\n", cal.ac1);
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC2_MSB_REG, &cal.ac2);
230433d6423SLionel Sambuc if (r != OK) {
231433d6423SLionel Sambuc return -1;
232433d6423SLionel Sambuc }
233433d6423SLionel Sambuc log_debug(&log, "cal.ac2 = %d\n", cal.ac2);
234433d6423SLionel Sambuc
235433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC3_MSB_REG, &cal.ac3);
236433d6423SLionel Sambuc if (r != OK) {
237433d6423SLionel Sambuc return -1;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc log_debug(&log, "cal.ac3 = %d\n", cal.ac3);
240433d6423SLionel Sambuc
241433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC4_MSB_REG, &cal.ac4);
242433d6423SLionel Sambuc if (r != OK) {
243433d6423SLionel Sambuc return -1;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc log_debug(&log, "cal.ac4 = %u\n", cal.ac4);
246433d6423SLionel Sambuc
247433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC5_MSB_REG, &cal.ac5);
248433d6423SLionel Sambuc if (r != OK) {
249433d6423SLionel Sambuc return -1;
250433d6423SLionel Sambuc }
251433d6423SLionel Sambuc log_debug(&log, "cal.ac5 = %u\n", cal.ac5);
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, AC6_MSB_REG, &cal.ac6);
254433d6423SLionel Sambuc if (r != OK) {
255433d6423SLionel Sambuc return -1;
256433d6423SLionel Sambuc }
257433d6423SLionel Sambuc log_debug(&log, "cal.ac6 = %u\n", cal.ac6);
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, B1_MSB_REG, &cal.b1);
260433d6423SLionel Sambuc if (r != OK) {
261433d6423SLionel Sambuc return -1;
262433d6423SLionel Sambuc }
263433d6423SLionel Sambuc log_debug(&log, "cal.b1 = %d\n", cal.b1);
264433d6423SLionel Sambuc
265433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, B2_MSB_REG, &cal.b2);
266433d6423SLionel Sambuc if (r != OK) {
267433d6423SLionel Sambuc return -1;
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc log_debug(&log, "cal.b2 = %d\n", cal.b2);
270433d6423SLionel Sambuc
271433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, MB_MSB_REG, &cal.mb);
272433d6423SLionel Sambuc if (r != OK) {
273433d6423SLionel Sambuc return -1;
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc log_debug(&log, "cal.mb = %d\n", cal.mb);
276433d6423SLionel Sambuc
277433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, MC_MSB_REG, &cal.mc);
278433d6423SLionel Sambuc if (r != OK) {
279433d6423SLionel Sambuc return -1;
280433d6423SLionel Sambuc }
281433d6423SLionel Sambuc log_debug(&log, "cal.mc = %d\n", cal.mc);
282433d6423SLionel Sambuc
283433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, MD_MSB_REG, &cal.md);
284433d6423SLionel Sambuc if (r != OK) {
285433d6423SLionel Sambuc return -1;
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc log_debug(&log, "cal.md = %d\n", cal.md);
288433d6423SLionel Sambuc
289433d6423SLionel Sambuc /* Validate. Data sheet says values should not be 0x0000 nor 0xffff */
290433d6423SLionel Sambuc if (!CAL_COEF_IS_VALID(cal.ac1) ||
291433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.ac2) ||
292433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.ac3) ||
293433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.ac4) ||
294433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.ac5) ||
295433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.ac6) ||
296433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.b1) ||
297433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.b2) ||
298433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.mb) ||
299433d6423SLionel Sambuc !CAL_COEF_IS_VALID(cal.mc) || !CAL_COEF_IS_VALID(cal.md)) {
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc log_warn(&log, "Invalid calibration data found on chip.\n");
302433d6423SLionel Sambuc return -1;
303433d6423SLionel Sambuc }
304433d6423SLionel Sambuc
305433d6423SLionel Sambuc log_debug(&log, "Read Cal Data OK\n");
306433d6423SLionel Sambuc
307433d6423SLionel Sambuc return OK;
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc /*
311433d6423SLionel Sambuc * Measure the uncompensated temperature and uncompensated pressure from the
312433d6423SLionel Sambuc * chip and apply the formulas to determine the true temperature and pressure.
313433d6423SLionel Sambuc * Note, the data sheet is light on the details when it comes to defining the
314433d6423SLionel Sambuc * meaning of each variable, so this function has a lot of cryptic names in it.
315433d6423SLionel Sambuc */
316433d6423SLionel Sambuc static int
measure(int32_t * temperature,int32_t * pressure)317433d6423SLionel Sambuc measure(int32_t * temperature, int32_t * pressure)
318433d6423SLionel Sambuc {
319433d6423SLionel Sambuc int r;
320433d6423SLionel Sambuc
321433d6423SLionel Sambuc /* Types are given in the datasheet. Their long translates to 32-bits */
322433d6423SLionel Sambuc
323433d6423SLionel Sambuc int16_t ut; /* uncompensated temperature */
324433d6423SLionel Sambuc int32_t up; /* uncompensated pressure */
325433d6423SLionel Sambuc int32_t x1;
326433d6423SLionel Sambuc int32_t x2;
327433d6423SLionel Sambuc int32_t x3;
328433d6423SLionel Sambuc int32_t b3;
329433d6423SLionel Sambuc uint32_t b4;
330433d6423SLionel Sambuc int32_t b5;
331433d6423SLionel Sambuc int32_t b6;
332433d6423SLionel Sambuc uint32_t b7;
333433d6423SLionel Sambuc int32_t t; /* true temperature (in 0.1C) */
334433d6423SLionel Sambuc int32_t p; /* true pressure (in Pa) */
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc log_debug(&log, "Triggering Temp Reading...\n");
337433d6423SLionel Sambuc
338433d6423SLionel Sambuc /* trigger temperature reading */
339433d6423SLionel Sambuc r = i2creg_write8(bus_endpoint, address, CTRL_REG, CMD_TRIG_T);
340433d6423SLionel Sambuc if (r != OK) {
341433d6423SLionel Sambuc log_warn(&log, "Failed to trigger temperature reading.\n");
342433d6423SLionel Sambuc return -1;
343433d6423SLionel Sambuc }
344433d6423SLionel Sambuc
345433d6423SLionel Sambuc /* wait for sampling to be completed. */
346433d6423SLionel Sambuc micro_delay(UDELAY_T);
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc /* read the uncompensated temperature */
349433d6423SLionel Sambuc r = i2creg_read16(bus_endpoint, address, SENSOR_VAL_MSB_REG, &ut);
350433d6423SLionel Sambuc if (r != OK) {
351433d6423SLionel Sambuc log_warn(&log, "Failed to read temperature.\n");
352433d6423SLionel Sambuc return -1;
353433d6423SLionel Sambuc }
354433d6423SLionel Sambuc
355433d6423SLionel Sambuc log_debug(&log, "ut = %d\n", ut);
356433d6423SLionel Sambuc
357433d6423SLionel Sambuc log_debug(&log, "Triggering Pressure Reading...\n");
358433d6423SLionel Sambuc
359433d6423SLionel Sambuc /* trigger pressure reading */
360433d6423SLionel Sambuc r = i2creg_write8(bus_endpoint, address, CTRL_REG, p_cmd->cmd);
361433d6423SLionel Sambuc if (r != OK) {
362433d6423SLionel Sambuc log_warn(&log, "Failed to trigger pressure reading.\n");
363433d6423SLionel Sambuc return -1;
364433d6423SLionel Sambuc }
365433d6423SLionel Sambuc
366433d6423SLionel Sambuc /* wait for sampling to be completed. */
367433d6423SLionel Sambuc micro_delay(p_cmd->udelay);
368433d6423SLionel Sambuc
369433d6423SLionel Sambuc /* read the uncompensated pressure */
370433d6423SLionel Sambuc r = i2creg_read24(bus_endpoint, address, SENSOR_VAL_MSB_REG, &up);
371433d6423SLionel Sambuc if (r != OK) {
372433d6423SLionel Sambuc log_warn(&log, "Failed to read pressure.\n");
373433d6423SLionel Sambuc return -1;
374433d6423SLionel Sambuc }
375433d6423SLionel Sambuc
376433d6423SLionel Sambuc /* shift by 8 - oversampling setting */
377433d6423SLionel Sambuc up = (up >> (8 - p_cmd->mode));
378433d6423SLionel Sambuc
379433d6423SLionel Sambuc log_debug(&log, "up = %d\n", up);
380433d6423SLionel Sambuc
381433d6423SLionel Sambuc /* convert uncompensated temperature to true temperature */
382433d6423SLionel Sambuc x1 = ((ut - cal.ac6) * cal.ac5) / (1 << 15);
383433d6423SLionel Sambuc x2 = (cal.mc * (1 << 11)) / (x1 + cal.md);
384433d6423SLionel Sambuc b5 = x1 + x2;
385433d6423SLionel Sambuc t = (b5 + 8) / (1 << 4);
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc /* save the result */
388433d6423SLionel Sambuc *temperature = t;
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc log_debug(&log, "t = %d\n", t);
391433d6423SLionel Sambuc
392433d6423SLionel Sambuc /* Convert uncompensated pressure to true pressure.
393433d6423SLionel Sambuc * This is really how the data sheet suggests doing it.
394433d6423SLionel Sambuc * There is no alternative approach suggested. Other open
395433d6423SLionel Sambuc * source drivers I've found use this method.
396433d6423SLionel Sambuc */
397433d6423SLionel Sambuc b6 = b5 - 4000;
398433d6423SLionel Sambuc x1 = ((cal.b2 * ((b6 * b6) >> 12)) >> 11);
399433d6423SLionel Sambuc x2 = ((cal.ac2 * b6) >> 11);
400433d6423SLionel Sambuc x3 = x1 + x2;
401433d6423SLionel Sambuc b3 = (((((cal.ac1 * 4) + x3) << p_cmd->mode) + 2) >> 2);
402433d6423SLionel Sambuc x1 = ((cal.ac3 * b6) >> 13);
403433d6423SLionel Sambuc x2 = ((cal.b1 * ((b6 * b6) >> 12)) >> 16);
404433d6423SLionel Sambuc x3 = (((x1 + x2) + 2) >> 2);
405433d6423SLionel Sambuc b4 = ((cal.ac4 * ((uint32_t) (x3 + 32768))) >> 15);
406433d6423SLionel Sambuc b7 = ((uint32_t) up - b3) * (50000 >> p_cmd->mode);
407433d6423SLionel Sambuc p = (b7 < 0x80000000) ? (b7 * 2) / b4 : (b7 / b4) * 2;
408433d6423SLionel Sambuc x1 = (p >> 8) * (p >> 8);
409433d6423SLionel Sambuc x1 = ((x1 * 3038) >> 16);
410433d6423SLionel Sambuc x2 = ((-7357 * p) >> 16);
411433d6423SLionel Sambuc p = p + ((x1 + x2 + 3791) >> 4);
412433d6423SLionel Sambuc
413433d6423SLionel Sambuc *pressure = p;
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc log_debug(&log, "p = %d\n", p);
416433d6423SLionel Sambuc
417433d6423SLionel Sambuc return OK;
418433d6423SLionel Sambuc }
419433d6423SLionel Sambuc
420433d6423SLionel Sambuc static ssize_t
bmp085_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))421433d6423SLionel Sambuc bmp085_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
422433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
423433d6423SLionel Sambuc {
424433d6423SLionel Sambuc u64_t dev_size;
425433d6423SLionel Sambuc int r;
426433d6423SLionel Sambuc uint32_t temperature, pressure;
427433d6423SLionel Sambuc
428433d6423SLionel Sambuc r = measure(&temperature, &pressure);
429433d6423SLionel Sambuc if (r != OK) {
430433d6423SLionel Sambuc return EIO;
431433d6423SLionel Sambuc }
432433d6423SLionel Sambuc
433433d6423SLionel Sambuc memset(buffer, '\0', BUFFER_LEN + 1);
434433d6423SLionel Sambuc snprintf(buffer, BUFFER_LEN, "%-16s: %d.%01d\n%-16s: %d\n",
435433d6423SLionel Sambuc "TEMPERATURE", temperature / 10, temperature % 10, "PRESSURE",
436433d6423SLionel Sambuc pressure);
437433d6423SLionel Sambuc
438433d6423SLionel Sambuc log_trace(&log, "%s", buffer);
439433d6423SLionel Sambuc
440433d6423SLionel Sambuc dev_size = (u64_t)strlen(buffer);
441433d6423SLionel Sambuc if (position >= dev_size) return 0;
442433d6423SLionel Sambuc if (position + size > dev_size)
443433d6423SLionel Sambuc size = (size_t)(dev_size - position);
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, 0,
446433d6423SLionel Sambuc (vir_bytes)(buffer + (size_t)position), size);
447433d6423SLionel Sambuc
448433d6423SLionel Sambuc return (r != OK) ? r : size;
449433d6423SLionel Sambuc }
450433d6423SLionel Sambuc
451433d6423SLionel Sambuc static void
bmp085_other(message * m,int ipc_status)452433d6423SLionel Sambuc bmp085_other(message * m, int ipc_status)
453433d6423SLionel Sambuc {
454433d6423SLionel Sambuc int r;
455433d6423SLionel Sambuc
456433d6423SLionel Sambuc if (is_ipc_notify(ipc_status)) {
457433d6423SLionel Sambuc if (m->m_source == DS_PROC_NR) {
458433d6423SLionel Sambuc log_debug(&log,
459433d6423SLionel Sambuc "bus driver changed state, update endpoint\n");
460433d6423SLionel Sambuc i2cdriver_handle_bus_update(&bus_endpoint, bus,
461433d6423SLionel Sambuc address);
462433d6423SLionel Sambuc }
463433d6423SLionel Sambuc return;
464433d6423SLionel Sambuc }
465433d6423SLionel Sambuc
466433d6423SLionel Sambuc log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
467433d6423SLionel Sambuc }
468433d6423SLionel Sambuc
469433d6423SLionel Sambuc static int
sef_cb_lu_state_save(int UNUSED (result),int UNUSED (flags))470e1f889d2SCristiano Giuffrida sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
471433d6423SLionel Sambuc {
472433d6423SLionel Sambuc ds_publish_u32("bus", bus, DSF_OVERWRITE);
473433d6423SLionel Sambuc ds_publish_u32("address", address, DSF_OVERWRITE);
474433d6423SLionel Sambuc return OK;
475433d6423SLionel Sambuc }
476433d6423SLionel Sambuc
477433d6423SLionel Sambuc static int
lu_state_restore(void)478433d6423SLionel Sambuc lu_state_restore(void)
479433d6423SLionel Sambuc {
480433d6423SLionel Sambuc /* Restore the state. */
481433d6423SLionel Sambuc u32_t value;
482433d6423SLionel Sambuc
483433d6423SLionel Sambuc ds_retrieve_u32("bus", &value);
484433d6423SLionel Sambuc ds_delete_u32("bus");
485433d6423SLionel Sambuc bus = (int) value;
486433d6423SLionel Sambuc
487433d6423SLionel Sambuc ds_retrieve_u32("address", &value);
488433d6423SLionel Sambuc ds_delete_u32("address");
489433d6423SLionel Sambuc address = (int) value;
490433d6423SLionel Sambuc
491433d6423SLionel Sambuc return OK;
492433d6423SLionel Sambuc }
493433d6423SLionel Sambuc
494433d6423SLionel Sambuc static int
sef_cb_init(int type,sef_init_info_t * UNUSED (info))495433d6423SLionel Sambuc sef_cb_init(int type, sef_init_info_t * UNUSED(info))
496433d6423SLionel Sambuc {
497433d6423SLionel Sambuc int r;
498433d6423SLionel Sambuc
499433d6423SLionel Sambuc if (type == SEF_INIT_LU) {
500433d6423SLionel Sambuc /* Restore the state. */
501433d6423SLionel Sambuc lu_state_restore();
502433d6423SLionel Sambuc }
503433d6423SLionel Sambuc
504433d6423SLionel Sambuc /* look-up the endpoint for the bus driver */
505433d6423SLionel Sambuc bus_endpoint = i2cdriver_bus_endpoint(bus);
506433d6423SLionel Sambuc if (bus_endpoint == 0) {
507433d6423SLionel Sambuc log_warn(&log, "Couldn't find bus driver.\n");
508433d6423SLionel Sambuc return EXIT_FAILURE;
509433d6423SLionel Sambuc }
510433d6423SLionel Sambuc
511433d6423SLionel Sambuc /* claim the device */
512433d6423SLionel Sambuc r = i2cdriver_reserve_device(bus_endpoint, address);
513433d6423SLionel Sambuc if (r != OK) {
514433d6423SLionel Sambuc log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
515433d6423SLionel Sambuc address, r);
516433d6423SLionel Sambuc return EXIT_FAILURE;
517433d6423SLionel Sambuc }
518433d6423SLionel Sambuc
519433d6423SLionel Sambuc r = bmp085_init();
520433d6423SLionel Sambuc if (r != OK) {
521433d6423SLionel Sambuc log_warn(&log, "Couldn't initialize device\n");
522433d6423SLionel Sambuc return EXIT_FAILURE;
523433d6423SLionel Sambuc }
524433d6423SLionel Sambuc
525433d6423SLionel Sambuc if (type != SEF_INIT_LU) {
526433d6423SLionel Sambuc
527433d6423SLionel Sambuc /* sign up for updates about the i2c bus going down/up */
528433d6423SLionel Sambuc r = i2cdriver_subscribe_bus_updates(bus);
529433d6423SLionel Sambuc if (r != OK) {
530433d6423SLionel Sambuc log_warn(&log, "Couldn't subscribe to bus updates\n");
531433d6423SLionel Sambuc return EXIT_FAILURE;
532433d6423SLionel Sambuc }
533433d6423SLionel Sambuc
534433d6423SLionel Sambuc i2cdriver_announce(bus);
535433d6423SLionel Sambuc log_debug(&log, "announced\n");
536433d6423SLionel Sambuc }
537433d6423SLionel Sambuc
538433d6423SLionel Sambuc return OK;
539433d6423SLionel Sambuc }
540433d6423SLionel Sambuc
541433d6423SLionel Sambuc static void
sef_local_startup(void)542433d6423SLionel Sambuc sef_local_startup(void)
543433d6423SLionel Sambuc {
544433d6423SLionel Sambuc /*
545433d6423SLionel Sambuc * Register init callbacks. Use the same function for all event types
546433d6423SLionel Sambuc */
547433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init);
548433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init);
549433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init);
550433d6423SLionel Sambuc
551433d6423SLionel Sambuc /*
552433d6423SLionel Sambuc * Register live update callbacks.
553433d6423SLionel Sambuc */
554433d6423SLionel Sambuc sef_setcb_lu_state_save(sef_cb_lu_state_save);
555433d6423SLionel Sambuc
556433d6423SLionel Sambuc /* Let SEF perform startup. */
557433d6423SLionel Sambuc sef_startup();
558433d6423SLionel Sambuc }
559433d6423SLionel Sambuc
560433d6423SLionel Sambuc int
main(int argc,char * argv[])561433d6423SLionel Sambuc main(int argc, char *argv[])
562433d6423SLionel Sambuc {
563433d6423SLionel Sambuc int r;
564433d6423SLionel Sambuc
565433d6423SLionel Sambuc env_setargs(argc, argv);
566433d6423SLionel Sambuc
567433d6423SLionel Sambuc r = i2cdriver_env_parse(&bus, &address, valid_addrs);
568433d6423SLionel Sambuc if (r < 0) {
569433d6423SLionel Sambuc log_warn(&log, "Expecting -args 'bus=X address=0x77'\n");
570433d6423SLionel Sambuc log_warn(&log, "Example -args 'bus=1 address=0x77'\n");
571433d6423SLionel Sambuc return EXIT_FAILURE;
572433d6423SLionel Sambuc } else if (r > 0) {
573433d6423SLionel Sambuc log_warn(&log,
574433d6423SLionel Sambuc "Invalid slave address for device, expecting 0x77\n");
575433d6423SLionel Sambuc return EXIT_FAILURE;
576433d6423SLionel Sambuc }
577433d6423SLionel Sambuc
578433d6423SLionel Sambuc sef_local_startup();
579433d6423SLionel Sambuc
580433d6423SLionel Sambuc chardriver_task(&bmp085_tab);
581433d6423SLionel Sambuc
582433d6423SLionel Sambuc return 0;
583433d6423SLionel Sambuc }
584