1433d6423SLionel Sambuc /* Driver for the TSL2550 Ambient Light 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 #include <minix/type.h>
10433d6423SLionel Sambuc #include <minix/spin.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc /*
13433d6423SLionel Sambuc * Device Commands
14433d6423SLionel Sambuc */
15433d6423SLionel Sambuc #define CMD_PWR_DOWN 0x00
16433d6423SLionel Sambuc #define CMD_PWR_UP 0x03
17433d6423SLionel Sambuc #define CMD_EXT_RANGE 0x1d
18433d6423SLionel Sambuc #define CMD_NORM_RANGE 0x18
19433d6423SLionel Sambuc #define CMD_READ_ADC0 0x43
20433d6423SLionel Sambuc #define CMD_READ_ADC1 0x83
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc /* When powered up and communicating, the register should have this value */
23433d6423SLionel Sambuc #define EXPECTED_PWR_UP_TEST_VAL 0x03
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc /* Maximum Lux value in Standard Mode */
26433d6423SLionel Sambuc #define MAX_LUX_STD_MODE 1846
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc /* Bit Masks for ADC Data */
29433d6423SLionel Sambuc #define ADC_VALID_MASK (1<<7)
30433d6423SLionel Sambuc #define ADC_CHORD_MASK ((1<<6)|(1<<5)|(1<<4))
31433d6423SLionel Sambuc #define ADC_STEP_MASK ((1<<3)|(1<<2)|(1<<1)|(1<<0))
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc #define ADC_VAL_IS_VALID(x) ((x & ADC_VALID_MASK) == ADC_VALID_MASK)
34433d6423SLionel Sambuc #define ADC_VAL_TO_CHORD_BITS(x) ((x & ADC_CHORD_MASK) >> 4)
35433d6423SLionel Sambuc #define ADC_VAL_TO_STEP_BITS(x) (x & ADC_STEP_MASK)
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
38433d6423SLionel Sambuc static struct log log = {
39433d6423SLionel Sambuc .name = "tsl2550",
40433d6423SLionel Sambuc .log_level = LEVEL_INFO,
41433d6423SLionel Sambuc .log_func = default_log
42433d6423SLionel Sambuc };
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc /* The slave address is hardwired to 0x39 and cannot be changed. */
45433d6423SLionel Sambuc static i2c_addr_t valid_addrs[2] = {
46433d6423SLionel Sambuc 0x39, 0x00
47433d6423SLionel Sambuc };
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc /* Buffer to store output string returned when reading from device file. */
50433d6423SLionel Sambuc #define BUFFER_LEN 32
51433d6423SLionel Sambuc char buffer[BUFFER_LEN + 1];
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc /* the bus that this device is on (counting starting at 1) */
54433d6423SLionel Sambuc static uint32_t bus;
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc /* slave address of the device */
57433d6423SLionel Sambuc static i2c_addr_t address;
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc /* endpoint for the driver for the bus itself. */
60433d6423SLionel Sambuc static endpoint_t bus_endpoint;
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc /* main driver functions */
63433d6423SLionel Sambuc static int tsl2550_init(void);
64433d6423SLionel Sambuc static int adc_read(int adc, uint8_t * val);
65433d6423SLionel Sambuc static int measure_lux(uint32_t * lux);
66433d6423SLionel Sambuc
67433d6423SLionel Sambuc /* libchardriver callbacks */
68433d6423SLionel Sambuc static ssize_t tsl2550_read(devminor_t minor, u64_t position, endpoint_t endpt,
69433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
70433d6423SLionel Sambuc static void tsl2550_other(message * m, int ipc_status);
71433d6423SLionel Sambuc
72433d6423SLionel Sambuc /* Entry points to this driver from libchardriver. */
73433d6423SLionel Sambuc static struct chardriver tsl2550_tab = {
74433d6423SLionel Sambuc .cdr_read = tsl2550_read,
75433d6423SLionel Sambuc .cdr_other = tsl2550_other
76433d6423SLionel Sambuc };
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc /*
79433d6423SLionel Sambuc * These two lookup tables and the formulas used in measure_lux() are from
80433d6423SLionel Sambuc * 'TAOS INTELLIGENT OPTO SENSOR DESIGNER'S NOTEBOOK' Number 9
81433d6423SLionel Sambuc * 'Simplified TSL2550 Lux Calculation for Embedded and Micro Controllers'.
82433d6423SLionel Sambuc *
83433d6423SLionel Sambuc * The tables and formulas eliminate the need for floating point math and
84433d6423SLionel Sambuc * functions from libm. It also speeds up the calculations.
85433d6423SLionel Sambuc */
86433d6423SLionel Sambuc
87433d6423SLionel Sambuc /* Look up table for converting ADC values to ADC counts */
88433d6423SLionel Sambuc static const uint32_t adc_counts_lut[128] = {
89433d6423SLionel Sambuc 0, 1, 2, 3, 4, 5, 6, 7,
90433d6423SLionel Sambuc 8, 9, 10, 11, 12, 13, 14, 15,
91433d6423SLionel Sambuc 16, 18, 20, 22, 24, 26, 28, 30,
92433d6423SLionel Sambuc 32, 34, 36, 38, 40, 42, 44, 46,
93433d6423SLionel Sambuc 49, 53, 57, 61, 65, 69, 73, 77,
94433d6423SLionel Sambuc 81, 85, 89, 93, 97, 101, 105, 109,
95433d6423SLionel Sambuc 115, 123, 131, 139, 147, 155, 163, 171,
96433d6423SLionel Sambuc 179, 187, 195, 203, 211, 219, 227, 235,
97433d6423SLionel Sambuc 247, 263, 279, 295, 311, 327, 343, 359,
98433d6423SLionel Sambuc 375, 391, 407, 423, 439, 455, 471, 487,
99433d6423SLionel Sambuc 511, 543, 575, 607, 639, 671, 703, 735,
100433d6423SLionel Sambuc 767, 799, 831, 863, 895, 927, 959, 991,
101433d6423SLionel Sambuc 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
102433d6423SLionel Sambuc 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
103433d6423SLionel Sambuc 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
104433d6423SLionel Sambuc 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015
105433d6423SLionel Sambuc };
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /* Look up table of scaling factors */
108433d6423SLionel Sambuc static const uint32_t ratio_lut[129] = {
109433d6423SLionel Sambuc 100, 100, 100, 100, 100, 100, 100, 100,
110433d6423SLionel Sambuc 100, 100, 100, 100, 100, 100, 99, 99,
111433d6423SLionel Sambuc 99, 99, 99, 99, 99, 99, 99, 99,
112433d6423SLionel Sambuc 99, 99, 99, 98, 98, 98, 98, 98,
113433d6423SLionel Sambuc 98, 98, 97, 97, 97, 97, 97, 96,
114433d6423SLionel Sambuc 96, 96, 96, 95, 95, 95, 94, 94,
115433d6423SLionel Sambuc 93, 93, 93, 92, 92, 91, 91, 90,
116433d6423SLionel Sambuc 89, 89, 88, 87, 87, 86, 85, 84,
117433d6423SLionel Sambuc 83, 82, 81, 80, 79, 78, 77, 75,
118433d6423SLionel Sambuc 74, 73, 71, 69, 68, 66, 64, 62,
119433d6423SLionel Sambuc 60, 58, 56, 54, 52, 49, 47, 44,
120433d6423SLionel Sambuc 42, 41, 40, 40, 39, 39, 38, 38,
121433d6423SLionel Sambuc 37, 37, 37, 36, 36, 36, 35, 35,
122433d6423SLionel Sambuc 35, 35, 34, 34, 34, 34, 33, 33,
123433d6423SLionel Sambuc 33, 33, 32, 32, 32, 32, 32, 31,
124433d6423SLionel Sambuc 31, 31, 31, 31, 30, 30, 30, 30,
125433d6423SLionel Sambuc 30
126433d6423SLionel Sambuc };
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc static int
measure_lux(uint32_t * lux)129433d6423SLionel Sambuc measure_lux(uint32_t * lux)
130433d6423SLionel Sambuc {
131433d6423SLionel Sambuc int r;
132433d6423SLionel Sambuc uint8_t adc0_val, adc1_val;
133433d6423SLionel Sambuc uint32_t adc0_cnt, adc1_cnt;
134433d6423SLionel Sambuc uint32_t ratio;
135433d6423SLionel Sambuc
136433d6423SLionel Sambuc r = adc_read(0, &adc0_val);
137433d6423SLionel Sambuc if (r != OK) {
138433d6423SLionel Sambuc return -1;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc
141433d6423SLionel Sambuc r = adc_read(1, &adc1_val);
142433d6423SLionel Sambuc if (r != OK) {
143433d6423SLionel Sambuc return -1;
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc
146433d6423SLionel Sambuc /* Look up the adc count, drop the MSB to put in range 0-127. */
147433d6423SLionel Sambuc adc0_cnt = adc_counts_lut[adc0_val & ~ADC_VALID_MASK];
148433d6423SLionel Sambuc adc1_cnt = adc_counts_lut[adc1_val & ~ADC_VALID_MASK];
149433d6423SLionel Sambuc
150433d6423SLionel Sambuc /* default scaling factor */
151433d6423SLionel Sambuc ratio = 128;
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /* calculate ratio - avoid div by 0, ensure cnt1 <= cnt0 */
154433d6423SLionel Sambuc if ((adc0_cnt != 0) && (adc1_cnt <= adc0_cnt)) {
155433d6423SLionel Sambuc ratio = (adc1_cnt * 128 / adc0_cnt);
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc /* ensure ratio isn't outside ratio_lut[] */
159433d6423SLionel Sambuc if (ratio > 128) {
160433d6423SLionel Sambuc ratio = 128;
161433d6423SLionel Sambuc }
162433d6423SLionel Sambuc
163433d6423SLionel Sambuc /* calculate lux */
164433d6423SLionel Sambuc *lux = ((adc0_cnt - adc1_cnt) * ratio_lut[ratio]) / 256;
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc /* range check */
167433d6423SLionel Sambuc if (*lux > MAX_LUX_STD_MODE) {
168433d6423SLionel Sambuc *lux = MAX_LUX_STD_MODE;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc
171433d6423SLionel Sambuc return OK;
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc
174433d6423SLionel Sambuc static int
adc_read(int adc,uint8_t * val)175433d6423SLionel Sambuc adc_read(int adc, uint8_t * val)
176433d6423SLionel Sambuc {
177433d6423SLionel Sambuc int r;
178433d6423SLionel Sambuc spin_t spin;
179433d6423SLionel Sambuc
180433d6423SLionel Sambuc if (adc != 0 && adc != 1) {
181433d6423SLionel Sambuc log_warn(&log, "Invalid ADC number %d, expected 0 or 1.\n",
182433d6423SLionel Sambuc adc);
183433d6423SLionel Sambuc return EINVAL;
184433d6423SLionel Sambuc }
185433d6423SLionel Sambuc
186433d6423SLionel Sambuc if (val == NULL) {
187433d6423SLionel Sambuc log_warn(&log, "Read called with a NULL pointer.\n");
188433d6423SLionel Sambuc return EINVAL;
189433d6423SLionel Sambuc }
190433d6423SLionel Sambuc
191433d6423SLionel Sambuc *val = (adc == 0) ? CMD_READ_ADC0 : CMD_READ_ADC1;
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc /* Select the ADC to read from */
194433d6423SLionel Sambuc r = i2creg_raw_write8(bus_endpoint, address, *val);
195433d6423SLionel Sambuc if (r != OK) {
196433d6423SLionel Sambuc log_warn(&log, "Failed to write ADC read command.\n");
197433d6423SLionel Sambuc return -1;
198433d6423SLionel Sambuc }
199433d6423SLionel Sambuc
200433d6423SLionel Sambuc *val = 0;
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc /* Repeatedly read until the value is valid (i.e. the conversion
203433d6423SLionel Sambuc * finishes). Depending on the timing, the data sheet says this
204433d6423SLionel Sambuc * could take up to 400ms.
205433d6423SLionel Sambuc */
206433d6423SLionel Sambuc spin_init(&spin, 400000);
207433d6423SLionel Sambuc do {
208433d6423SLionel Sambuc r = i2creg_raw_read8(bus_endpoint, address, val);
209433d6423SLionel Sambuc if (r != OK) {
210433d6423SLionel Sambuc log_warn(&log, "Failed to read ADC%d value.\n", adc);
211433d6423SLionel Sambuc return -1;
212433d6423SLionel Sambuc }
213433d6423SLionel Sambuc
214433d6423SLionel Sambuc if (ADC_VAL_IS_VALID(*val)) {
215433d6423SLionel Sambuc return OK;
216433d6423SLionel Sambuc }
217433d6423SLionel Sambuc } while (spin_check(&spin));
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc /* Final read attempt. If the bus was really busy with other requests
220433d6423SLionel Sambuc * and the timing of things happened in the worst possible case,
221433d6423SLionel Sambuc * there is a chance that the loop above only did 1 read (slightly
222433d6423SLionel Sambuc * before 400 ms) and left the loop. To ensure there is a final read
223433d6423SLionel Sambuc * at or after the 400 ms mark, we try one last time here.
224433d6423SLionel Sambuc */
225433d6423SLionel Sambuc r = i2creg_raw_read8(bus_endpoint, address, val);
226433d6423SLionel Sambuc if (r != OK) {
227433d6423SLionel Sambuc log_warn(&log, "Failed to read ADC%d value.\n", adc);
228433d6423SLionel Sambuc return -1;
229433d6423SLionel Sambuc }
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc if (ADC_VAL_IS_VALID(*val)) {
232433d6423SLionel Sambuc return OK;
233433d6423SLionel Sambuc } else {
234433d6423SLionel Sambuc log_warn(&log, "ADC%d never returned a valid result.\n", adc);
235433d6423SLionel Sambuc return EIO;
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc }
238433d6423SLionel Sambuc
239433d6423SLionel Sambuc static int
tsl2550_init(void)240433d6423SLionel Sambuc tsl2550_init(void)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc int r;
243433d6423SLionel Sambuc uint8_t val;
244433d6423SLionel Sambuc
245433d6423SLionel Sambuc /* Power on the device */
246433d6423SLionel Sambuc r = i2creg_raw_write8(bus_endpoint, address, CMD_PWR_UP);
247433d6423SLionel Sambuc if (r != OK) {
248433d6423SLionel Sambuc log_warn(&log, "Power-up command failed.\n");
249433d6423SLionel Sambuc return -1;
250433d6423SLionel Sambuc }
251433d6423SLionel Sambuc
252433d6423SLionel Sambuc /* Read power on test value */
253433d6423SLionel Sambuc r = i2creg_raw_read8(bus_endpoint, address, &val);
254433d6423SLionel Sambuc if (r != OK) {
255433d6423SLionel Sambuc log_warn(&log, "Failed to read power on test value.\n");
256433d6423SLionel Sambuc return -1;
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc /* Check power on test value */
260433d6423SLionel Sambuc if (val != EXPECTED_PWR_UP_TEST_VAL) {
261433d6423SLionel Sambuc log_warn(&log, "Bad test value. Got 0x%x, expected 0x%x\n",
262433d6423SLionel Sambuc val, EXPECTED_PWR_UP_TEST_VAL);
263433d6423SLionel Sambuc return -1;
264433d6423SLionel Sambuc }
265433d6423SLionel Sambuc
266433d6423SLionel Sambuc /* Set range to normal */
267433d6423SLionel Sambuc r = i2creg_raw_write8(bus_endpoint, address, CMD_NORM_RANGE);
268433d6423SLionel Sambuc if (r != OK) {
269433d6423SLionel Sambuc log_warn(&log, "Normal range command failed.\n");
270433d6423SLionel Sambuc return -1;
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc return OK;
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc
276433d6423SLionel Sambuc static ssize_t
tsl2550_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))277433d6423SLionel Sambuc tsl2550_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt,
278433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
279433d6423SLionel Sambuc {
280433d6423SLionel Sambuc u64_t dev_size;
281433d6423SLionel Sambuc int bytes, r;
282433d6423SLionel Sambuc uint32_t lux;
283433d6423SLionel Sambuc
284433d6423SLionel Sambuc r = measure_lux(&lux);
285433d6423SLionel Sambuc if (r != OK) {
286433d6423SLionel Sambuc return EIO;
287433d6423SLionel Sambuc }
288433d6423SLionel Sambuc
289433d6423SLionel Sambuc memset(buffer, '\0', BUFFER_LEN + 1);
290433d6423SLionel Sambuc snprintf(buffer, BUFFER_LEN, "%-16s: %d\n", "ILLUMINANCE", lux);
291433d6423SLionel Sambuc
292433d6423SLionel Sambuc dev_size = (u64_t)strlen(buffer);
293433d6423SLionel Sambuc if (position >= dev_size) return 0;
294433d6423SLionel Sambuc if (position + size > dev_size)
295433d6423SLionel Sambuc size = (size_t)(dev_size - position);
296433d6423SLionel Sambuc
297433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, 0,
298433d6423SLionel Sambuc (vir_bytes)(buffer + (size_t)position), size);
299433d6423SLionel Sambuc
300433d6423SLionel Sambuc return (r != OK) ? r : size;
301433d6423SLionel Sambuc }
302433d6423SLionel Sambuc
303433d6423SLionel Sambuc static void
tsl2550_other(message * m,int ipc_status)304433d6423SLionel Sambuc tsl2550_other(message * m, int ipc_status)
305433d6423SLionel Sambuc {
306433d6423SLionel Sambuc int r;
307433d6423SLionel Sambuc
308433d6423SLionel Sambuc if (is_ipc_notify(ipc_status)) {
309433d6423SLionel Sambuc if (m->m_source == DS_PROC_NR) {
310433d6423SLionel Sambuc log_debug(&log,
311433d6423SLionel Sambuc "bus driver changed state, update endpoint\n");
312433d6423SLionel Sambuc i2cdriver_handle_bus_update(&bus_endpoint, bus,
313433d6423SLionel Sambuc address);
314433d6423SLionel Sambuc }
315433d6423SLionel Sambuc return;
316433d6423SLionel Sambuc }
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc
321433d6423SLionel Sambuc static int
sef_cb_lu_state_save(int UNUSED (result),int UNUSED (flags))322*e1f889d2SCristiano Giuffrida sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
323433d6423SLionel Sambuc {
324433d6423SLionel Sambuc ds_publish_u32("bus", bus, DSF_OVERWRITE);
325433d6423SLionel Sambuc ds_publish_u32("address", address, DSF_OVERWRITE);
326433d6423SLionel Sambuc return OK;
327433d6423SLionel Sambuc }
328433d6423SLionel Sambuc
329433d6423SLionel Sambuc static int
lu_state_restore(void)330433d6423SLionel Sambuc lu_state_restore(void)
331433d6423SLionel Sambuc {
332433d6423SLionel Sambuc /* Restore the state. */
333433d6423SLionel Sambuc u32_t value;
334433d6423SLionel Sambuc
335433d6423SLionel Sambuc ds_retrieve_u32("bus", &value);
336433d6423SLionel Sambuc ds_delete_u32("bus");
337433d6423SLionel Sambuc bus = (int) value;
338433d6423SLionel Sambuc
339433d6423SLionel Sambuc ds_retrieve_u32("address", &value);
340433d6423SLionel Sambuc ds_delete_u32("address");
341433d6423SLionel Sambuc address = (int) value;
342433d6423SLionel Sambuc
343433d6423SLionel Sambuc return OK;
344433d6423SLionel Sambuc }
345433d6423SLionel Sambuc
346433d6423SLionel Sambuc static int
sef_cb_init(int type,sef_init_info_t * UNUSED (info))347433d6423SLionel Sambuc sef_cb_init(int type, sef_init_info_t * UNUSED(info))
348433d6423SLionel Sambuc {
349433d6423SLionel Sambuc int r;
350433d6423SLionel Sambuc
351433d6423SLionel Sambuc if (type == SEF_INIT_LU) {
352433d6423SLionel Sambuc /* Restore the state. */
353433d6423SLionel Sambuc lu_state_restore();
354433d6423SLionel Sambuc }
355433d6423SLionel Sambuc
356433d6423SLionel Sambuc /* look-up the endpoint for the bus driver */
357433d6423SLionel Sambuc bus_endpoint = i2cdriver_bus_endpoint(bus);
358433d6423SLionel Sambuc if (bus_endpoint == 0) {
359433d6423SLionel Sambuc log_warn(&log, "Couldn't find bus driver.\n");
360433d6423SLionel Sambuc return EXIT_FAILURE;
361433d6423SLionel Sambuc }
362433d6423SLionel Sambuc
363433d6423SLionel Sambuc /* claim the device */
364433d6423SLionel Sambuc r = i2cdriver_reserve_device(bus_endpoint, address);
365433d6423SLionel Sambuc if (r != OK) {
366433d6423SLionel Sambuc log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
367433d6423SLionel Sambuc address, r);
368433d6423SLionel Sambuc return EXIT_FAILURE;
369433d6423SLionel Sambuc }
370433d6423SLionel Sambuc
371433d6423SLionel Sambuc r = tsl2550_init();
372433d6423SLionel Sambuc if (r != OK) {
373433d6423SLionel Sambuc log_warn(&log, "Device Init Failed\n");
374433d6423SLionel Sambuc return EXIT_FAILURE;
375433d6423SLionel Sambuc }
376433d6423SLionel Sambuc
377433d6423SLionel Sambuc if (type != SEF_INIT_LU) {
378433d6423SLionel Sambuc
379433d6423SLionel Sambuc /* sign up for updates about the i2c bus going down/up */
380433d6423SLionel Sambuc r = i2cdriver_subscribe_bus_updates(bus);
381433d6423SLionel Sambuc if (r != OK) {
382433d6423SLionel Sambuc log_warn(&log, "Couldn't subscribe to bus updates\n");
383433d6423SLionel Sambuc return EXIT_FAILURE;
384433d6423SLionel Sambuc }
385433d6423SLionel Sambuc
386433d6423SLionel Sambuc i2cdriver_announce(bus);
387433d6423SLionel Sambuc log_debug(&log, "announced\n");
388433d6423SLionel Sambuc }
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc return OK;
391433d6423SLionel Sambuc }
392433d6423SLionel Sambuc
393433d6423SLionel Sambuc static void
sef_local_startup(void)394433d6423SLionel Sambuc sef_local_startup(void)
395433d6423SLionel Sambuc {
396433d6423SLionel Sambuc /*
397433d6423SLionel Sambuc * Register init callbacks. Use the same function for all event types
398433d6423SLionel Sambuc */
399433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init);
400433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init);
401433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init);
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc /*
404433d6423SLionel Sambuc * Register live update callbacks.
405433d6423SLionel Sambuc */
406433d6423SLionel Sambuc sef_setcb_lu_state_save(sef_cb_lu_state_save);
407433d6423SLionel Sambuc
408433d6423SLionel Sambuc /* Let SEF perform startup. */
409433d6423SLionel Sambuc sef_startup();
410433d6423SLionel Sambuc }
411433d6423SLionel Sambuc
412433d6423SLionel Sambuc int
main(int argc,char * argv[])413433d6423SLionel Sambuc main(int argc, char *argv[])
414433d6423SLionel Sambuc {
415433d6423SLionel Sambuc int r;
416433d6423SLionel Sambuc
417433d6423SLionel Sambuc env_setargs(argc, argv);
418433d6423SLionel Sambuc
419433d6423SLionel Sambuc r = i2cdriver_env_parse(&bus, &address, valid_addrs);
420433d6423SLionel Sambuc if (r < 0) {
421433d6423SLionel Sambuc log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
422433d6423SLionel Sambuc log_warn(&log, "Example -args 'bus=1 address=0x39'\n");
423433d6423SLionel Sambuc return EXIT_FAILURE;
424433d6423SLionel Sambuc } else if (r > 0) {
425433d6423SLionel Sambuc log_warn(&log,
426433d6423SLionel Sambuc "Invalid slave address for device, expecting 0x39\n");
427433d6423SLionel Sambuc return EXIT_FAILURE;
428433d6423SLionel Sambuc }
429433d6423SLionel Sambuc
430433d6423SLionel Sambuc sef_local_startup();
431433d6423SLionel Sambuc
432433d6423SLionel Sambuc chardriver_task(&tsl2550_tab);
433433d6423SLionel Sambuc
434433d6423SLionel Sambuc return 0;
435433d6423SLionel Sambuc }
436