Add ambient light sensor HAL

Add ambient light sensor HAL for tsl258x sensor base input subsys.

Change-Id: I16999c6d54ddb9889d2769a0a372029f4abe2fd1
Tracked-On: https://jira01.devtools.intel.com/browse/MARVIN-551
Signed-off-by: Baixing Tan <baixingx.tan@intel.com>
Reviewed-on: https://android.intel.com:443/356619
diff --git a/als/AlsSensor.cpp b/als/AlsSensor.cpp
new file mode 100644
index 0000000..61afd66
--- /dev/null
+++ b/als/AlsSensor.cpp
@@ -0,0 +1,184 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "AlsSensor.h"
+
+#define ALS_DATA_NAME "tsl2584 ambient light sensor"
+#define SYSFS_ENABLE_FILE "/sys/class/i2c-adapter/i2c-6/6-0029/als_enable"
+#define SYSFS_POLL_FILE "/sys/class/i2c-adapter/i2c-6/6-0029/als_delay"
+
+/*****************************************************************************/
+
+#define FIRST_GOOD_EVENT    1
+
+LightSensor::LightSensor()
+    : SensorBase(NULL, ALS_DATA_NAME),
+      mEnabled(0),
+      mEventsSinceEnable(0),
+      mInputReader(4),
+      mHasPendingEvent(false)
+{
+    mPendingEvent.version = sizeof(sensors_event_t);
+    mPendingEvent.sensor = ID_L;
+    mPendingEvent.type = SENSOR_TYPE_LIGHT;
+    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+}
+
+LightSensor::~LightSensor() {
+    if (mEnabled) {
+        enable(0, 0);
+    }
+}
+
+int LightSensor::setDelay(int32_t /* handle */, int64_t ns)
+{
+    int fd;
+    int len, ms, ret = -1;
+    char buf[6];
+
+    ms = ns / 1000000;
+
+    fd = open(SYSFS_POLL_FILE, O_RDWR);
+    if (fd) {
+        len = 6;
+        memset(buf, 0, len);
+        snprintf(buf, len, "%d", ms);
+        write(fd, buf, sizeof(buf));
+        close(fd);
+        ret = 0;
+    } else
+        ALOGE("file  open failure\n");
+
+    return ret;
+}
+int LightSensor::enable(int32_t /* handle */, int en)
+{
+    int flags = en ? 1 : 0;
+
+    mEventsSinceEnable = 0;
+    mPreviousLight = -1;
+    if (flags != mEnabled) {
+        int fd;
+        fd = open(SYSFS_ENABLE_FILE, O_RDWR);
+        if (fd >= 0) {
+            char buf[2];
+            buf[1] = 0;
+            if (flags) {
+                buf[0] = '1';
+            } else {
+                buf[0] = '0';
+            }
+            write(fd, buf, sizeof(buf));
+            close(fd);
+            mEnabled = flags;
+            return 0;
+        }
+        return -1;
+    }
+
+    if (en)
+        mEnabled=1;
+    else
+        mEnabled=0;
+
+    return 0;
+}
+
+#ifdef HAL_VERSION_GT_1_0
+int LightSensor::batch(int /* handle */, int /* flags */, int64_t period_ns, int64_t /* timeout */)
+{
+    int fd;
+    int len, ms, ret = -1;
+    char buf[6];
+
+    ms = period_ns / 1000000;
+
+    fd = open(SYSFS_POLL_FILE, O_RDWR);
+    if (fd) {
+       len = 6;
+       memset(buf, 0, len);
+       snprintf(buf, len, "%d", ms);
+       write(fd, buf, sizeof(buf));
+       close(fd);
+       ret = 0;
+    }
+    else
+        ALOGE("file  open failure\n");
+
+    return ret;
+}
+#endif
+
+bool LightSensor::hasPendingEvents() const {
+    return mHasPendingEvent;
+}
+
+int LightSensor::readEvents(sensors_event_t* data, int count)
+{
+    if (count < 1)
+        return -EINVAL;
+
+    if (mHasPendingEvent) {
+        mHasPendingEvent = false;
+        mPendingEvent.timestamp = getTimestamp();
+        *data = mPendingEvent;
+        return mEnabled ? 1 : 0;
+    }
+
+    ssize_t n = mInputReader.fill(data_fd);
+    if (n < 0)
+        return n;
+
+    int numEventReceived = 0;
+    input_event const* event;
+
+    while (count && mInputReader.readEvent(&event)) {
+        int type = event->type;
+        if (type == EV_MSC) {
+            if (event->code == EVENT_TYPE_LIGHT) {
+                 mPendingEvent.light = event->value;
+                 if (mEventsSinceEnable < FIRST_GOOD_EVENT)
+                    mEventsSinceEnable++;
+            }
+        } else if (type == EV_SYN) {
+            mPendingEvent.timestamp = timevalToNano(event->time);
+            if (mEnabled && (mPendingEvent.light != mPreviousLight) &&
+                    mEventsSinceEnable >= FIRST_GOOD_EVENT) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+                mPreviousLight = mPendingEvent.light;
+            }
+        } else {
+            ALOGE("LightSensor: unknown event (type=%d, code=%d)",
+                    type, event->code);
+        }
+        mInputReader.next();
+    }
+
+    return numEventReceived;
+}
diff --git a/als/AlsSensor.h b/als/AlsSensor.h
new file mode 100644
index 0000000..a393b0b
--- /dev/null
+++ b/als/AlsSensor.h
@@ -0,0 +1,65 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+#ifndef ANDROID_LIGHT_SENSOR_H
+#define ANDROID_LIGHT_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "sensors.h"
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+/* the GP2A is a binary proximity sensor that triggers around 5 cm on
+ * this hardware */
+#define PROXIMITY_THRESHOLD_GP2A  5.0f
+
+struct input_event;
+
+class LightSensor : public SensorBase {
+    int mEnabled;
+    int mEventsSinceEnable;
+    InputEventCircularReader mInputReader;
+    sensors_event_t mPendingEvent;
+    bool mHasPendingEvent;
+    char input_sysfs_path[PATH_MAX];
+    int input_sysfs_path_len;
+
+    int setInitialState();
+    float mPreviousLight;
+    float indexToValue(size_t index) const;
+
+public:
+            LightSensor();
+    virtual ~LightSensor();
+    virtual int readEvents(sensors_event_t* data, int count);
+    virtual bool hasPendingEvents() const;
+    virtual int setDelay(int32_t handle, int64_t ns);
+    virtual int enable(int32_t handle, int enabled);
+#ifdef HAL_VERSION_GT_1_0
+    virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
+#endif
+
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_LIGHT_SENSOR_H
diff --git a/als/Android.mk b/als/Android.mk
new file mode 100644
index 0000000..f824d5e
--- /dev/null
+++ b/als/Android.mk
@@ -0,0 +1,78 @@
+# Copyright (C) 2015 Intel Corp
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation, not prelinked, and stored in
+# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+
+# ANDROID version check
+MAJOR_VERSION := $(shell echo $(PLATFORM_VERSION) | cut -f1 -d.)
+MINOR_VERSION := $(shell echo $(PLATFORM_VERSION) | cut -f2 -d.)
+
+VERSION_JB := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 1 && echo true)
+VERSION_JB := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 2 && echo true)
+VERSION_JB_MR2 := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 3 && echo true)
+VERSION_KK := $(shell test $(MAJOR_VERSION) -eq 4 -a $(MINOR_VERSION) -eq 4 && echo true)
+VERSION_L := $(shell test $(MAJOR_VERSION) -eq 5 && echo true)
+#ANDROID version check END
+
+LOCAL_MODULE := sensor_als.$(TARGET_DEVICE)
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_MODULE_TAGS := optional
+# TODO: remove LOG_NDEBUG=0 for production builds, keep it during integration
+LOCAL_CFLAGS := -DLOG_TAG=\"MvnSensors\" -DLOG_NDEBUG=0
+LOCAL_CFLAGS += -DINVENSENSE_COMPASS_CAL
+
+ifeq ($(VERSION_JB),true)
+LOCAL_CFLAGS += -DANDROID_JB
+endif
+
+ifeq ($(VERSION_JBMR2),true)
+LOCAL_CFLAGS += -DANDROID_JBMR2
+#hal version is greater than and equal 1_0
+LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0
+endif
+
+ifeq ($(VERSION_KK),true)
+LOCAL_CFLAGS += -DANDROID_KK
+#hal version is greater than and equal 1_0
+LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0
+#hal version is greater than 1_0
+LOCAL_CFLAGS += -DHAL_VERSION_GT_1_0
+endif
+
+ifeq ($(VERSION_L),true)
+LOCAL_CFLAGS += -DANDROID_L
+#hal version is greater than and equal 1_0
+LOCAL_CFLAGS += -DHAL_VERSION_GE_1_0
+#hal version is greater than 1_0
+LOCAL_CFLAGS += -DHAL_VERSION_GT_1_0
+endif
+
+#LOCAL_C_INCLUDES += hardware/invensense/libsensors_iio
+LOCAL_SRC_FILES := \
+    sensors.cpp \
+    InputEventReader.cpp \
+    AlsSensor.cpp \
+    SensorBase.cpp
+
+LOCAL_SHARED_LIBRARIES := liblog libutils libdl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/als/InputEventReader.cpp b/als/InputEventReader.cpp
new file mode 100644
index 0000000..b747b6f
--- /dev/null
+++ b/als/InputEventReader.cpp
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <linux/input.h>
+#include <cutils/log.h>
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+InputEventCircularReader::InputEventCircularReader(size_t numEvents)
+    : mBuffer(new input_event[numEvents * 2]),
+      mBufferEnd(mBuffer + numEvents),
+      mHead(mBuffer),
+      mCurr(mBuffer),
+      mFreeSpace(numEvents)
+{
+    FUNC_LOG;
+    mLastFd = -1;
+}
+
+InputEventCircularReader::~InputEventCircularReader()
+{
+    FUNC_LOG;
+    delete [] mBuffer;
+}
+
+/* TODO: clear DEBUG flag on production builds, keep it during integration */
+#define INPUT_EVENT_DEBUG (1)
+ssize_t InputEventCircularReader::fill(int fd)
+{
+    FUNC_LOG;
+    size_t numEventsRead = 0;
+    mLastFd = fd;
+
+    LOGV_IF(INPUT_EVENT_DEBUG,
+            "DEBUG:%s enter, fd=%d\n", __PRETTY_FUNCTION__, fd);
+    if (mFreeSpace) {
+        const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));
+        if (nread < 0 || nread % sizeof(input_event)) {
+            if (INPUT_EVENT_DEBUG) {
+                LOGV_IF(nread < 0, "DEBUG:%s exit nread < 0\n",
+                        __PRETTY_FUNCTION__);
+                LOGV_IF(nread % sizeof(input_event),
+                        "DEBUG:%s exit nread %% sizeof(input_event)\n",
+                        __PRETTY_FUNCTION__);
+            }
+            return (nread < 0 ? -errno : -EINVAL);
+        }
+
+        numEventsRead = nread / sizeof(input_event);
+        if (numEventsRead) {
+            mHead += numEventsRead;
+            mFreeSpace -= numEventsRead;
+            if (mHead > mBufferEnd) {
+                size_t s = mHead - mBufferEnd;
+                memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));
+                mHead = mBuffer + s;
+            }
+        }
+    }
+
+    LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s exit, numEventsRead:%d\n",
+            __PRETTY_FUNCTION__, numEventsRead);
+    return numEventsRead;
+}
+
+ssize_t InputEventCircularReader::readEvent(input_event const** events)
+{
+    FUNC_LOG;
+    *events = mCurr;
+    ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;
+    LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s fd:%d, available:%d\n",
+            __PRETTY_FUNCTION__, mLastFd, (int)available);
+    return (available ? 1 : 0);
+}
+
+void InputEventCircularReader::next()
+{
+    FUNC_LOG;
+    mCurr++;
+    mFreeSpace++;
+    if (mCurr >= mBufferEnd) {
+        mCurr = mBuffer;
+    }
+    ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;
+    LOGV_IF(INPUT_EVENT_DEBUG, "DEBUG:%s fd:%d, still available:%d\n",
+            __PRETTY_FUNCTION__, mLastFd, (int)available);
+}
+
diff --git a/als/InputEventReader.h b/als/InputEventReader.h
new file mode 100644
index 0000000..ab09458
--- /dev/null
+++ b/als/InputEventReader.h
@@ -0,0 +1,50 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef ANDROID_INPUT_EVENT_READER_H
+#define ANDROID_INPUT_EVENT_READER_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class InputEventCircularReader
+{
+    struct input_event* const mBuffer;
+    struct input_event* const mBufferEnd;
+    struct input_event* mHead;
+    struct input_event* mCurr;
+    ssize_t mFreeSpace;
+    int mLastFd;
+
+public:
+    InputEventCircularReader(size_t numEvents);
+    ~InputEventCircularReader();
+    ssize_t fill(int fd);
+    ssize_t readEvent(input_event const** events);
+    void next();
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_INPUT_EVENT_READER_H
diff --git a/als/SensorBase.cpp b/als/SensorBase.cpp
new file mode 100644
index 0000000..5cdf7cf
--- /dev/null
+++ b/als/SensorBase.cpp
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+#include <linux/input.h>
+
+#include "SensorBase.h"
+
+/*****************************************************************************/
+
+SensorBase::SensorBase(const char* dev_name,
+                       const char* data_name) : dev_name(dev_name),
+                                                data_name(data_name),
+                                                dev_fd(-1),
+                                                data_fd(-1)
+{
+    FUNC_LOG;
+    ALOGV("%s(): dev_name=%s, data_name=%s ", __func__, dev_name, data_name);
+
+    if (data_name) {
+        data_fd = openInput(data_name);
+    }
+}
+
+SensorBase::~SensorBase() {
+    FUNC_LOG;
+    if (data_fd >= 0) {
+        close(data_fd);
+    }
+    if (dev_fd >= 0) {
+        close(dev_fd);
+    }
+}
+
+int SensorBase::open_device() {
+    FUNC_LOG;
+    if (dev_fd<0 && dev_name) {
+        dev_fd = open(dev_name, O_RDONLY);
+        LOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno));
+    }
+    return 0;
+}
+
+int SensorBase::close_device() {
+    FUNC_LOG;
+    if (dev_fd >= 0) {
+        close(dev_fd);
+        dev_fd = -1;
+    }
+    return 0;
+}
+
+int SensorBase::getFd() const {
+    FUNC_LOG;
+    if (!data_name) {
+        return dev_fd;
+    }
+    return data_fd;
+}
+
+int SensorBase::setDelay(int32_t /* handle */, int64_t /* ns */) {
+    FUNC_LOG;
+    return 0;
+}
+
+bool SensorBase::hasPendingEvents() const {
+    FUNC_LOG;
+    return false;
+}
+
+int64_t SensorBase::getTimestamp() {
+    FUNC_LOG;
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_BOOTTIME, &t);
+    return int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+
+int SensorBase::openInput(const char* inputName) {
+    FUNC_LOG;
+    int fd = -1;
+    const char *dirname = "/dev/input";
+    char devname[PATH_MAX];
+    char *filename;
+    DIR *dir;
+    struct dirent *de;
+    dir = opendir(dirname);
+    if(dir == NULL)
+        return -1;
+    strcpy(devname, dirname);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+    while((de = readdir(dir))) {
+        if(de->d_name[0] == '.' &&
+                (de->d_name[1] == '\0' ||
+                        (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+            continue;
+        strcpy(filename, de->d_name);
+        fd = open(devname, O_RDONLY);
+        LOGV_IF(EXTRA_VERBOSE, "path open %s", devname);
+        LOGI("path open %s", devname);
+        if (fd >= 0) {
+            char name[80];
+            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+                name[0] = '\0';
+            }
+            LOGV_IF(EXTRA_VERBOSE, "name read %s", name);
+            if (!strncmp(name, inputName, strlen(inputName))) {
+                break;
+            } else {
+                close(fd);
+                fd = -1;
+            }
+        }
+    }
+    closedir(dir);
+    LOGE_IF(fd < 0, "couldn't find '%s' input device", inputName);
+    return fd;
+}
+
+int SensorBase::enable(int32_t /* handle */, int /* enabled */)
+{
+    FUNC_LOG;
+    return 0;
+}
+
+#ifdef HAL_VERSION_GT_1_0
+int SensorBase::batch(int /* handle */, int /* flags */, int64_t /* period_ns */, int64_t /* timeout */)
+{
+    FUNC_LOG;
+    return 0;
+}
+#endif
diff --git a/als/SensorBase.h b/als/SensorBase.h
new file mode 100644
index 0000000..2eaa872
--- /dev/null
+++ b/als/SensorBase.h
@@ -0,0 +1,101 @@
+/*
+* Copyright (C) 2015 Intel Corp
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef ANDROID_SENSOR_BASE_H
+#define ANDROID_SENSOR_BASE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#if defined ANDROID_L
+/* #warning "build for Wear" */
+#define LOGV_IF ALOGV_IF
+#define LOGE_IF ALOGE_IF
+#define LOGI_IF ALOGI_IF
+#define LOGI    ALOGI
+#define LOGE    ALOGE
+#define LOGV    ALOGV
+#define LOGW    ALOGW
+#else
+#warning "build for ICS or earlier version"
+#endif
+
+/* Log enablers, each of these independent */
+
+/* TODO: clear all logging below on production build, keep it during integration */
+#define PROCESS_VERBOSE (1) /* process log messages */
+#define EXTRA_VERBOSE   (1) /* verbose log messages */
+#define SYSFS_VERBOSE   (1) /* log sysfs interactions as cat/echo for repro
+                               purpose on a shell */
+#define FUNC_ENTRY      (1) /* log entry in all one-time functions */
+
+/* Note that enabling this logs may affect performance */
+#define HANDLER_ENTRY   (1) /* log entry in all handler functions */
+#define ENG_VERBOSE     (1) /* log some a lot more info about the internals */
+#define INPUT_DATA      (1) /* log the data input from the events */
+#define HANDLER_DATA    (1) /* log the data fetched from the handlers */
+
+#define FUNC_LOG \
+            LOGV("%s (hardware/intel/sensors/als)", __PRETTY_FUNCTION__)
+#define VFUNC_LOG \
+            LOGV_IF(FUNC_ENTRY, "Entering function '%s' (hardware/intel/sensors/als)", __PRETTY_FUNCTION__)
+#define VHANDLER_LOG \
+            LOGV_IF(HANDLER_ENTRY, "Entering handler '%s' (hardware/intel/sensors/als)", __PRETTY_FUNCTION__)
+#define CALL_MEMBER_FN(pobject, ptrToMember) ((pobject)->*(ptrToMember))
+
+#define MAX_SYSFS_NAME_LEN  (100)
+#define IIO_BUFFER_LENGTH   (480)
+
+/*****************************************************************************/
+
+struct sensors_event_t;
+
+class SensorBase {
+protected:
+    const char *dev_name;
+    const char *data_name;
+    int dev_fd;
+    int data_fd;
+
+    int openInput(const char* inputName);
+    static int64_t getTimestamp();
+    static int64_t timevalToNano(timeval const& t) {
+        return t.tv_sec * 1000000000LL + t.tv_usec * 1000;
+    }
+
+    int open_device();
+    int close_device();
+
+public:
+            SensorBase(const char* dev_name, const char* data_name);
+
+    virtual ~SensorBase();
+
+    virtual int readEvents(sensors_event_t* data, int count) = 0;
+    virtual bool hasPendingEvents() const;
+    virtual int getFd() const;
+    virtual int setDelay(int32_t handle, int64_t ns);
+    virtual int enable(int32_t handle, int enabled);
+#ifdef HAL_VERSION_GT_1_0
+    virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
+#endif
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_SENSOR_BASE_H
diff --git a/als/sensors.cpp b/als/sensors.cpp
new file mode 100644
index 0000000..513e5e8
--- /dev/null
+++ b/als/sensors.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2015 Intel Corp
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/sensors.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <math.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include <utils/Atomic.h>
+#include <utils/Log.h>
+
+#include "sensors.h"
+#include "AlsSensor.h"
+
+/*****************************************************************************/
+
+#define DELAY_OUT_TIME          0x7FFFFFFF
+#define LIGHT_SENSOR_POLLTIME   2000000000
+
+#define SENSORS_LIGHT_HANDLE    (ID_L)
+#define SENSORS_TILT_HANDLE     (ID_T)
+/*****************************************************************************/
+
+/* The SENSORS Module */
+static struct sensor_t sSensorList[] = {
+        { "TSL2584 Ambient light sensor",
+          "ams, ltd.",
+          1, SENSORS_LIGHT_HANDLE,
+          SENSOR_TYPE_LIGHT, 65535.0f, 1.0f, 0.015f,
+          0, 0, 0, SENSOR_STRING_TYPE_LIGHT, NULL,
+          5000000, SENSOR_FLAG_ON_CHANGE_MODE, { } },
+};
+
+static int open_sensors(const struct hw_module_t* module, const char* id,
+                        struct hw_device_t** device);
+
+
+static int sensors__get_sensors_list(struct sensors_module_t* /* module */,
+                                     struct sensor_t const** list)
+{
+    *list = sSensorList;
+    return ARRAY_SIZE(sSensorList);
+}
+
+static struct hw_module_methods_t sensors_module_methods = {
+        open: open_sensors
+};
+
+struct sensors_module_t HAL_MODULE_INFO_SYM = {
+        common: {
+                tag: HARDWARE_MODULE_TAG,
+                version_major: 1,
+                version_minor: 0,
+                id: SENSORS_HARDWARE_MODULE_ID,
+                name: "Intel MVN Sensor module",
+                author: "Intel MVN Company",
+                methods: &sensors_module_methods,
+                dso: 0,
+                reserved: {},
+        },
+        get_sensors_list: sensors__get_sensors_list,
+};
+
+struct sensors_poll_context_t {
+#ifdef HAL_VERSION_GE_1_0
+    struct sensors_poll_device_1 device; // must be first
+#else
+    struct sensors_poll_device_t device; // must be first
+#endif
+    sensors_poll_context_t();
+    ~sensors_poll_context_t();
+    int activate(int handle, int enabled);
+    int setDelay(int handle, int64_t ns);
+#ifdef HAL_VERSION_GT_1_0
+    int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
+#endif
+    int pollEvents(sensors_event_t* data, int count);
+    bool getInitialized() { return mInitialized; };
+
+private:
+    bool mInitialized;
+
+    enum {
+        light = 0,
+        numSensorDrivers,       // wake pipe goes here
+        numFds,
+    };
+
+    static const size_t wake = numFds - 1;
+    static const char WAKE_MESSAGE = 'W';
+    struct pollfd mPollFds[numFds];
+    int mWritePipeFd;
+    SensorBase* mSensors[numSensorDrivers];
+
+    int handleToDriver(int handle) const {
+        switch (handle) {
+            case ID_L:
+                return light;
+        }
+        return -EINVAL;
+    }
+};
+
+/*****************************************************************************/
+
+sensors_poll_context_t::sensors_poll_context_t()
+{
+    FUNC_LOG;
+    mInitialized = false;
+    /* Must clean this up early or else the destructor will make a mess */
+    memset(mSensors, 0, sizeof(mSensors));
+
+    mSensors[light] = new LightSensor();
+    mPollFds[light].fd = mSensors[light]->getFd();
+    mPollFds[light].events = POLLIN;
+    mPollFds[light].revents = 0;
+
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
+    fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
+    fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
+    mWritePipeFd = wakeFds[1];
+
+    mPollFds[wake].fd = wakeFds[0];
+    mPollFds[wake].events = POLLIN;
+    mPollFds[wake].revents = 0;
+    mInitialized = true;
+}
+
+sensors_poll_context_t::~sensors_poll_context_t()
+{
+    FUNC_LOG;
+    for (int i=0 ; i<numSensorDrivers ; i++) {
+        delete mSensors[i];
+    }
+    close(mPollFds[wake].fd);
+    close(mWritePipeFd);
+    mInitialized = false;
+}
+
+int sensors_poll_context_t::activate(int handle, int enabled)
+{
+    FUNC_LOG;
+    if (!mInitialized) return -EINVAL;
+    int index = handleToDriver(handle);
+    if (index < 0) return index;
+    int err =  mSensors[index]->enable(handle, enabled);
+    if (!err) {
+        const char wakeMessage(WAKE_MESSAGE);
+        int result = write(mWritePipeFd, &wakeMessage, 1);
+        ALOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));
+    }
+    return err;
+}
+
+int sensors_poll_context_t::setDelay(int handle, int64_t ns)
+{
+    FUNC_LOG;
+    int index = handleToDriver(handle);
+    if (index < 0) return index;
+    return mSensors[index]->setDelay(handle, ns);
+}
+
+#ifdef HAL_VERSION_GT_1_0
+int sensors_poll_context_t::batch(int handle, int flags, int64_t period_ns, int64_t timeout)
+{
+    FUNC_LOG;
+    int index = handleToDriver(handle);
+    if (index < 0) return index;
+    return mSensors[index]->batch(handle, flags, period_ns, timeout);
+}
+#endif
+
+int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
+{
+    FUNC_LOG;
+    int nbEvents = 0;
+    int n = 0;
+    do {
+        for (int i=0 ; count && i<numSensorDrivers; i++) {
+            SensorBase* const sensor(mSensors[i]);
+            if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
+                int nb;
+                nb = sensor->readEvents(data, count);
+                if (nb < count) {
+                    mPollFds[i].revents = 0;
+                }
+                count -= nb;
+                nbEvents += nb;
+                data += nb;
+            }
+        }
+        if (count) {
+            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
+            if (n < 0) {
+                ALOGE("poll() failed (%s)", strerror(errno));
+                return -errno;
+            }
+
+            if (mPollFds[wake].revents & POLLIN) {
+                char msg;
+                int result = read(mPollFds[wake].fd, &msg, 1);
+                ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
+                ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
+                mPollFds[wake].revents = 0;
+            }
+        }
+    } while (n && count);
+    return nbEvents;
+}
+
+/*****************************************************************************/
+
+static int poll__close(struct hw_device_t *dev)
+{
+    FUNC_LOG;
+    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+    if (ctx) {
+        delete ctx;
+    }
+    return 0;
+}
+
+static int poll__activate(struct sensors_poll_device_t *dev,
+                          int handle, int enabled)
+{
+    FUNC_LOG;
+    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+    return ctx->activate(handle, enabled);
+}
+
+static int poll__setDelay(struct sensors_poll_device_t *dev,
+                          int handle, int64_t ns)
+{
+    FUNC_LOG;
+    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+    return ctx->setDelay(handle, ns);
+}
+
+#ifdef HAL_VERSION_GT_1_0
+static int poll__batch(struct sensors_poll_device_1 *dev,
+                       int handle, int flags, int64_t period_ns, int64_t timeout)
+{
+    FUNC_LOG;
+    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+    return ctx->batch(handle, flags, period_ns, timeout);
+}
+#endif
+
+static int poll__poll(struct sensors_poll_device_t *dev,
+                      sensors_event_t* data, int count)
+{
+    FUNC_LOG;
+    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+    return ctx->pollEvents(data, count);
+}
+
+/*****************************************************************************/
+
+/** Open a new instance of a sensor device using name */
+static int open_sensors(const struct hw_module_t* module, const char* id,
+                        struct hw_device_t** device)
+{
+    FUNC_LOG;
+    int status = -EINVAL;
+    sensors_poll_context_t *dev = new sensors_poll_context_t();
+
+    if (!dev->getInitialized()) {
+        ALOGE("Failed to open the sensors (%s)", id);
+        return status;
+    }
+#ifdef HAL_VERSION_GE_1_0
+    memset(&dev->device, 0, sizeof(sensors_poll_device_1));
+#else
+    memset(&dev->device, 0, sizeof(sensors_poll_device_t));
+#endif
+
+    dev->device.common.tag = HARDWARE_DEVICE_TAG;
+#ifdef ANDROID_KK
+    dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_1;
+#elif defined(ANDROID_JBMR2)
+    dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_0;
+#else
+    dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
+#endif
+    dev->device.common.module   = const_cast<hw_module_t*>(module);
+    dev->device.common.close    = poll__close;
+    dev->device.activate        = poll__activate;
+    dev->device.setDelay        = poll__setDelay;
+#ifdef HAL_VERSION_GT_1_0
+    dev->device.batch           = poll__batch;
+#endif
+    dev->device.poll            = poll__poll;
+
+    *device = &dev->device.common;
+    status = 0;
+
+    return status;
+}
diff --git a/als/sensors.h b/als/sensors.h
new file mode 100644
index 0000000..2e8685a
--- /dev/null
+++ b/als/sensors.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Intel Corp
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INTELNDG_SENSORS_H
+#define ANDROID_INTELNDG_SENSORS_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <linux/input.h>
+#include <hardware/hardware.h>
+#include <hardware/sensors.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define ARRAY_SIZE(a)       (sizeof(a) / sizeof(a[0]))
+
+#define ID_INTELNDG_BASE    (0x1000)
+/* light sensor ID */
+#define ID_L                (ID_INTELNDG_BASE)
+/* tilt sensor ID */
+#define ID_T                (ID_L + 1)
+
+/*****************************************************************************/
+
+/*
+ * The SENSORS Module
+ */
+
+/*****************************************************************************/
+/* the GP2A is a binary proximity sensor that triggers around 5 cm on
+ * this hardware */
+#define PROXIMITY_THRESHOLD_GP2A    5.0f
+
+/* input event code for light sensor */
+#define EVENT_TYPE_LIGHT            MSC_RAW
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif  /* ANDROID_INTELNDG_SENSORS_H */