]> Zhao Yanbai Git Server - minix.git/commitdiff
tsl2550: driver for the TSL2550 light sensor 77/777/2
authorThomas Cort <tcort@minix3.org>
Mon, 19 Aug 2013 10:57:27 +0000 (06:57 -0400)
committerThomas Cort <tcort@minix3.org>
Thu, 22 Aug 2013 20:53:49 +0000 (16:53 -0400)
Change-Id: I9e1c87132404509ffec8bf22a8c6cc993df1aa73

commands/MAKEDEV/MAKEDEV.sh
distrib/sets/lists/minix/md.evbarm
drivers/Makefile
drivers/tsl2550/Makefile [new file with mode: 0644]
drivers/tsl2550/README.txt [new file with mode: 0644]
drivers/tsl2550/tsl2550.c [new file with mode: 0644]
etc/system.conf
include/minix/dmap.h

index e5eecf5d92f69f587b8e2388eb389233ad4fb5b6..5322a87cbf98672be18ae86f6d02532f97757a2a 100644 (file)
@@ -30,7 +30,8 @@ case $#:$1 in
        eepromb2s50 eepromb2s51 eepromb2s52 eepromb2s53 \
        eepromb2s54 eepromb2s55 eepromb2s56 eepromb2s57 \
        eepromb3s50 eepromb3s51 eepromb3s52 eepromb3s53 \
-       eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57
+       eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \
+       tsl2550b1s39 tsl2550b2s39 tsl2550b3s39
     ;;
 0:|1:-\?)
     cat >&2 <<EOF
@@ -39,6 +40,7 @@ Where key is one of the following:
   ram mem kmem null boot zero    # One of these makes all these memory devices
   fb0                    # Make /dev/fb0
   i2c-1 i2c-2 i2c-3       # Make /dev/i2c-[1-3]
+  tsl2550b{1,3}s39       # TSL2550 Ambient Light Sensors
   fd0 fd1 ...            # Floppy devices for drive 0, 1, ...
   fd0p0 fd1p0 ...        # Make floppy partitions fd0p[0-3], fd1p[0-3], ...
   c0d0 c0d1 ...                  # Make disks c0d0, c0d1, ...
@@ -307,6 +309,12 @@ do
        $e mknod eepromb${b}s5${s} b ${m} 0
        $e chmod 600 eepromb${b}s5${s}
        ;;
+    tsl2550b[1-3]s39)
+       b=`expr $dev : 'tsl2550b\\(.*\\)s39'` #bus number
+       m=`expr ${b} + 46`
+       $e mknod tsl2550b${b}s39 c ${m} 0
+       $e chmod 444 tsl2550b${b}s39
+       ;;
     *)
        echo "$0: don't know about $dev" >&2
        ex=1
index bcd293634a248e31b4b6b3c121b6436a8eb70cf9..679cdce36ecb9f13c8b26a503f2679f27be49581 100644 (file)
 ./usr/sbin/tda19988                    minix-sys
 ./usr/sbin/tps65217                    minix-sys
 ./usr/sbin/tps65950                    minix-sys
+./usr/sbin/tsl2550                     minix-sys
 ./usr/tests/minix-posix/mod            minix-sys
 ./usr/tests/minix-posix/test63         minix-sys
index 6c9f811ef7c863e77a7d7d1417a98336ce2922ea..6f6e220b0dcba492e822d5e95a811540af7c5762 100644 (file)
@@ -24,7 +24,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
 
 .if ${MACHINE_ARCH} == "earm"
 SUBDIR= cat24c256 fb gpio i2c mmc lan8710a log readclock \
-       tda19988 tps65217 tps65950 tty random
+       tda19988 tps65217 tps65950 tsl2550 tty random
 .endif
 
 .endif # ${MKIMAGEONLY} != "yes"
