diff options
author | Paul Kocialkowski <contact@paulk.fr> | 2014-01-14 15:57:09 +0100 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-02-22 00:46:58 +0100 |
commit | ac135b66fb258b669dbcf4608a9ea7f386c00386 (patch) | |
tree | 1bcd0ba7fb97575db72404db9a3b9edc521f3aa3 /sensors | |
parent | f916f30d78514a3800a88d0f917debd77ec8a787 (diff) | |
download | device_samsung_n7100-ac135b66fb258b669dbcf4608a9ea7f386c00386.zip device_samsung_n7100-ac135b66fb258b669dbcf4608a9ea7f386c00386.tar.gz device_samsung_n7100-ac135b66fb258b669dbcf4608a9ea7f386c00386.tar.bz2 |
SMDK4x12 Sensors
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Diffstat (limited to 'sensors')
-rw-r--r-- | sensors/Android.mk | 42 | ||||
-rw-r--r-- | sensors/akm8963.c | 683 | ||||
-rw-r--r-- | sensors/bmp180.c | 238 | ||||
-rw-r--r-- | sensors/cm36651_light.c | 229 | ||||
-rw-r--r-- | sensors/cm36651_proximity.c | 228 | ||||
-rw-r--r-- | sensors/input.c | 340 | ||||
-rw-r--r-- | sensors/lsm330dlc_acceleration.c | 265 | ||||
-rw-r--r-- | sensors/lsm330dlc_gyroscope.c | 253 | ||||
-rw-r--r-- | sensors/orientation.c | 444 | ||||
-rw-r--r-- | sensors/smdk4x12_sensors.c | 292 | ||||
-rw-r--r-- | sensors/smdk4x12_sensors.h | 108 | ||||
-rw-r--r-- | sensors/ssp.c | 76 | ||||
-rw-r--r-- | sensors/ssp.h | 177 |
13 files changed, 3375 insertions, 0 deletions
diff --git a/sensors/Android.mk b/sensors/Android.mk new file mode 100644 index 0000000..ab30bf0 --- /dev/null +++ b/sensors/Android.mk @@ -0,0 +1,42 @@ +# Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + smdk4x12_sensors.c \ + input.c \ + orientation.c \ + ssp.c \ + akm8963.c \ + cm36651_proximity.c \ + cm36651_light.c \ + lsm330dlc_acceleration.c \ + lsm330dlc_gyroscope.c \ + bmp180.c + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH) + +LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libhardware +LOCAL_PRELINK_MODULE := false + +LOCAL_MODULE := sensors.smdk4x12 +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/sensors/akm8963.c b/sensors/akm8963.c new file mode 100644 index 0000000..96d35ca --- /dev/null +++ b/sensors/akm8963.c @@ -0,0 +1,683 @@ +/* + * Copyright (C) 2014 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +#define AKM8963_CONFIG_PATH "/data/misc/akmd_set.txt" + +struct akm8963_data { + struct smdk4x12_sensors_handlers *orientation_sensor; + + sensors_vec_t magnetic; + unsigned short magnetic_data[4][3]; + int magnetic_data_count; + int magnetic_data_index; + + unsigned short magnetic_extrema[2][3]; + unsigned char asa[3]; + int ho[3]; + + long int delay; + int device_fd; + int uinput_fd; + + pthread_t thread; + pthread_mutex_t mutex; + int thread_continue; +}; + +// This AKM8963 implementation is based on intuitive understanding of how the +// AKM8963 data is translated to SI units. +// +// The raw data is a two-byte short value that is the 16 bit ADC read value. +// This value has to be corrected using the ASA Sensivity Adujstment value +// as such: v_adj = v * (((ASA - 128) * 0.5) / 128 + 1) +// LSB values can then be converted to uT units, with 0.15uT/LSB: +// m = 0.15 * v * (((ASA - 128) * 0.5) / 128 + 1) +// +// Moreover, we calculate and apply a software offset (HO) in order to have the +// maximum final values for each axis at ~45uT and minimum at ~-45uT. +// In order to store HO as an integer, the applied offset is 0.06 * HO: +// m = 0.15 * v * (((ASA - 128) * 0.5) / 128 + 1) - 0.06 * HO + + +int akm8963_magnetic_extrema(struct akm8963_data *data, int index) +{ + if (data == NULL || index < 0 || index >= 3) + return -EINVAL; + + // Calculate the extrema from HO (software offset) + data->magnetic_extrema[0][index] = (unsigned short) ((-45.0f + 0.06 * data->ho[index]) / (0.15f * (((data->asa[index] - 128) * 0.5f) / 128 + 1))); + data->magnetic_extrema[1][index] = (unsigned short) ((45.0f + 0.06 * data->ho[index]) / (0.15f * (((data->asa[index] - 128) * 0.5f) / 128 + 1))); + + return 0; +} + +int akm8963_config_read(struct akm8963_data *data) +{ + char buffer[256] = { 0 }; + int config_fd = -1; + int offset = 0; + int length; + int count; + int value; + char *p; + int rc; + + if (data == NULL) + return -EINVAL; + + config_fd = open(AKM8963_CONFIG_PATH, O_RDONLY); + if (config_fd < 0) { + ALOGE("%s: Unable to open akm8963 config %d %s", __func__, errno, strerror(errno)); + goto error; + } + + rc = 0; + + do { + lseek(config_fd, offset, SEEK_SET); + + length = read(config_fd, buffer, sizeof(buffer)); + if (length <= 0) + break; + + p = strchr((const char *) &buffer, '\n'); + if (p != NULL) { + offset += (int) p - (int) buffer + 1; + *p = '\0'; + } else if ((size_t) length < sizeof(buffer)) { + buffer[length] = '\0'; + } + + count = sscanf((char const *) &buffer, "HSUC_HO_FORM0.x = %d", &value); + if (count == 1) { + data->ho[0] = value; + rc |= akm8963_magnetic_extrema(data, 0); + } + + count = sscanf((char const *) &buffer, "HSUC_HO_FORM0.y = %d", &value); + if (count == 1) { + data->ho[1] = value; + rc |= akm8963_magnetic_extrema(data, 1); + } + + count = sscanf((char const *) &buffer, "HSUC_HO_FORM0.z = %d", &value); + if (count == 1) { + data->ho[2] = value; + rc |= akm8963_magnetic_extrema(data, 2); + } + } while (p != NULL && length > 0); + + goto complete; + +error: + rc = -1; + +complete: + if (config_fd >= 0) + close(config_fd); + + return rc; +} + +int akm8963_config_write(struct akm8963_data *data) +{ + char buffer[256] = { 0 }; + int config_fd = -1; + int length; + int value; + int rc; + + if (data == NULL) + return -EINVAL; + + config_fd = open(AKM8963_CONFIG_PATH, O_WRONLY | O_TRUNC | O_CREAT, 0664); + if (config_fd < 0) { + ALOGE("%s: Unable to open akm8963 config", __func__); + goto error; + } + + value = (int) data->ho[0]; + length = snprintf((char *) &buffer, sizeof(buffer), "HSUC_HO_FORM0.x = %d\n", value); + + rc = write(config_fd, buffer, length); + if (rc < length) { + ALOGE("%s: Unable to write akm8963 config", __func__); + goto error; + } + + value = (int) data->ho[1]; + length = snprintf((char *) &buffer, sizeof(buffer), "HSUC_HO_FORM0.y = %d\n", value); + + rc = write(config_fd, buffer, length); + if (rc < length) { + ALOGE("%s: Unable to write akm8963 config", __func__); + goto error; + } + + value = (int) data->ho[2]; + length = snprintf((char *) &buffer, sizeof(buffer), "HSUC_HO_FORM0.z = %d\n", value); + + rc = write(config_fd, buffer, length); + if (rc < length) { + ALOGE("%s: Unable to write akm8963 config", __func__); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (config_fd >= 0) + close(config_fd); + + return rc; +} + +int akm8963_ho_calibration(struct akm8963_data *data, + unsigned short *magnetic_data, size_t magnetic_data_size) +{ + float ho[2]; + int gain_index; + int i; + + if (data == NULL || magnetic_data == NULL || magnetic_data_size < 3) + return -EINVAL; + + // Update the extrema from the current raw magnetic data + for (i = 0; i < 3; i++) { + if (magnetic_data[i] < data->magnetic_extrema[0][i] || data->magnetic_extrema[0][i] == 0) + data->magnetic_extrema[0][i] = magnetic_data[i]; + if (magnetic_data[i] > data->magnetic_extrema[1][i] || data->magnetic_extrema[1][i] == 0) + data->magnetic_extrema[1][i] = magnetic_data[i]; + } + + // Calculate HO (software offset) + if (data->magnetic_data_count % 10 == 0) { + for (i = 0; i < 3; i++) { + // Calculate offset for minimum to be at -45uT + ho[0] = (0.15f * (((data->asa[i] - 128) * 0.5f) / 128 + 1) * data->magnetic_extrema[0][i] + 45.0f) / 0.06f; + // Calculate offset for maximum to be at +45uT + ho[1] = (0.15f * (((data->asa[i] - 128) * 0.5f) / 128 + 1) * data->magnetic_extrema[1][i] - 45.0f) / 0.06f; + // Average offset to make everyone (mostly) happy + data->ho[i] = (int) (ho[0] + ho[1]) / 2.0f; + } + } + + return 0; +} + +int akm8963_magnetic_axis(struct akm8963_data *data, int index, float *axis) +{ + float value; + int count; + int i; + + if (data == NULL || axis == NULL || index < 0 || index >= 3) + return -EINVAL; + + count = data->magnetic_data_count >= 4 ? 4 : data->magnetic_data_count; + value = 0; + + // Average the last 4 (or less) raw magnetic values + for (i = 0; i < count; i++) + value += (float) data->magnetic_data[i][index]; + value /= count; + + // Adjust sensitivity using ASA value + value *= (((data->asa[index] - 128) * 0.5f) / 128 + 1); + + // Magnetic field value in uT from corrected value and HO offset + *axis = 0.15f * value - 0.06f * data->ho[index]; + + return 0; +} + +int akm8963_magnetic(struct akm8963_data *data) +{ + int rc; + + if (data == NULL) + return -EINVAL; + + rc = 0; + rc |= akm8963_magnetic_axis(data, 0, &data->magnetic.x); + rc |= akm8963_magnetic_axis(data, 1, &data->magnetic.y); + rc |= akm8963_magnetic_axis(data, 2, &data->magnetic.z); + + return rc; +} + +void *akm8963_thread(void *thread_data) +{ + struct smdk4x12_sensors_handlers *handlers = NULL; + struct akm8963_data *data = NULL; + struct input_event event; + struct timeval time; + unsigned char i2c_data[8] = { 0 }; + unsigned short magnetic_data[3] = { 0 }; + int index; + long int before, after; + int diff; + int device_fd; + int uinput_fd; + int rc; + + if (thread_data == NULL) + return NULL; + + handlers = (struct smdk4x12_sensors_handlers *) thread_data; + if (handlers->data == NULL) + return NULL; + + data = (struct akm8963_data *) handlers->data; + + device_fd = data->device_fd; + if (device_fd < 0) + return NULL; + + uinput_fd = data->uinput_fd; + if (uinput_fd < 0) + return NULL; + + while (data->thread_continue) { + pthread_mutex_lock(&data->mutex); + if (!data->thread_continue) + break; + + while (handlers->activated) { + gettimeofday(&time, NULL); + before = timestamp(&time); + + memset(&i2c_data, 0, sizeof(i2c_data)); + rc = ioctl(device_fd, ECS_IOCTL_GET_MAGDATA, &i2c_data); + if (rc < 0) { + ALOGE("%s: Unable to get akm8963 data", __func__); + goto next; + } + + if (!(i2c_data[0] & 0x01)) { + ALOGE("%s: akm8963 data is not ready", __func__); + goto next; + } + + magnetic_data[0] = (unsigned short) ((i2c_data[2] << 8) | (i2c_data[1] & 0xff)); + magnetic_data[1] = (unsigned short) ((i2c_data[4] << 8) | (i2c_data[3] & 0xff)); + magnetic_data[2] = (unsigned short) ((i2c_data[6] << 8) | (i2c_data[5] & 0xff)); + + index = data->magnetic_data_index; + + data->magnetic_data[index][0] = magnetic_data[0]; + data->magnetic_data[index][1] = magnetic_data[1]; + data->magnetic_data[index][2] = magnetic_data[2]; + + data->magnetic_data_index = (index + 1) % 4; + data->magnetic_data_count++; + + rc = akm8963_ho_calibration(data, (unsigned short *) &magnetic_data, sizeof(magnetic_data)); + if (rc < 0) { + ALOGE("%s: Unable to calibrate akm8963 HO", __func__); + goto next; + } + + rc = akm8963_magnetic(data); + if (rc < 0) { + ALOGE("%s: Unable to get akm8963 magnetic", __func__); + goto next; + } + + input_event_set(&event, EV_REL, REL_X, (int) (data->magnetic.x * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_REL, REL_Y, (int) (data->magnetic.y * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_REL, REL_Z, (int) (data->magnetic.z * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_SYN, 0, 0); + write(uinput_fd, &event, sizeof(event)); + +next: + gettimeofday(&time, NULL); + after = timestamp(&time); + + diff = (int) (data->delay - (after - before)) / 1000; + if (diff <= 0) + continue; + + usleep(diff); + } + } + return NULL; +} + +int akm8963_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct akm8963_data *data = NULL; + pthread_attr_t thread_attr; + int device_fd = -1; + int uinput_fd = -1; + int input_fd = -1; + int rc; + int i; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL || device == NULL) + return -EINVAL; + + data = (struct akm8963_data *) calloc(1, sizeof(struct akm8963_data)); + + for (i = 0; i < device->handlers_count; i++) { + if (device->handlers[i] == NULL) + continue; + + if (device->handlers[i]->handle == SENSOR_TYPE_ORIENTATION) + data->orientation_sensor = device->handlers[i]; + } + + device_fd = open("/dev/akm8963", O_RDONLY); + if (device_fd < 0) { + ALOGE("%s: Unable to open device", __func__); + goto error; + } + + rc = ioctl(device_fd, ECS_IOCTL_GET_FUSEROMDATA, &data->asa); + if (rc < 0) { + ALOGE("%s: Unable to get akm8963 FUSE ROM data", __func__); + goto error; + } + + ALOGD("AKM8963 ASA (Sensitivity Adjustment) values are: (%d, %d, %d)", + data->asa[0], data->asa[1], data->asa[2]); + + uinput_fd = uinput_rel_create("magnetic"); + if (uinput_fd < 0) { + ALOGD("%s: Unable to create uinput", __func__); + goto error; + } + + input_fd = input_open("magnetic"); + if (input_fd < 0) { + ALOGE("%s: Unable to open magnetic input", __func__); + goto error; + } + + data->thread_continue = 1; + + pthread_mutex_init(&data->mutex, NULL); + pthread_mutex_lock(&data->mutex); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + + rc = pthread_create(&data->thread, &thread_attr, akm8963_thread, (void *) handlers); + if (rc < 0) { + ALOGE("%s: Unable to create akm8963 thread", __func__); + pthread_mutex_destroy(&data->mutex); + goto error; + } + + data->device_fd = device_fd; + data->uinput_fd = uinput_fd; + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (uinput_fd >= 0) + close(uinput_fd); + + if (input_fd >= 0) + close(input_fd); + + if (device_fd >= 0) + close(device_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int akm8963_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + struct akm8963_data *data = NULL; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct akm8963_data *) handlers->data; + + handlers->activated = 0; + data->thread_continue = 0; + pthread_mutex_unlock(&data->mutex); + + pthread_mutex_destroy(&data->mutex); + + if (data->uinput_fd >= 0) { + uinput_destroy(data->uinput_fd); + close(data->uinput_fd); + } + data->uinput_fd = -1; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (data->device_fd >= 0) + close(data->device_fd); + data->device_fd = -1; + + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int akm8963_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct akm8963_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct akm8963_data *) handlers->data; + + rc = akm8963_config_read(data); + if (rc < 0) { + ALOGE("%s: Unable to read akm8963 config", __func__); + } + + rc = ssp_sensor_enable(GEOMAGNETIC_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + pthread_mutex_unlock(&data->mutex); + + return 0; +} + +int akm8963_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct akm8963_data *data; + int empty; + int rc; + int i; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct akm8963_data *) handlers->data; + + empty = 1; + + for (i = 0; i < (ssize_t) (sizeof(data->magnetic_extrema) / (sizeof(short) * 2)); i++) { + if (data->magnetic_extrema[0][i] != 0 || data->magnetic_extrema[1][i] != 0) { + empty = 0; + break; + } + } + + if (!empty) { + rc = akm8963_config_write(data); + if (rc < 0) + ALOGE("%s: Unable to write akm8963 config", __func__); + } + + rc = ssp_sensor_disable(GEOMAGNETIC_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 0; + + return 0; +} + +int akm8963_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct akm8963_data *data; + char path_delay[PATH_MAX] = "/sys/class/sensors/ssp_sensor/mag_poll_delay"; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct akm8963_data *) handlers->data; + + rc = sysfs_value_write(path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + data->delay = delay; + + return 0; +} + +float akm8963_convert(int value) +{ + return (float) value / 1000.0f; +} + +int akm8963_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct akm8963_data *data; + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || handlers->data == NULL || event == NULL) + return -EINVAL; + + data = (struct akm8963_data *) handlers->data; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -1; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + event->magnetic.status = SENSOR_STATUS_ACCURACY_MEDIUM; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + switch (input_event.code) { + case REL_X: + event->magnetic.x = akm8963_convert(input_event.value); + break; + case REL_Y: + event->magnetic.y = akm8963_convert(input_event.value); + break; + case REL_Z: + event->magnetic.z = akm8963_convert(input_event.value); + break; + default: + continue; + } + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + if (data->orientation_sensor != NULL) + orientation_fill(data->orientation_sensor, NULL, &event->magnetic); + + return 0; +} + +struct smdk4x12_sensors_handlers akm8963 = { + .name = "AKM8963", + .handle = SENSOR_TYPE_MAGNETIC_FIELD, + .init = akm8963_init, + .deinit = akm8963_deinit, + .activate = akm8963_activate, + .deactivate = akm8963_deactivate, + .set_delay = akm8963_set_delay, + .get_data = akm8963_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/bmp180.c b/sensors/bmp180.c new file mode 100644 index 0000000..c50474c --- /dev/null +++ b/sensors/bmp180.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <math.h> +#include <sys/types.h> +#include <linux/ioctl.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +struct bmp180_data { + char path_delay[PATH_MAX]; +}; + +int bmp180_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct bmp180_data *data = NULL; + char path[PATH_MAX] = { 0 }; + int input_fd = -1; + int rc; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL) + return -EINVAL; + + data = (struct bmp180_data *) calloc(1, sizeof(struct bmp180_data)); + + input_fd = input_open("pressure_sensor"); + if (input_fd < 0) { + ALOGE("%s: Unable to open input", __func__); + goto error; + } + + rc = sysfs_path_prefix("pressure_sensor", (char *) &path); + if (rc < 0 || path[0] == '\0') { + ALOGE("%s: Unable to open sysfs", __func__); + goto error; + } + + snprintf(data->path_delay, PATH_MAX, "%s/pressure_poll_delay", path); + + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int bmp180_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL) + return -EINVAL; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (handlers->data != NULL) + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int bmp180_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct bmp180_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct bmp180_data *) handlers->data; + + rc = ssp_sensor_enable(PRESSURE_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int bmp180_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct bmp180_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct bmp180_data *) handlers->data; + + rc = ssp_sensor_disable(PRESSURE_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int bmp180_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct bmp180_data *data; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct bmp180_data *) handlers->data; + + rc = sysfs_value_write(data->path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + return 0; +} + +float bmp180_convert(int value) +{ + return value / 100.0f; +} + +int bmp180_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || event == NULL) + return -EINVAL; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -EINVAL; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + switch (input_event.code) { + case REL_HWHEEL: + event->pressure = bmp180_convert(input_event.value); + break; + default: + continue; + } + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT && event->pressure != 0) { + event->timestamp = input_timestamp(&input_event); + break; + } else { + return -1; + } + } + } while (1); + + return 0; +} + +struct smdk4x12_sensors_handlers bmp180 = { + .name = "BMP180", + .handle = SENSOR_TYPE_PRESSURE, + .init = bmp180_init, + .deinit = bmp180_deinit, + .activate = bmp180_activate, + .deactivate = bmp180_deactivate, + .set_delay = bmp180_set_delay, + .get_data = bmp180_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/cm36651_light.c b/sensors/cm36651_light.c new file mode 100644 index 0000000..421a276 --- /dev/null +++ b/sensors/cm36651_light.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <math.h> +#include <sys/types.h> +#include <linux/ioctl.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +struct cm36651_light_data { + char path_delay[PATH_MAX]; +}; + +int cm36651_light_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct cm36651_light_data *data = NULL; + char path[PATH_MAX] = { 0 }; + int input_fd = -1; + int rc; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL) + return -EINVAL; + + data = (struct cm36651_light_data *) calloc(1, sizeof(struct cm36651_light_data)); + + input_fd = input_open("light_sensor"); + if (input_fd < 0) { + ALOGE("%s: Unable to open input", __func__); + goto error; + } + + rc = sysfs_path_prefix("light_sensor", (char *) &path); + if (rc < 0 || path[0] == '\0') { + ALOGE("%s: Unable to open sysfs", __func__); + goto error; + } + + snprintf(data->path_delay, PATH_MAX, "%s/light_poll_delay", path); + + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int cm36651_light_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL) + return -EINVAL; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (handlers->data != NULL) + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int cm36651_light_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct cm36651_light_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_light_data *) handlers->data; + + rc = ssp_sensor_enable(LIGHT_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int cm36651_light_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct cm36651_light_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_light_data *) handlers->data; + + rc = ssp_sensor_disable(LIGHT_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int cm36651_light_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct cm36651_light_data *data; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_light_data *) handlers->data; + + rc = sysfs_value_write(data->path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + return 0; +} + +float cm36651_light_convert(int value) +{ + return (float) value * 1.7f - 0.5f; +} + +int cm36651_light_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || event == NULL) + return -EINVAL; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -EINVAL; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + if (input_event.code == REL_MISC) + event->light = cm36651_light_convert(input_event.value); + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + return 0; +} + +struct smdk4x12_sensors_handlers cm36651_light = { + .name = "CM36651 Light", + .handle = SENSOR_TYPE_LIGHT, + .init = cm36651_light_init, + .deinit = cm36651_light_deinit, + .activate = cm36651_light_activate, + .deactivate = cm36651_light_deactivate, + .set_delay = cm36651_light_set_delay, + .get_data = cm36651_light_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/cm36651_proximity.c b/sensors/cm36651_proximity.c new file mode 100644 index 0000000..108f00b --- /dev/null +++ b/sensors/cm36651_proximity.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <linux/ioctl.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +struct cm36651_proximity_data { + char path_delay[PATH_MAX]; +}; + +int cm36651_proximity_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct cm36651_proximity_data *data = NULL; + char path[PATH_MAX] = { 0 }; + int input_fd = -1; + int rc; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL) + return -EINVAL; + + data = (struct cm36651_proximity_data *) calloc(1, sizeof(struct cm36651_proximity_data)); + + input_fd = input_open("proximity_sensor"); + if (input_fd < 0) { + ALOGE("%s: Unable to open input", __func__); + goto error; + } + + rc = sysfs_path_prefix("proximity_sensor", (char *) &path); + if (rc < 0 || path[0] == '\0') { + ALOGE("%s: Unable to open sysfs", __func__); + goto error; + } + + snprintf(data->path_delay, PATH_MAX, "%s/prox_poll_delay", path); + + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int cm36651_proximity_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL) + return -EINVAL; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (handlers->data != NULL) + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int cm36651_proximity_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct cm36651_proximity_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_proximity_data *) handlers->data; + + rc = ssp_sensor_enable(PROXIMITY_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int cm36651_proximity_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct cm36651_proximity_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_proximity_data *) handlers->data; + + rc = ssp_sensor_disable(PROXIMITY_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int cm36651_proximity_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct cm36651_proximity_data *data; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct cm36651_proximity_data *) handlers->data; + + rc = sysfs_value_write(data->path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + return 0; +} + +float cm36651_proximity_convert(int value) +{ + return (float) value * 6.0f; +} + +int cm36651_proximity_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || event == NULL) + return -EINVAL; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -EINVAL; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_ABS) { + if (input_event.code == ABS_DISTANCE) + event->distance = cm36651_proximity_convert(input_event.value); + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + return 0; +} + +struct smdk4x12_sensors_handlers cm36651_proximity = { + .name = "CM36651 Proximity", + .handle = SENSOR_TYPE_PROXIMITY, + .init = cm36651_proximity_init, + .deinit = cm36651_proximity_deinit, + .activate = cm36651_proximity_activate, + .deactivate = cm36651_proximity_deactivate, + .set_delay = cm36651_proximity_set_delay, + .get_data = cm36651_proximity_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/input.c b/sensors/input.c new file mode 100644 index 0000000..5199b28 --- /dev/null +++ b/sensors/input.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> +#include <linux/ioctl.h> +#include <linux/input.h> +#include <linux/uinput.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" + +void input_event_set(struct input_event *event, int type, int code, int value) +{ + if (event == NULL) + return; + + memset(event, 0, sizeof(struct input_event)); + + event->type = type, + event->code = code; + event->value = value; + + gettimeofday(&event->time, NULL); +} + +long int timestamp(struct timeval *time) +{ + if (time == NULL) + return -1; + + return time->tv_sec * 1000000000LL + time->tv_usec * 1000; +} + +long int input_timestamp(struct input_event *event) +{ + if (event == NULL) + return -1; + + return timestamp(&event->time); +} + +int uinput_rel_create(const char *name) +{ + struct uinput_user_dev uinput_dev; + int uinput_fd; + int rc; + + if (name == NULL) + return -1; + + uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + if (uinput_fd < 0) { + ALOGE("%s: Unable to open uinput device", __func__); + goto error; + } + + memset(&uinput_dev, 0, sizeof(uinput_dev)); + + strncpy(uinput_dev.name, name, sizeof(uinput_dev.name)); + uinput_dev.id.bustype = BUS_I2C; + uinput_dev.id.vendor = 0; + uinput_dev.id.product = 0; + uinput_dev.id.version = 0; + + rc = 0; + rc |= ioctl(uinput_fd, UI_SET_EVBIT, EV_REL); + rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_X); + rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_Y); + rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_Z); + rc |= ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN); + + if (rc < 0) { + ALOGE("%s: Unable to set uinput bits", __func__); + goto error; + } + + rc = write(uinput_fd, &uinput_dev, sizeof(uinput_dev)); + if (rc < 0) { + ALOGE("%s: Unable to write uinput device", __func__); + goto error; + } + + rc = ioctl(uinput_fd, UI_DEV_CREATE); + if (rc < 0) { + ALOGE("%s: Unable to create uinput device", __func__); + goto error; + } + + usleep(3000); + + return uinput_fd; + +error: + if (uinput_fd >= 0) + close(uinput_fd); + + return -1; +} + +void uinput_destroy(int uinput_fd) +{ + if (uinput_fd < 0) + return; + + ioctl(uinput_fd, UI_DEV_DESTROY); +} + +int input_open(char *name) +{ + DIR *d; + struct dirent *di; + + char input_name[80] = { 0 }; + char path[PATH_MAX]; + char *c; + int fd; + int rc; + + if (name == NULL) + return -EINVAL; + + d = opendir("/dev/input"); + if (d == NULL) + return -1; + + while ((di = readdir(d))) { + if (di == NULL || strcmp(di->d_name, ".") == 0 || strcmp(di->d_name, "..") == 0) + continue; + + snprintf(path, PATH_MAX, "/dev/input/%s", di->d_name); + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + continue; + + rc = ioctl(fd, EVIOCGNAME(sizeof(input_name) - 1), &input_name); + if (rc < 0) + continue; + + c = strstr((char *) &input_name, "\n"); + if (c != NULL) + *c = '\0'; + + if (strcmp(input_name, name) == 0) + return fd; + else + close(fd); + } + + return -1; +} + +int sysfs_path_prefix(char *name, char *path_prefix) +{ + DIR *d; + struct dirent *di; + + char input_name[80] = { 0 }; + char path[PATH_MAX]; + char *c; + int fd; + + if (name == NULL || path_prefix == NULL) + return -EINVAL; + + d = opendir("/sys/class/input"); + if (d == NULL) + return -1; + + while ((di = readdir(d))) { + if (di == NULL || strcmp(di->d_name, ".") == 0 || strcmp(di->d_name, "..") == 0) + continue; + + snprintf(path, PATH_MAX, "/sys/class/input/%s/name", di->d_name); + + fd = open(path, O_RDONLY); + if (fd < 0) + continue; + + read(fd, &input_name, sizeof(input_name)); + close(fd); + + c = strstr((char *) &input_name, "\n"); + if (c != NULL) + *c = '\0'; + + if (strcmp(input_name, name) == 0) { + snprintf(path_prefix, PATH_MAX, "/sys/class/input/%s", di->d_name); + return 0; + } + } + + return -1; +} + +int sysfs_value_read(char *path) +{ + char buffer[100]; + int value; + int fd = -1; + int rc; + int i; + + if (path == NULL) + return -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + goto error; + + rc = read(fd, &buffer, sizeof(buffer)); + if (rc <= 0) + goto error; + + i = 0; + while (buffer[i] == ' ' || buffer[i] == '\t') + i++; + + value = atoi(&buffer[i]); + goto complete; + +error: + value = -1; + +complete: + if (fd >= 0) + close(fd); + + return value; +} + +int sysfs_value_write(char *path, int value) +{ + char buffer[100]; + int fd = -1; + int rc; + + if (path == NULL) + return -1; + + fd = open(path, O_WRONLY); + if (fd < 0) + goto error; + + snprintf((char *) &buffer, sizeof(buffer), "%d\n", value); + + rc = write(fd, buffer, strlen(buffer)); + if (rc < (int) strlen(buffer)) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (fd >= 0) + close(fd); + + return rc; +} + +int sysfs_string_read(char *path, char *buffer, size_t length) +{ + int fd = -1; + int rc; + + if (path == NULL || buffer == NULL || length == 0) + return -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + goto error; + + rc = read(fd, buffer, length); + if (rc <= 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (fd >= 0) + close(fd); + + return rc; +} + +int sysfs_string_write(char *path, char *buffer, size_t length) +{ + int fd = -1; + int rc; + + if (path == NULL || buffer == NULL || length == 0) + return -1; + + fd = open(path, O_WRONLY); + if (fd < 0) + goto error; + + rc = write(fd, buffer, length); + if (rc <= 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (fd >= 0) + close(fd); + + return rc; +} diff --git a/sensors/lsm330dlc_acceleration.c b/sensors/lsm330dlc_acceleration.c new file mode 100644 index 0000000..efb0388 --- /dev/null +++ b/sensors/lsm330dlc_acceleration.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +struct lsm330dlc_acceleration_data { + struct smdk4x12_sensors_handlers *orientation_sensor; + + char path_delay[PATH_MAX]; + + sensors_vec_t acceleration; +}; + +int lsm330dlc_acceleration_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct lsm330dlc_acceleration_data *data = NULL; + char path[PATH_MAX] = { 0 }; + int input_fd = -1; + int rc; + int i; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL) + return -EINVAL; + + data = (struct lsm330dlc_acceleration_data *) calloc(1, sizeof(struct lsm330dlc_acceleration_data)); + + for (i = 0; i < device->handlers_count; i++) { + if (device->handlers[i] == NULL) + continue; + + if (device->handlers[i]->handle == SENSOR_TYPE_ORIENTATION) + data->orientation_sensor = device->handlers[i]; + } + + input_fd = input_open("accelerometer_sensor"); + if (input_fd < 0) { + ALOGE("%s: Unable to open input", __func__); + goto error; + } + + rc = sysfs_path_prefix("accelerometer_sensor", (char *) &path); + if (rc < 0 || path[0] == '\0') { + ALOGE("%s: Unable to open sysfs", __func__); + goto error; + } + + snprintf(data->path_delay, PATH_MAX, "%s/acc_poll_delay", path); + + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int lsm330dlc_acceleration_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL) + return -EINVAL; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (handlers->data != NULL) + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int lsm330dlc_acceleration_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct lsm330dlc_acceleration_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_acceleration_data *) handlers->data; + + rc = ssp_sensor_enable(ACCELEROMETER_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int lsm330dlc_acceleration_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct lsm330dlc_acceleration_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_acceleration_data *) handlers->data; + + rc = ssp_sensor_disable(ACCELEROMETER_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 0; + + return 0; +} + +int lsm330dlc_acceleration_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct lsm330dlc_acceleration_data *data; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_acceleration_data *) handlers->data; + + rc = sysfs_value_write(data->path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + return 0; +} + +float lsm330dlc_acceleration_convert(int value) +{ + return (float) value * (GRAVITY_EARTH / 1024.0f); +} + +int lsm330dlc_acceleration_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct lsm330dlc_acceleration_data *data; + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || handlers->data == NULL || event == NULL) + return -EINVAL; + + data = (struct lsm330dlc_acceleration_data *) handlers->data; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -1; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + event->acceleration.x = data->acceleration.x; + event->acceleration.y = data->acceleration.y; + event->acceleration.z = data->acceleration.z; + + event->magnetic.status = SENSOR_STATUS_ACCURACY_MEDIUM; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + switch (input_event.code) { + case REL_X: + event->acceleration.x = lsm330dlc_acceleration_convert(input_event.value); + break; + case REL_Y: + event->acceleration.y = lsm330dlc_acceleration_convert(input_event.value); + break; + case REL_Z: + event->acceleration.z = lsm330dlc_acceleration_convert(input_event.value); + break; + default: + continue; + } + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + data->acceleration.x = event->acceleration.x; + data->acceleration.y = event->acceleration.y; + data->acceleration.z = event->acceleration.z; + + if (data->orientation_sensor != NULL) + orientation_fill(data->orientation_sensor, &event->acceleration, NULL); + + return 0; +} + +struct smdk4x12_sensors_handlers lsm330dlc_acceleration = { + .name = "LSM330DLC Acceleration", + .handle = SENSOR_TYPE_ACCELEROMETER, + .init = lsm330dlc_acceleration_init, + .deinit = lsm330dlc_acceleration_deinit, + .activate = lsm330dlc_acceleration_activate, + .deactivate = lsm330dlc_acceleration_deactivate, + .set_delay = lsm330dlc_acceleration_set_delay, + .get_data = lsm330dlc_acceleration_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/lsm330dlc_gyroscope.c b/sensors/lsm330dlc_gyroscope.c new file mode 100644 index 0000000..da2d81d --- /dev/null +++ b/sensors/lsm330dlc_gyroscope.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <math.h> +#include <sys/types.h> +#include <linux/ioctl.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +struct lsm330dlc_gyroscope_data { + char path_delay[PATH_MAX]; + + sensors_vec_t gyro; +}; + +int lsm330dlc_gyroscope_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct lsm330dlc_gyroscope_data *data = NULL; + char path[PATH_MAX] = { 0 }; + int input_fd = -1; + int rc; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL) + return -EINVAL; + + data = (struct lsm330dlc_gyroscope_data *) calloc(1, sizeof(struct lsm330dlc_gyroscope_data)); + + input_fd = input_open("gyro_sensor"); + if (input_fd < 0) { + ALOGE("%s: Unable to open input", __func__); + goto error; + } + + rc = sysfs_path_prefix("gyro_sensor", (char *) &path); + if (rc < 0 || path[0] == '\0') { + ALOGE("%s: Unable to open sysfs", __func__); + goto error; + } + + snprintf(data->path_delay, PATH_MAX, "%s/gyro_poll_delay", path); + + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int lsm330dlc_gyroscope_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL) + return -EINVAL; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + if (handlers->data != NULL) + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int lsm330dlc_gyroscope_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct lsm330dlc_gyroscope_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_gyroscope_data *) handlers->data; + + rc = ssp_sensor_enable(GYROSCOPE_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to enable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int lsm330dlc_gyroscope_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct lsm330dlc_gyroscope_data *data; + int rc; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_gyroscope_data *) handlers->data; + + rc = ssp_sensor_disable(GYROSCOPE_SENSOR); + if (rc < 0) { + ALOGE("%s: Unable to disable ssp sensor", __func__); + return -1; + } + + handlers->activated = 1; + + return 0; +} + +int lsm330dlc_gyroscope_set_delay(struct smdk4x12_sensors_handlers *handlers, long int delay) +{ + struct lsm330dlc_gyroscope_data *data; + int rc; + + ALOGD("%s(%p, %ld)", __func__, handlers, delay); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct lsm330dlc_gyroscope_data *) handlers->data; + + rc = sysfs_value_write(data->path_delay, (int) delay); + if (rc < 0) { + ALOGE("%s: Unable to write sysfs value", __func__); + return -1; + } + + return 0; +} + +float lsm330dlc_gyroscope_convert(int value) +{ + return value * (70.0f / 4000.0f) * (3.1415926535f / 180.0f); +} + +int lsm330dlc_gyroscope_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct lsm330dlc_gyroscope_data *data; + struct input_event input_event; + int input_fd; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || handlers->data == NULL || event == NULL) + return -EINVAL; + + data = (struct lsm330dlc_gyroscope_data *) handlers->data; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -EINVAL; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + event->gyro.x = data->gyro.x; + event->gyro.y = data->gyro.y; + event->gyro.z = data->gyro.z; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + switch (input_event.code) { + case REL_RX: + event->gyro.x = lsm330dlc_gyroscope_convert(input_event.value); + break; + case REL_RY: + event->gyro.y = lsm330dlc_gyroscope_convert(input_event.value); + break; + case REL_RZ: + event->gyro.z = lsm330dlc_gyroscope_convert(input_event.value); + break; + default: + continue; + } + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + data->gyro.x = event->gyro.x; + data->gyro.y = event->gyro.y; + data->gyro.z = event->gyro.z; + + return 0; +} + +struct smdk4x12_sensors_handlers lsm330dlc_gyroscope = { + .name = "LSM330DLC Gyroscope", + .handle = SENSOR_TYPE_GYROSCOPE, + .init = lsm330dlc_gyroscope_init, + .deinit = lsm330dlc_gyroscope_deinit, + .activate = lsm330dlc_gyroscope_activate, + .deactivate = lsm330dlc_gyroscope_deactivate, + .set_delay = lsm330dlc_gyroscope_set_delay, + .get_data = lsm330dlc_gyroscope_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/orientation.c b/sensors/orientation.c new file mode 100644 index 0000000..e3529bd --- /dev/null +++ b/sensors/orientation.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <fcntl.h> +#include <errno.h> +#include <math.h> +#include <linux/ioctl.h> +#include <linux/uinput.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" + +struct orientation_data { + struct smdk4x12_sensors_handlers *acceleration_sensor; + struct smdk4x12_sensors_handlers *magnetic_sensor; + + sensors_vec_t orientation; + sensors_vec_t acceleration; + sensors_vec_t magnetic; + + long int delay; + int uinput_fd; + + pthread_t thread; + pthread_mutex_t mutex; + int thread_continue; +}; + +static float rad2deg(float v) +{ + return (v * 180.0f / 3.1415926535f); +} + +static float vector_scalar(sensors_vec_t *v, sensors_vec_t *d) +{ + return v->x * d->x + v->y * d->y + v->z * d->z; +} + +static float vector_length(sensors_vec_t *v) +{ + return sqrtf(vector_scalar(v, v)); +} + +void orientation_calculate(sensors_vec_t *a, sensors_vec_t *m, sensors_vec_t *o) +{ + float azimuth, pitch, roll; + float la, sinp, cosp, sinr, cosr, x, y; + + if (a == NULL || m == NULL || o == NULL) + return; + + la = vector_length(a); + pitch = asinf(-(a->y) / la); + roll = asinf((a->x) / la); + + sinp = sinf(pitch); + cosp = cosf(pitch); + sinr = sinf(roll); + cosr = cosf(roll); + + y = -(m->x) * cosr + m->z * sinr; + x = m->x * sinp * sinr + m->y * cosp + m->z * sinp * cosr; + azimuth = atan2f(y, x); + + o->azimuth = rad2deg(azimuth); + o->pitch = rad2deg(pitch); + o->roll = rad2deg(roll); + + if (o->azimuth < 0) + o->azimuth += 360.0f; +} + +void *orientation_thread(void *thread_data) +{ + struct smdk4x12_sensors_handlers *handlers = NULL; + struct orientation_data *data = NULL; + struct input_event event; + struct timeval time; + long int before, after; + int diff; + int uinput_fd; + + if (thread_data == NULL) + return NULL; + + handlers = (struct smdk4x12_sensors_handlers *) thread_data; + if (handlers->data == NULL) + return NULL; + + data = (struct orientation_data *) handlers->data; + + uinput_fd = data->uinput_fd; + if (uinput_fd < 0) + return NULL; + + while (data->thread_continue) { + pthread_mutex_lock(&data->mutex); + if (!data->thread_continue) + break; + + while (handlers->activated) { + gettimeofday(&time, NULL); + before = timestamp(&time); + + orientation_calculate(&data->acceleration, &data->magnetic, &data->orientation); + + input_event_set(&event, EV_REL, REL_X, (int) (data->orientation.azimuth * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_REL, REL_Y, (int) (data->orientation.pitch * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_REL, REL_Z, (int) (data->orientation.roll * 1000)); + write(uinput_fd, &event, sizeof(event)); + input_event_set(&event, EV_SYN, 0, 0); + write(uinput_fd, &event, sizeof(event)); + + gettimeofday(&time, NULL); + after = timestamp(&time); + + diff = (int) (data->delay - (after - before)) / 1000; + if (diff <= 0) + continue; + + usleep(diff); + } + } + + return NULL; +} + +int orientation_fill(struct smdk4x12_sensors_handlers *handlers, + sensors_vec_t *acceleration, sensors_vec_t *magnetic) +{ + struct orientation_data *data; + +// ALOGD("%s(%p, %p, %p)", __func__, handlers, acceleration, magnetic); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct orientation_data *) handlers->data; + + if (acceleration != NULL) { + data->acceleration.x = acceleration->x; + data->acceleration.y = acceleration->y; + data->acceleration.z = acceleration->z; + } + + if (magnetic != NULL) { + data->magnetic.x = magnetic->x; + data->magnetic.y = magnetic->y; + data->magnetic.z = magnetic->z; + } + + return 0; +} + +int orientation_init(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device) +{ + struct orientation_data *data = NULL; + pthread_attr_t thread_attr; + int uinput_fd = -1; + int input_fd = -1; + int rc; + int i; + + ALOGD("%s(%p, %p)", __func__, handlers, device); + + if (handlers == NULL || device == NULL) + return -EINVAL; + + data = (struct orientation_data *) calloc(1, sizeof(struct orientation_data)); + + for (i = 0; i < device->handlers_count; i++) { + if (device->handlers[i] == NULL) + continue; + + if (device->handlers[i]->handle == SENSOR_TYPE_ACCELEROMETER) + data->acceleration_sensor = device->handlers[i]; + else if (device->handlers[i]->handle == SENSOR_TYPE_MAGNETIC_FIELD) + data->magnetic_sensor = device->handlers[i]; + } + + if (data->acceleration_sensor == NULL || data->magnetic_sensor == NULL) { + ALOGE("%s: Missing sensors for orientation", __func__); + goto error; + } + + uinput_fd = uinput_rel_create("orientation"); + if (uinput_fd < 0) { + ALOGD("%s: Unable to create uinput", __func__); + goto error; + } + + input_fd = input_open("orientation"); + if (input_fd < 0) { + ALOGE("%s: Unable to open orientation input", __func__); + goto error; + } + + data->thread_continue = 1; + + pthread_mutex_init(&data->mutex, NULL); + pthread_mutex_lock(&data->mutex); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + + rc = pthread_create(&data->thread, &thread_attr, orientation_thread, (void *) handlers); + if (rc < 0) { + ALOGE("%s: Unable to create orientation thread", __func__); + pthread_mutex_destroy(&data->mutex); + goto error; + } + + data->uinput_fd = uinput_fd; + handlers->poll_fd = input_fd; + handlers->data = (void *) data; + + return 0; + +error: + if (data != NULL) + free(data); + + if (uinput_fd >= 0) + close(uinput_fd); + + if (input_fd >= 0) + close(input_fd); + + handlers->poll_fd = -1; + handlers->data = NULL; + + return -1; +} + +int orientation_deinit(struct smdk4x12_sensors_handlers *handlers) +{ + struct orientation_data *data; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct orientation_data *) handlers->data; + + handlers->activated = 0; + data->thread_continue = 0; + pthread_mutex_unlock(&data->mutex); + + pthread_mutex_destroy(&data->mutex); + + if (data->uinput_fd >= 0) { + uinput_destroy(data->uinput_fd); + close(data->uinput_fd); + } + data->uinput_fd = -1; + + if (handlers->poll_fd >= 0) + close(handlers->poll_fd); + handlers->poll_fd = -1; + + free(handlers->data); + handlers->data = NULL; + + return 0; +} + +int orientation_activate(struct smdk4x12_sensors_handlers *handlers) +{ + struct orientation_data *data; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct orientation_data *) handlers->data; + + if (data->acceleration_sensor == NULL || data->magnetic_sensor == NULL) + return -1; + + data->acceleration_sensor->needed |= SMDK4x12_SENSORS_NEEDED_ORIENTATION; + if (data->acceleration_sensor->needed == SMDK4x12_SENSORS_NEEDED_ORIENTATION) + data->acceleration_sensor->activate(data->acceleration_sensor); + + data->magnetic_sensor->needed |= SMDK4x12_SENSORS_NEEDED_ORIENTATION; + if (data->magnetic_sensor->needed == SMDK4x12_SENSORS_NEEDED_ORIENTATION) + data->magnetic_sensor->activate(data->magnetic_sensor); + + handlers->activated = 1; + pthread_mutex_unlock(&data->mutex); + + return 0; +} + +int orientation_deactivate(struct smdk4x12_sensors_handlers *handlers) +{ + struct orientation_data *data; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct orientation_data *) handlers->data; + + if (data->acceleration_sensor == NULL || data->magnetic_sensor == NULL) + return -1; + + data->acceleration_sensor->needed &= ~(SMDK4x12_SENSORS_NEEDED_ORIENTATION); + if (data->acceleration_sensor->needed == 0) + data->acceleration_sensor->deactivate(data->acceleration_sensor); + + data->magnetic_sensor->needed &= ~(SMDK4x12_SENSORS_NEEDED_ORIENTATION); + if (data->magnetic_sensor->needed == 0) + data->magnetic_sensor->deactivate(data->magnetic_sensor); + + handlers->activated = 0; + + return 0; +} + +int orientation_set_delay(struct smdk4x12_sensors_handlers *handlers, + long int delay) +{ + struct orientation_data *data; + + ALOGD("%s(%p)", __func__, handlers); + + if (handlers == NULL || handlers->data == NULL) + return -EINVAL; + + data = (struct orientation_data *) handlers->data; + + if (data->acceleration_sensor == NULL || data->magnetic_sensor == NULL) + return -1; + + if (data->acceleration_sensor->needed == SMDK4x12_SENSORS_NEEDED_ORIENTATION) + data->acceleration_sensor->set_delay(data->acceleration_sensor, delay); + + if (data->magnetic_sensor->needed == SMDK4x12_SENSORS_NEEDED_ORIENTATION) + data->magnetic_sensor->set_delay(data->magnetic_sensor, delay); + + data->delay = delay; + + return 0; +} + +float orientation_convert(int value) +{ + return (float) value / 1000.0f; +} + +int orientation_get_data(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event) +{ + struct input_event input_event; + int input_fd = -1; + int rc; + +// ALOGD("%s(%p, %p)", __func__, handlers, event); + + if (handlers == NULL || event == NULL) + return -EINVAL; + + input_fd = handlers->poll_fd; + if (input_fd < 0) + return -EINVAL; + + memset(event, 0, sizeof(struct sensors_event_t)); + event->version = sizeof(struct sensors_event_t); + event->sensor = handlers->handle; + event->type = handlers->handle; + + event->orientation.status = SENSOR_STATUS_ACCURACY_MEDIUM; + + do { + rc = read(input_fd, &input_event, sizeof(input_event)); + if (rc < (int) sizeof(input_event)) + break; + + if (input_event.type == EV_REL) { + switch (input_event.code) { + case REL_X: + event->orientation.azimuth = orientation_convert(input_event.value); + break; + case REL_Y: + event->orientation.pitch = orientation_convert(input_event.value); + break; + case REL_Z: + event->orientation.roll = orientation_convert(input_event.value); + break; + default: + continue; + } + } else if (input_event.type == EV_SYN) { + if (input_event.code == SYN_REPORT) + event->timestamp = input_timestamp(&input_event); + } + } while (input_event.type != EV_SYN); + + return 0; +} + +struct smdk4x12_sensors_handlers orientation = { + .name = "Orientation", + .handle = SENSOR_TYPE_ORIENTATION, + .init = orientation_init, + .deinit = orientation_deinit, + .activate = orientation_activate, + .deactivate = orientation_deactivate, + .set_delay = orientation_set_delay, + .get_data = orientation_get_data, + .activated = 0, + .needed = 0, + .poll_fd = -1, + .data = NULL, +}; diff --git a/sensors/smdk4x12_sensors.c b/sensors/smdk4x12_sensors.c new file mode 100644 index 0000000..29de591 --- /dev/null +++ b/sensors/smdk4x12_sensors.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <fcntl.h> +#include <errno.h> +#include <poll.h> +#include <sys/select.h> +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" + +/* + * Sensors list + */ + +struct sensor_t smdk4x12_sensors[] = { + { "LSM330DLC Acceleration Sensor", "STMicroelectronics", 1, SENSOR_TYPE_ACCELEROMETER, + SENSOR_TYPE_ACCELEROMETER, 2 * GRAVITY_EARTH, 0.0096f, 0.25f, 10000, {}, }, + { "AKM8963 Magnetic Sensor", "Asahi Kasei Microdevices", 1, SENSOR_TYPE_MAGNETIC_FIELD, + SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, 0.06f, 6.0f, 10000, {}, }, + { "Orientation Sensor", "SMDK4x12 Sensors", 1, SENSOR_TYPE_ORIENTATION, + SENSOR_TYPE_ORIENTATION, 360.0f, 0.1f, 0.0f, 10000, {}, }, + { "CM36651 Light Sensor", "Capella Microsystems", 1, SENSOR_TYPE_LIGHT, + SENSOR_TYPE_LIGHT, 3000.0f, 1.0f, 0.2f, 0, {}, }, + { "CM36651 Proximity Sensor", "Capella Microsystems", 1, SENSOR_TYPE_PROXIMITY, + SENSOR_TYPE_PROXIMITY, 6.0f, 6.0f, 1.3f, 0, {}, }, + { "LSM330DLC Gyroscope Sensor", "STMicroelectronics", 1, SENSOR_TYPE_GYROSCOPE, + SENSOR_TYPE_GYROSCOPE, 500.0f * (3.1415926535f / 180.0f), (70.0f / 4000.0f) * (3.1415926535f / 180.0f), 6.1f, 5000, {}, }, + { "BMP180 Pressure Sensor", "Bosch", 1, SENSOR_TYPE_PRESSURE, + SENSOR_TYPE_PRESSURE, 1000.0f, 1.0f, 1.0f, 66700, {}, }, +}; + +int smdk4x12_sensors_count = sizeof(smdk4x12_sensors) / sizeof(struct sensor_t); + +struct smdk4x12_sensors_handlers *smdk4x12_sensors_handlers[] = { + &lsm330dlc_acceleration, + &akm8963, + &orientation, + &cm36651_proximity, + &cm36651_light, + &lsm330dlc_gyroscope, + &bmp180, +}; + +int smdk4x12_sensors_handlers_count = sizeof(smdk4x12_sensors_handlers) / + sizeof(struct smdk4x12_sensors_handlers *); + +/* + * SMDK4x12 Sensors + */ + +int smdk4x12_sensors_activate(struct sensors_poll_device_t *dev, int handle, + int enabled) +{ + struct smdk4x12_sensors_device *device; + int i; + + ALOGD("%s(%p, %d, %d)", __func__, dev, handle, enabled); + + if (dev == NULL) + return -EINVAL; + + device = (struct smdk4x12_sensors_device *) dev; + + if (device->handlers == NULL || device->handlers_count <= 0) + return -EINVAL; + + for (i = 0; i < device->handlers_count; i++) { + if (device->handlers[i] == NULL) + continue; + + if (device->handlers[i]->handle == handle) { + if (enabled && device->handlers[i]->activate != NULL) { + device->handlers[i]->needed |= SMDK4x12_SENSORS_NEEDED_API; + if (device->handlers[i]->needed == SMDK4x12_SENSORS_NEEDED_API) + return device->handlers[i]->activate(device->handlers[i]); + else + return 0; + } else if (!enabled && device->handlers[i]->deactivate != NULL) { + device->handlers[i]->needed &= ~SMDK4x12_SENSORS_NEEDED_API; + if (device->handlers[i]->needed == 0) + return device->handlers[i]->deactivate(device->handlers[i]); + else + return 0; + } + } + } + + return -1; +} + +int smdk4x12_sensors_set_delay(struct sensors_poll_device_t *dev, int handle, + int64_t ns) +{ + struct smdk4x12_sensors_device *device; + int i; + + ALOGD("%s(%p, %d, %ld)", __func__, dev, handle, (long int) ns); + + if (dev == NULL) + return -EINVAL; + + device = (struct smdk4x12_sensors_device *) dev; + + if (device->handlers == NULL || device->handlers_count <= 0) + return -EINVAL; + + for (i = 0; i < device->handlers_count; i++) { + if (device->handlers[i] == NULL) + continue; + + if (device->handlers[i]->handle == handle && device->handlers[i]->set_delay != NULL) + return device->handlers[i]->set_delay(device->handlers[i], (long int) ns); + } + + return 0; +} + +int smdk4x12_sensors_poll(struct sensors_poll_device_t *dev, + struct sensors_event_t* data, int count) +{ + struct smdk4x12_sensors_device *device; + int i, j; + int c, n; + int poll_rc, rc; + +// ALOGD("%s(%p, %p, %d)", __func__, dev, data, count); + + if (dev == NULL) + return -EINVAL; + + device = (struct smdk4x12_sensors_device *) dev; + + if (device->handlers == NULL || device->handlers_count <= 0 || + device->poll_fds == NULL || device->poll_fds_count <= 0) + return -EINVAL; + + n = 0; + + do { + poll_rc = poll(device->poll_fds, device->poll_fds_count, n > 0 ? 0 : -1); + if (poll_rc < 0) + return -1; + + for (i = 0; i < device->poll_fds_count; i++) { + if (!(device->poll_fds[i].revents & POLLIN)) + continue; + + for (j = 0; j < device->handlers_count; j++) { + if (device->handlers[j] == NULL || device->handlers[j]->poll_fd != device->poll_fds[i].fd || device->handlers[j]->get_data == NULL) + continue; + + rc = device->handlers[j]->get_data(device->handlers[j], &data[n]); + if (rc < 0) { + device->poll_fds[i].revents = 0; + poll_rc = -1; + } else { + n++; + count--; + } + } + } + } while ((poll_rc > 0 || n < 1) && count > 0); + + return n; +} + +/* + * Interface + */ + +int smdk4x12_sensors_close(hw_device_t *device) +{ + struct smdk4x12_sensors_device *smdk4x12_sensors_device; + int i; + + ALOGD("%s(%p)", __func__, device); + + if (device == NULL) + return -EINVAL; + + smdk4x12_sensors_device = (struct smdk4x12_sensors_device *) device; + + if (smdk4x12_sensors_device->poll_fds != NULL) + free(smdk4x12_sensors_device->poll_fds); + + for (i = 0; i < smdk4x12_sensors_device->handlers_count; i++) { + if (smdk4x12_sensors_device->handlers[i] == NULL || smdk4x12_sensors_device->handlers[i]->deinit == NULL) + continue; + + smdk4x12_sensors_device->handlers[i]->deinit(smdk4x12_sensors_device->handlers[i]); + } + + free(device); + + return 0; +} + +int smdk4x12_sensors_open(const struct hw_module_t* module, const char *id, + struct hw_device_t** device) +{ + struct smdk4x12_sensors_device *smdk4x12_sensors_device; + int p, i; + + ALOGD("%s(%p, %s, %p)", __func__, module, id, device); + + if (module == NULL || device == NULL) + return -EINVAL; + + smdk4x12_sensors_device = (struct smdk4x12_sensors_device *) + calloc(1, sizeof(struct smdk4x12_sensors_device)); + smdk4x12_sensors_device->device.common.tag = HARDWARE_DEVICE_TAG; + smdk4x12_sensors_device->device.common.version = 0; + smdk4x12_sensors_device->device.common.module = (struct hw_module_t *) module; + smdk4x12_sensors_device->device.common.close = smdk4x12_sensors_close; + smdk4x12_sensors_device->device.activate = smdk4x12_sensors_activate; + smdk4x12_sensors_device->device.setDelay = smdk4x12_sensors_set_delay; + smdk4x12_sensors_device->device.poll = smdk4x12_sensors_poll; + smdk4x12_sensors_device->handlers = smdk4x12_sensors_handlers; + smdk4x12_sensors_device->handlers_count = smdk4x12_sensors_handlers_count; + smdk4x12_sensors_device->poll_fds = (struct pollfd *) + calloc(1, smdk4x12_sensors_handlers_count * sizeof(struct pollfd)); + + p = 0; + for (i = 0; i < smdk4x12_sensors_handlers_count; i++) { + if (smdk4x12_sensors_handlers[i] == NULL || smdk4x12_sensors_handlers[i]->init == NULL) + continue; + + smdk4x12_sensors_handlers[i]->init(smdk4x12_sensors_handlers[i], smdk4x12_sensors_device); + if (smdk4x12_sensors_handlers[i]->poll_fd >= 0) { + smdk4x12_sensors_device->poll_fds[p].fd = smdk4x12_sensors_handlers[i]->poll_fd; + smdk4x12_sensors_device->poll_fds[p].events = POLLIN; + p++; + } + } + + smdk4x12_sensors_device->poll_fds_count = p; + + *device = &(smdk4x12_sensors_device->device.common); + + return 0; +} + +int smdk4x12_sensors_get_sensors_list(struct sensors_module_t* module, + const struct sensor_t **sensors_p) +{ + ALOGD("%s(%p, %p)", __func__, module, sensors_p); + + if (sensors_p == NULL) + return -EINVAL; + + *sensors_p = smdk4x12_sensors; + return smdk4x12_sensors_count; +} + +struct hw_module_methods_t smdk4x12_sensors_module_methods = { + .open = smdk4x12_sensors_open, +}; + +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 = "SMDK4x12 Sensors", + .author = "Paul Kocialkowski", + .methods = &smdk4x12_sensors_module_methods, + }, + .get_sensors_list = smdk4x12_sensors_get_sensors_list, +}; diff --git a/sensors/smdk4x12_sensors.h b/sensors/smdk4x12_sensors.h new file mode 100644 index 0000000..5dc54d8 --- /dev/null +++ b/sensors/smdk4x12_sensors.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <poll.h> +#include <linux/input.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#ifndef _SMDK4x12_SENSORS_H_ +#define _SMDK4x12_SENSORS_H_ + +#define SMDK4x12_SENSORS_NEEDED_API (1 << 0) +#define SMDK4x12_SENSORS_NEEDED_ORIENTATION (1 << 1) + +struct smdk4x12_sensors_device; + +struct smdk4x12_sensors_handlers { + char *name; + int handle; + + int (*init)(struct smdk4x12_sensors_handlers *handlers, + struct smdk4x12_sensors_device *device); + int (*deinit)(struct smdk4x12_sensors_handlers *handlers); + int (*activate)(struct smdk4x12_sensors_handlers *handlers); + int (*deactivate)(struct smdk4x12_sensors_handlers *handlers); + int (*set_delay)(struct smdk4x12_sensors_handlers *handlers, + long int delay); + int (*get_data)(struct smdk4x12_sensors_handlers *handlers, + struct sensors_event_t *event); + + int activated; + int needed; + int poll_fd; + + void *data; +}; + +struct smdk4x12_sensors_device { + struct sensors_poll_device_t device; + + struct smdk4x12_sensors_handlers **handlers; + int handlers_count; + + struct pollfd *poll_fds; + int poll_fds_count; +}; + +extern struct smdk4x12_sensors_handlers *smdk4x12_sensors_handlers[]; +extern int smdk4x12_sensors_handlers_count; + +int smdk4x12_sensors_activate(struct sensors_poll_device_t *dev, int handle, + int enabled); +int smdk4x12_sensors_set_delay(struct sensors_poll_device_t *dev, int handle, + int64_t ns); +int smdk4x12_sensors_poll(struct sensors_poll_device_t *dev, + struct sensors_event_t* data, int count); + +/* + * Input + */ + +void input_event_set(struct input_event *event, int type, int code, int value); +long int timestamp(struct timeval *time); +long int input_timestamp(struct input_event *event); +int uinput_rel_create(const char *name); +void uinput_destroy(int uinput_fd); +int input_open(char *name); +int sysfs_path_prefix(char *name, char *path_prefix); +int sysfs_value_read(char *path); +int sysfs_value_write(char *path, int value); +int sysfs_string_read(char *path, char *buffer, size_t length); +int sysfs_string_write(char *path, char *buffer, size_t length); + +/* + * Sensors + */ + +int orientation_fill(struct smdk4x12_sensors_handlers *handlers, + sensors_vec_t *acceleration, sensors_vec_t *magnetic); + +int ssp_sensor_enable(int sensor_type); +int ssp_sensor_disable(int sensor_type); + +extern struct smdk4x12_sensors_handlers lsm330dlc_acceleration; +extern struct smdk4x12_sensors_handlers akm8963; +extern struct smdk4x12_sensors_handlers orientation; +extern struct smdk4x12_sensors_handlers cm36651_proximity; +extern struct smdk4x12_sensors_handlers cm36651_light; +extern struct smdk4x12_sensors_handlers lsm330dlc_gyroscope; +extern struct smdk4x12_sensors_handlers bmp180; + +#endif diff --git a/sensors/ssp.c b/sensors/ssp.c new file mode 100644 index 0000000..d1d4ae1 --- /dev/null +++ b/sensors/ssp.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 Paul Kocialkowski <contact@paulk.fr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <errno.h> + +#include <hardware/sensors.h> +#include <hardware/hardware.h> + +#define LOG_TAG "smdk4x12_sensors" +#include <utils/Log.h> + +#include "smdk4x12_sensors.h" +#include "ssp.h" + +int ssp_sensor_enable(int sensor_type) +{ + char path_enable[PATH_MAX] = "/sys/class/sensors/ssp_sensor/enable"; + int value; + int rc; + + ALOGD("%s(%d)", __func__, sensor_type); + + if (sensor_type < 0 || sensor_type >= SENSOR_FACTORY_MAX) + return -EINVAL; + + value = sysfs_value_read(path_enable); + if (value < 0) + value = 0; + + value |= (1 << sensor_type); + + rc = sysfs_value_write(path_enable, value); + if (rc < 0) + return -1; + + return 0; +} + +int ssp_sensor_disable(int sensor_type) +{ + char path_enable[PATH_MAX] = "/sys/class/sensors/ssp_sensor/enable"; + int value; + int rc; + + ALOGD("%s(%d)", __func__, sensor_type); + + if (sensor_type < 0 || sensor_type >= SENSOR_FACTORY_MAX) + return -EINVAL; + + value = sysfs_value_read(path_enable); + if (value < 0) + value = 0; + + value &= ~(1 << sensor_type); + + rc = sysfs_value_write(path_enable, value); + if (rc < 0) + return -1; + + return 0; +} diff --git a/sensors/ssp.h b/sensors/ssp.h new file mode 100644 index 0000000..48c9ad9 --- /dev/null +++ b/sensors/ssp.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SSP_PRJ_H__ +#define __SSP_PRJ_H__ + +#include <stdint.h> + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define SSP_SW_RESET_TIME 3000 +#define DEFUALT_POLLING_DELAY (200 * NSEC_PER_MSEC) +#define PROX_AVG_READ_NUM 80 +#define DEFAULT_RETRIES 3 + +/* Sensor Sampling Time Define */ +enum { + SENSOR_NS_DELAY_FASTEST = 10000000, /* 10msec */ + SENSOR_NS_DELAY_GAME = 20000000, /* 20msec */ + SENSOR_NS_DELAY_UI = 66700000, /* 66.7msec */ + SENSOR_NS_DELAY_NORMAL = 200000000, /* 200msec */ +}; + +enum { + SENSOR_MS_DELAY_FASTEST = 10, /* 10msec */ + SENSOR_MS_DELAY_GAME = 20, /* 20msec */ + SENSOR_MS_DELAY_UI = 66, /* 66.7msec */ + SENSOR_MS_DELAY_NORMAL = 200, /* 200msec */ +}; + +enum { + SENSOR_CMD_DELAY_FASTEST = 0, /* 10msec */ + SENSOR_CMD_DELAY_GAME, /* 20msec */ + SENSOR_CMD_DELAY_UI, /* 66.7msec */ + SENSOR_CMD_DELAY_NORMAL, /* 200msec */ +}; + +/* + * SENSOR_DELAY_SET_STATE + * Check delay set to avoid sending ADD instruction twice + */ +enum { + INITIALIZATION_STATE = 0, + NO_SENSOR_STATE, + ADD_SENSOR_STATE, + RUNNING_SENSOR_STATE, +}; + +/* Gyroscope DPS */ +#define GYROSCOPE_DPS250 250 +#define GYROSCOPE_DPS500 500 +#define GYROSCOPE_DPS2000 2000 + +/* kernel -> ssp manager cmd*/ +#define SSP_LIBRARY_SLEEP_CMD (1 << 5) +#define SSP_LIBRARY_LARGE_DATA_CMD (1 << 6) +#define SSP_LIBRARY_WAKEUP_CMD (1 << 7) + +/* ioctl command */ +#define AKMIO 0xA1 +#define ECS_IOCTL_GET_FUSEROMDATA _IOR(AKMIO, 0x01, unsigned char[3]) +#define ECS_IOCTL_GET_MAGDATA _IOR(AKMIO, 0x02, unsigned char[8]) +#define ECS_IOCTL_GET_ACCDATA _IOR(AKMIO, 0x03, int[3]) + +/* AP -> SSP Instruction */ +#define MSG2SSP_INST_BYPASS_SENSOR_ADD 0xA1 +#define MSG2SSP_INST_BYPASS_SENSOR_REMOVE 0xA2 +#define MSG2SSP_INST_REMOVE_ALL 0xA3 +#define MSG2SSP_INST_CHANGE_DELAY 0xA4 +#define MSG2SSP_INST_SENSOR_SELFTEST 0xA8 +#define MSG2SSP_INST_LIBRARY_ADD 0xB1 +#define MSG2SSP_INST_LIBRARY_REMOVE 0xB2 + +#define MSG2SSP_AP_STT 0xC8 +#define MSG2SSP_AP_STATUS_WAKEUP 0xD1 +#define MSG2SSP_AP_STATUS_SLEEP 0xD2 +#define MSG2SSP_AP_STATUS_RESET 0xD3 +#define MSG2SSP_AP_WHOAMI 0x0F +#define MSG2SSP_AP_FIRMWARE_REV 0xF0 +#define MSG2SSP_AP_SENSOR_FORMATION 0xF1 +#define MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xF2 +#define MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xF3 +#define MSG2SSP_AP_SENSOR_SCANNING 0xF4 + +#define MSG2SSP_AP_FUSEROM 0X01 + +/* AP -> SSP Data Protocol Frame Field */ +#define MSG2SSP_SSP_SLEEP 0xC1 +#define MSG2SSP_STS 0xC2 /* Start to Send */ +#define MSG2SSP_RTS 0xC4 /* Ready to Send */ +#define MSG2SSP_STT 0xC8 +#define MSG2SSP_SRM 0xCA /* Start to Read MSG */ +#define MSG2SSP_SSM 0xCB /* Start to Send MSG */ +#define MSG2SSP_SSD 0xCE /* Start to Send Data Type & Length */ + +/* SSP -> AP ACK about write CMD */ +#define MSG_ACK 0x80 /* ACK from SSP to AP */ +#define MSG_NAK 0x70 /* NAK from SSP to AP */ + + +/* SSP_INSTRUCTION_CMD */ +enum { + REMOVE_SENSOR = 0, + ADD_SENSOR, + CHANGE_DELAY, + GO_SLEEP, + FACTORY_MODE, + REMOVE_LIBRARY, + ADD_LIBRARY, +}; + +/* SENSOR_TYPE */ +enum { + ACCELEROMETER_SENSOR = 0, + GYROSCOPE_SENSOR, + GEOMAGNETIC_SENSOR, + PRESSURE_SENSOR, + GESTURE_SENSOR, + PROXIMITY_SENSOR, + LIGHT_SENSOR, + PROXIMITY_RAW, + ORIENTATION_SENSOR, + SENSOR_MAX, +}; + +/* SENSOR_FACTORY_MODE_TYPE */ +enum { + ACCELEROMETER_FACTORY = 0, + GYROSCOPE_FACTORY, + GEOMAGNETIC_FACTORY, + PRESSURE_FACTORY, + MCU_FACTORY, + GYROSCOPE_TEMP_FACTORY, + GYROSCOPE_DPS_FACTORY, + MCU_SLEEP_FACTORY, + SENSOR_FACTORY_MAX, +}; + +struct sensor_value { + union { + struct { + __s16 x; + __s16 y; + __s16 z; + }; + struct { + __u16 r; + __u16 g; + __u16 b; + __u16 w; + }; + __u8 prox[4]; + __s16 data[4]; + __s32 pressure[3]; + }; +}; + +struct calibraion_data { + int x; + int y; + int z; +}; + +#endif |