diff --git a/drivers/tsl2550/Makefile b/drivers/tsl2550/Makefile
new file mode 100644 (file)
index 0000000..19896dc
--- /dev/null
@@ -0,0 +1,14 @@
+# Makefile for the tsl2550 ambient light sensor found on the Weather Cape.
+PROG=  tsl2550
+SRCS=  tsl2550.c
+
+DPADD+=        ${LIBI2CDRIVER} ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
+LDADD+=        -li2cdriver -lchardriver -lsys -ltimers
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+CPPFLAGS+=     -I${NETBSDSRCDIR}
+
+.include <minix.service.mk>
diff --git a/drivers/tsl2550/README.txt b/drivers/tsl2550/README.txt
new file mode 100644 (file)
index 0000000..a7bb757
--- /dev/null
@@ -0,0 +1,46 @@
+TSL2550 Driver (Ambient Light Sensor)
+=====================================
+
+Overview
+--------
+
+This is the driver for the ambient light sensor commonly found on the
+WeatherCape expansion board for the BeagleBone.
+
+Interface
+---------
+
+This driver implements the character device interface. It supports reading
+through /dev/tsl2550b{1,3}s39. When read from, it returns a string containing
+a data label, a colon, and the sensor value.
+
+Example output of `cat /dev/tsl2550b3s39`:
+
+ILLUMINANCE     : 830
+
+Illuminance is expressed in lux. Valid values are 0 to 1846.
+
+Limitations
+-----------
+
+Extended mode isn't implemented. Normal mode should be sufficient for most
+applications.
+
+Testing the Code
+----------------
+
+The driver should have been started by a script in /etc/rc.capes/ If not,
+this is how you start up an instance:
+
+cd /dev && MAKEDEV tsl2550b3s39
+/bin/service up /usr/sbin/tsl2550 -label tsl2550.3.39 -dev /dev/tsl2550b3s39 \
+       -args 'bus=3 address=0x39'
+
+Getting the sensor value:
+
+cat /dev/tsl2550b3s39
+
+Killing an instance:
+
+/bin/service down tsl2550.3.39
+
diff --git a/drivers/tsl2550/tsl2550.c b/drivers/tsl2550/tsl2550.c
new file mode 100644 (file)
index 0000000..06cc31d
--- /dev/null
@@ -0,0 +1,567 @@
+/* Driver for the TSL2550 Ambient Light Sensor */
+
+#include <minix/ds.h>
+#include <minix/drivers.h>
+#include <minix/i2c.h>
+#include <minix/i2cdriver.h>
+#include <minix/chardriver.h>
+#include <minix/log.h>
+#include <minix/type.h>
+#include <minix/spin.h>
+
+/*
+ * Device Commands
+ */
+#define CMD_PWR_DOWN 0x00
+#define CMD_PWR_UP 0x03
+#define CMD_EXT_RANGE 0x1d
+#define CMD_NORM_RANGE 0x18
+#define CMD_READ_ADC0 0x43
+#define CMD_READ_ADC1 0x83
+
+/* When powered up and communicating, the register should have this value */
+#define EXPECTED_PWR_UP_TEST_VAL 0x03
+
+/* Maximum Lux value in Standard Mode */
+#define MAX_LUX_STD_MODE 1846
+
+/* Bit Masks for ADC Data */
+#define ADC_VALID_MASK (1<<7)
+#define ADC_CHORD_MASK ((1<<6)|(1<<5)|(1<<4))
+#define ADC_STEP_MASK ((1<<3)|(1<<2)|(1<<1)|(1<<0))
+
+#define ADC_VAL_IS_VALID(x) ((x & ADC_VALID_MASK) == ADC_VALID_MASK)
+#define ADC_VAL_TO_CHORD_BITS(x) ((x & ADC_CHORD_MASK) >> 4)
+#define ADC_VAL_TO_STEP_BITS(x) (x & ADC_STEP_MASK)
+
+/* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
+static struct log log = {
+       .name = "tsl2550",
+       .log_level = LEVEL_INFO,
+       .log_func = default_log
+};
+
+/* The slave address is hardwired to 0x39 and cannot be changed. */
+static i2c_addr_t valid_addrs[2] = {
+       0x39, 0x00
+};
+
+/* Buffer to store output string returned when reading from device file. */
+#define BUFFER_LEN 32
+char buffer[BUFFER_LEN + 1];
+
+/* the bus that this device is on (counting starting at 1) */
+static uint32_t bus;
+
+/* slave address of the device */
+static i2c_addr_t address;
+
+/* endpoint for the driver for the bus itself. */
+static endpoint_t bus_endpoint;
+
+/* register access functions */
+static int reg_read(uint8_t * val);
+static int reg_write(uint8_t val);
+
+/* main driver functions */
+static int tsl2550_init(void);
+static int adc_read(int adc, uint8_t * val);
+static int measure_lux(uint32_t * lux);
+
+/* libchardriver callbacks */
+static struct device *tsl2550_prepare(dev_t UNUSED(dev));
+static int tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position,
+    iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
+    unsigned int UNUSED(flags));
+static int tsl2550_other(message * m);
+
+/* SEF functions */
+static int sef_cb_lu_state_save(int);
+static int lu_state_restore(void);
+static int sef_cb_init(int type, sef_init_info_t * info);
+static void sef_local_startup(void);
+
+/* Entry points to this driver from libchardriver. */
+static struct chardriver tsl2550_tab = {
+       .cdr_open = do_nop,
+       .cdr_close = do_nop,
+       .cdr_ioctl = nop_ioctl,
+       .cdr_prepare = tsl2550_prepare,
+       .cdr_transfer = tsl2550_transfer,
+       .cdr_cleanup = nop_cleanup,
+       .cdr_alarm = nop_alarm,
+       .cdr_cancel = nop_cancel,
+       .cdr_select = nop_select,
+       .cdr_other = tsl2550_other
+};
+
+static struct device tsl2550_device = {
+       .dv_base = 0,
+       .dv_size = 0
+};
+
+/*
+ * These two lookup tables and the formulas used in measure_lux() are from
+ * 'TAOS INTELLIGENT OPTO SENSOR DESIGNER'S NOTEBOOK' Number 9
+ * 'Simplified TSL2550 Lux Calculation for Embedded and Micro Controllers'.
+ *
+ * The tables and formulas eliminate the need for floating point math and
+ * functions from libm. It also speeds up the calculations.
+ */
+
+/* Look up table for converting ADC values to ADC counts */
+static const uint32_t adc_counts_lut[128] = {
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       16, 18, 20, 22, 24, 26, 28, 30,
+       32, 34, 36, 38, 40, 42, 44, 46,
+       49, 53, 57, 61, 65, 69, 73, 77,
+       81, 85, 89, 93, 97, 101, 105, 109,
+       115, 123, 131, 139, 147, 155, 163, 171,
+       179, 187, 195, 203, 211, 219, 227, 235,
+       247, 263, 279, 295, 311, 327, 343, 359,
+       375, 391, 407, 423, 439, 455, 471, 487,
+       511, 543, 575, 607, 639, 671, 703, 735,
+       767, 799, 831, 863, 895, 927, 959, 991,
+       1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
+       1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
+       2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
+       3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015
+};
+
+/* Look up table of scaling factors */
+static const uint32_t ratio_lut[129] = {
+       100, 100, 100, 100, 100, 100, 100, 100,
+       100, 100, 100, 100, 100, 100, 99, 99,
+       99, 99, 99, 99, 99, 99, 99, 99,
+       99, 99, 99, 98, 98, 98, 98, 98,
+       98, 98, 97, 97, 97, 97, 97, 96,
+       96, 96, 96, 95, 95, 95, 94, 94,
+       93, 93, 93, 92, 92, 91, 91, 90,
+       89, 89, 88, 87, 87, 86, 85, 84,
+       83, 82, 81, 80, 79, 78, 77, 75,
+       74, 73, 71, 69, 68, 66, 64, 62,
+       60, 58, 56, 54, 52, 49, 47, 44,
+       42, 41, 40, 40, 39, 39, 38, 38,
+       37, 37, 37, 36, 36, 36, 35, 35,
+       35, 35, 34, 34, 34, 34, 33, 33,
+       33, 33, 32, 32, 32, 32, 32, 31,
+       31, 31, 31, 31, 30, 30, 30, 30,
+       30
+};
+
+static int
+measure_lux(uint32_t * lux)
+{
+       int r;
+       uint8_t adc0_val, adc1_val;
+       uint32_t adc0_cnt, adc1_cnt;
+       uint32_t ratio;
+
+       r = adc_read(0, &adc0_val);
+       if (r != OK) {
+               return -1;
+       }
+
+       r = adc_read(1, &adc1_val);
+       if (r != OK) {
+               return -1;
+       }
+
+       /* Look up the adc count, drop the MSB to put in range 0-127. */
+       adc0_cnt = adc_counts_lut[adc0_val & ~ADC_VALID_MASK];
+       adc1_cnt = adc_counts_lut[adc1_val & ~ADC_VALID_MASK];
+
+       /* default scaling factor */
+       ratio = 128;
+
+       /* calculate ratio - avoid div by 0, ensure cnt1 <= cnt0 */
+       if ((adc0_cnt != 0) && (adc1_cnt <= adc0_cnt)) {
+               ratio = (adc1_cnt * 128 / adc0_cnt);
+       }
+
+       /* ensure ratio isn't outside ratio_lut[] */
+       if (ratio > 128) {
+               ratio = 128;
+       }
+
+       /* calculate lux */
+       *lux = ((adc0_cnt - adc1_cnt) * ratio_lut[ratio]) / 256;
+
+       /* range check */
+       if (*lux > MAX_LUX_STD_MODE) {
+               *lux = MAX_LUX_STD_MODE;
+       }
+
+       return OK;
+}
+
+static int
+adc_read(int adc, uint8_t * val)
+{
+       int r;
+       spin_t spin;
+
+       if (adc != 0 && adc != 1) {
+               log_warn(&log, "Invalid ADC number %d, expected 0 or 1.\n",
+                   adc);
+               return EINVAL;
+       }
+
+       if (val == NULL) {
+               log_warn(&log, "Read called with a NULL pointer.\n");
+               return EINVAL;
+       }
+
+       *val = (adc == 0) ? CMD_READ_ADC0 : CMD_READ_ADC1;
+
+       /* Select the ADC to read from */
+       r = reg_write(*val);
+       if (r != OK) {
+               log_warn(&log, "Failed to write ADC read command.\n");
+               return -1;
+       }
+
+       *val = 0;
+
+       /* Repeatedly read until the value is valid (i.e. the conversion
+        * finishes). Depending on the timing, the data sheet says this
+        * could take up to 400ms.
+        */
+       spin_init(&spin, 400000);
+       do {
+               r = reg_read(val);
+               if (r != OK) {
+                       log_warn(&log, "Failed to read ADC%d value.\n", adc);
+                       return -1;
+               }
+
+               if (ADC_VAL_IS_VALID(*val)) {
+                       return OK;
+               }
+       } while (spin_check(&spin));
+
+       /* Final read attempt. If the bus was really busy with other requests
+        * and the timing of things happened in the worst possible case,
+        * there is a chance that the loop above only did 1 read (slightly
+        * before 400 ms) and left the loop. To ensure there is a final read
+        * at or after the 400 ms mark, we try one last time here.
+        */
+       r = reg_read(val);
+       if (r != OK) {
+               log_warn(&log, "Failed to read ADC%d value.\n", adc);
+               return -1;
+       }
+
+       if (ADC_VAL_IS_VALID(*val)) {
+               return OK;
+       } else {
+               log_warn(&log, "ADC%d never returned a valid result.\n", adc);
+               return EIO;
+       }
+}
+
+static int
+reg_read(uint8_t * val)
+{
+       int r;
+       minix_i2c_ioctl_exec_t ioctl_exec;
+
+       if (val == NULL) {
+               log_warn(&log, "Read called with a NULL pointer.\n");
+               return EINVAL;
+       }
+
+       memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
+
+       /* Read from chip */
+       ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
+       ioctl_exec.iie_addr = address;
+
+       /* No register address to write */
+       ioctl_exec.iie_cmdlen = 0;
+
+       /* Read one byte */
+       ioctl_exec.iie_buflen = 1;
+
+       r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
+       if (r != OK) {
+               log_warn(&log, "reg_read() failed (r=%d)\n", r);
+               return -1;
+       }
+
+       *val = ioctl_exec.iie_buf[0];
+
+       log_trace(&log, "Read 0x%x from reg\n", *val);
+
+       return OK;
+}
+
+static int
+reg_write(uint8_t val)
+{
+       int r;
+       minix_i2c_ioctl_exec_t ioctl_exec;
+
+       switch (val) {
+       case CMD_PWR_DOWN:
+       case CMD_PWR_UP:
+       case CMD_EXT_RANGE:
+       case CMD_NORM_RANGE:
+       case CMD_READ_ADC0:
+       case CMD_READ_ADC1:
+               /* Command is valid */
+               break;
+       default:
+               log_warn(&log,
+                   "reg_write() called with invalid command 0x%x\n", val);
+               return EINVAL;
+       }
+
+       memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
+
+       /* Write to chip */
+       ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
+       ioctl_exec.iie_addr = address;
+
+       /* No command bytes for writing to this chip */
+       ioctl_exec.iie_cmdlen = 0;
+
+       /* Set the byte to write */
+       ioctl_exec.iie_buf[0] = val;
+       ioctl_exec.iie_buflen = 1;
+
+       r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
+       if (r != OK) {
+               log_warn(&log, "reg_write() failed (r=%d)\n", r);
+               return -1;
+       }
+
+       log_trace(&log, "Wrote 0x%x to reg\n", val);
+
+       return OK;
+}
+
+static int
+tsl2550_init(void)
+{
+       int r;
+       uint8_t val;
+
+       /* Power on the device */
+       r = reg_write(CMD_PWR_UP);
+       if (r != OK) {
+               log_warn(&log, "Power-up command failed.\n");
+               return -1;
+       }
+
+       /* Read power on test value */
+       r = reg_read(&val);
+       if (r != OK) {
+               log_warn(&log, "Failed to read power on test value.\n");
+               return -1;
+       }
+
+       /* Check power on test value */
+       if (val != EXPECTED_PWR_UP_TEST_VAL) {
+               log_warn(&log, "Bad test value. Got 0x%x, expected 0x%x\n",
+                   val, EXPECTED_PWR_UP_TEST_VAL);
+               return -1;
+       }
+
+       /* Set range to normal */
+       r = reg_write(CMD_NORM_RANGE);
+       if (r != OK) {
+               log_warn(&log, "Normal range command failed.\n");
+               return -1;
+       }
+
+       return OK;
+}
+
+static struct device *
+tsl2550_prepare(dev_t UNUSED(dev))
+{
+       return &tsl2550_device;
+}
+
+static int
+tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position,
+    iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
+    unsigned int UNUSED(flags))
+{
+       int bytes, r;
+       uint32_t lux;
+
+       r = measure_lux(&lux);
+       if (r != OK) {
+               return EIO;
+       }
+
+       memset(buffer, '\0', BUFFER_LEN + 1);
+       snprintf(buffer, BUFFER_LEN, "%-16s: %d\n", "ILLUMINANCE", lux);
+
+       bytes = strlen(buffer) - position < iov->iov_size ?
+           strlen(buffer) - position : iov->iov_size;
+
+       if (bytes <= 0) {
+               return OK;
+       }
+
+       switch (opcode) {
+       case DEV_GATHER_S:
+               r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
+                   (vir_bytes) (buffer + position), bytes);
+               iov->iov_size -= bytes;
+               break;
+       default:
+               return EINVAL;
+       }
+
+       return r;
+}
+
+static int
+tsl2550_other(message * m)
+{
+       int r;
+
+       switch (m->m_type) {
+       case NOTIFY_MESSAGE:
+               if (m->m_source == DS_PROC_NR) {
+                       log_debug(&log,
+                           "bus driver changed state, update endpoint\n");
+                       i2cdriver_handle_bus_update(&bus_endpoint, bus,
+                           address);
+               }
+               r = OK;
+               break;
+       default:
+               log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
+               r = EINVAL;
+               break;
+       }
+
+       return r;
+}
+
+static int
+sef_cb_lu_state_save(int UNUSED(state))
+{
+       ds_publish_u32("bus", bus, DSF_OVERWRITE);
+       ds_publish_u32("address", address, DSF_OVERWRITE);
+       return OK;
+}
+
+static int
+lu_state_restore(void)
+{
+       /* Restore the state. */
+       u32_t value;
+
+       ds_retrieve_u32("bus", &value);
+       ds_delete_u32("bus");
+       bus = (int) value;
+
+       ds_retrieve_u32("address", &value);
+       ds_delete_u32("address");
+       address = (int) value;
+
+       return OK;
+}
+
+static int
+sef_cb_init(int type, sef_init_info_t * UNUSED(info))
+{
+       int r;
+
+       if (type == SEF_INIT_LU) {
+               /* Restore the state. */
+               lu_state_restore();
+       }
+
+       /* look-up the endpoint for the bus driver */
+       bus_endpoint = i2cdriver_bus_endpoint(bus);
+       if (bus_endpoint == 0) {
+               log_warn(&log, "Couldn't find bus driver.\n");
+               return EXIT_FAILURE;
+       }
+
+       /* claim the device */
+       r = i2cdriver_reserve_device(bus_endpoint, address);
+       if (r != OK) {
+               log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
+                   address, r);
+               return EXIT_FAILURE;
+       }
+
+       r = tsl2550_init();
+       if (r != OK) {
+               log_warn(&log, "Device Init Failed\n");
+               return EXIT_FAILURE;
+       }
+
+       if (type != SEF_INIT_LU) {
+
+               /* sign up for updates about the i2c bus going down/up */
+               r = i2cdriver_subscribe_bus_updates(bus);
+               if (r != OK) {
+                       log_warn(&log, "Couldn't subscribe to bus updates\n");
+                       return EXIT_FAILURE;
+               }
+
+               i2cdriver_announce(bus);
+               log_debug(&log, "announced\n");
+       }
+
+       return OK;
+}
+
+static void
+sef_local_startup(void)
+{
+       /*
+        * Register init callbacks. Use the same function for all event types
+        */
+       sef_setcb_init_fresh(sef_cb_init);
+       sef_setcb_init_lu(sef_cb_init);
+       sef_setcb_init_restart(sef_cb_init);
+
+       /*
+        * Register live update callbacks.
+        */
+       /* Agree to update immediately when LU is requested in a valid state. */
+       sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
+       /* Support live update starting from any standard state. */
+       sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
+       /* Register a custom routine to save the state. */
+       sef_setcb_lu_state_save(sef_cb_lu_state_save);
+
+       /* Let SEF perform startup. */
+       sef_startup();
+}
+
+int
+main(int argc, char *argv[])
+{
+       int r;
+
+       env_setargs(argc, argv);
+
+       r = i2cdriver_env_parse(&bus, &address, valid_addrs);
+       if (r < 0) {
+               log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
+               log_warn(&log, "Example -args 'bus=1 address=0x39'\n");
+               return EXIT_FAILURE;
+       } else if (r > 0) {
+               log_warn(&log,
+                   "Invalid slave address for device, expecting 0x39\n");
+               return EXIT_FAILURE;
+       }
+
+       sef_local_startup();
+
+       chardriver_task(&tsl2550_tab, CHARDRIVER_SYNC);
+
+       return 0;
+}
index 47045888f9fb5cc1dfd3e159e214d535800462d8..d37739e5ab1007db86e5d670ee22d58b3eeaf219 100644 (file)
@@ -636,6 +636,11 @@ service tps65950
        ipc SYSTEM RS DS i2c readclock.drv;
 };
 
+service tsl2550
+{
+       ipc SYSTEM RS DS i2c;
+};
+
 service vbox
 {
        system
index 5adc17cbd9d32d927014b57fc55b86cc8868b663..73ef35c22a710f1bdd18abb2d643494d5b809d1f 100644 (file)
@@ -66,6 +66,10 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
 #define EEPROMB3S55_MAJOR        44    /* 44 = /dev/eepromb3s55 (cat24c256)  */
 #define EEPROMB3S56_MAJOR        45    /* 45 = /dev/eepromb3s56 (cat24c256)  */
 #define EEPROMB3S57_MAJOR        46    /* 46 = /dev/eepromb3s57 (cat24c256)  */
+#define TSL2550B1S39_MAJOR       47    /* 47 = /dev/tsl2550b1s39 (tsl2550)   */
+#define TSL2550B2S39_MAJOR       48    /* 48 = /dev/tsl2550b2s39 (tsl2550)   */
+#define TSL2550B3S39_MAJOR       49    /* 49 = /dev/tsl2550b3s39 (tsl2550)   */
+
 
 /* Minor device numbers for memory driver. */
 #  define RAM_DEV_OLD                     0    /* minor device for /dev/ram */