From: Jinhyung Choi Date: Wed, 15 Oct 2014 09:57:10 +0000 (+0900) Subject: sensor: added pressure, ultraviolet, and hrm sensor X-Git-Tag: submit/tizen_common/20141029.133645~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_linux_3.12;p=sdk%2Femulator%2Femulator-kernel.git sensor: added pressure, ultraviolet, and hrm sensor - modified and converted the value (sync with sensor fw) Change-Id: I087418ae5c756042489d558d32b92baef6492e6a Signed-off-by: Jinhyung Choi --- diff --git a/drivers/maru/sensors/Makefile b/drivers/maru/sensors/Makefile index 92d79d5addce..5a9914616e08 100644 --- a/drivers/maru/sensors/Makefile +++ b/drivers/maru/sensors/Makefile @@ -5,4 +5,7 @@ obj-$(CONFIG_MARU_VIRTIO_SENSOR) += maru_virtio_sensor.o \ maru_light.o \ maru_proxi.o \ maru_rotation_vector.o \ - maru_haptic.o + maru_haptic.o \ + maru_pressure.o \ + maru_uv.o \ + maru_hrm.o diff --git a/drivers/maru/sensors/maru_accel.c b/drivers/maru/sensors/maru_accel.c index 679ffa36f88b..3bba6bb05a88 100644 --- a/drivers/maru/sensors/maru_accel.c +++ b/drivers/maru/sensors/maru_accel.c @@ -29,6 +29,7 @@ #include #include +#include #include "maru_virtio_sensor.h" @@ -49,12 +50,23 @@ static struct device *accel_sensor_device; static struct device *l_accel_sensor_device; #endif +#define GRAVITY_CHANGE_UNIT 15322 +static short sensor_convert_data(int number) +{ + int temp; + temp = number / 64; + temp = temp * (SHRT_MAX / 2); + temp = temp / GRAVITY_CHANGE_UNIT; + return (short)temp; +} + static void maru_accel_input_work_func(struct work_struct *work) { int poll_time = 200000000; int enable = 0; int ret = 0; int accel_x, accel_y, accel_z; + short raw_x, raw_y, raw_z; char sensor_data[__MAX_BUF_SENSOR]; struct maru_accel_data *data = container_of((struct delayed_work *)work, struct maru_accel_data, work); @@ -74,11 +86,27 @@ static void maru_accel_input_work_func(struct work_struct *work) { mutex_unlock(&data->data_mutex); if (!ret) { sscanf(sensor_data, "%d,%d,%d", &accel_x, &accel_y, &accel_z); - LOG(1, "accel_set %d, %d, %d", accel_x, accel_y, accel_z); - - input_report_rel(data->input_data, REL_RX, accel_x); - input_report_rel(data->input_data, REL_RY, accel_y); - input_report_rel(data->input_data, REL_RZ, accel_z); + LOG(1, "accel_set act %d, %d, %d", accel_x, accel_y, accel_z); + raw_x = sensor_convert_data(accel_x); + raw_y = sensor_convert_data(accel_y); + raw_z = sensor_convert_data(accel_z); + LOG(1, "accel_set raw %d, %d, %d", raw_x, raw_y, raw_z); + + if (raw_x == 0) { + raw_x = 1; + } + + if (raw_y == 0) { + raw_y = 1; + } + + if (raw_z == 0) { + raw_z = 1; + } + + input_report_rel(data->input_data, REL_X, raw_x); + input_report_rel(data->input_data, REL_Y, raw_y); + input_report_rel(data->input_data, REL_Z, raw_z); input_sync(data->input_data); } } @@ -236,10 +264,9 @@ static int set_initial_value(struct maru_accel_data *data) { int delay = 0; int ret = 0; - int enable = 0; char sensor_data [__MAX_BUF_SENSOR]; - memset(sensor_data, 0, __MAX_BUF_SENSOR); + memset(sensor_data, 0, sizeof(sensor_data)); ret = get_sensor_data(sensor_type_accel_delay, sensor_data); if (ret) { @@ -248,15 +275,6 @@ static int set_initial_value(struct maru_accel_data *data) } delay = sensor_atoi(sensor_data); - - ret = get_sensor_data(sensor_type_accel_enable, sensor_data); - if (ret) { - ERR("failed to get initial enable"); - return ret; - } - - enable = sensor_atoi(sensor_data); - if (delay < 0) { ERR("weird value is set initial delay"); return ret; @@ -264,10 +282,11 @@ static int set_initial_value(struct maru_accel_data *data) atomic_set(&data->poll_delay, delay); - if (enable) { - atomic_set(&data->enable, 1); - schedule_delayed_work(&data->work, 0); - } + memset(sensor_data, 0, sizeof(sensor_data)); + sensor_data[0] = '0'; + + set_sensor_data(sensor_type_accel_enable, sensor_data); + atomic_set(&data->enable, 0); return ret; } @@ -289,9 +308,9 @@ static int create_input_device(struct maru_accel_data *data) set_bit(EV_REL, input_data->evbit); set_bit(EV_SYN, input_data->evbit); - input_set_capability(input_data, EV_REL, REL_RX); - input_set_capability(input_data, EV_REL, REL_RY); - input_set_capability(input_data, EV_REL, REL_RZ); + input_set_capability(input_data, EV_REL, REL_X); + input_set_capability(input_data, EV_REL, REL_Y); + input_set_capability(input_data, EV_REL, REL_Z); data->input_data = input_data; diff --git a/drivers/maru/sensors/maru_geo.c b/drivers/maru/sensors/maru_geo.c index b5422e8909a8..3d5ac703e217 100644 --- a/drivers/maru/sensors/maru_geo.c +++ b/drivers/maru/sensors/maru_geo.c @@ -49,12 +49,18 @@ static struct device *geo_sensor_device; static struct device *l_geo_sensor_device; #endif +static short sensor_convert_data(int number) +{ + return (short) ((number * 5) / 3); // divided by 0.6 +} + static void maru_geo_input_work_func(struct work_struct *work) { int poll_time = 200000000; int enable = 0; int ret = 0; - int geo_x, geo_y, geo_z, hdst; + int geo_x, geo_y, geo_z, hdst = 4; + short raw_x, raw_y, raw_z; char sensor_data[__MAX_BUF_SENSOR]; struct maru_geo_data *data = container_of((struct delayed_work *)work, struct maru_geo_data, work); @@ -70,15 +76,31 @@ static void maru_geo_input_work_func(struct work_struct *work) { if (enable) { mutex_lock(&data->data_mutex); - ret = get_sensor_data(sensor_type_tilt, sensor_data); + ret = get_sensor_data(sensor_type_mag, sensor_data); mutex_unlock(&data->data_mutex); if (!ret) { - sscanf(sensor_data, "%d %d %d %d", &geo_x, &geo_y, &geo_z, &hdst); - LOG(1, "geo_set %d, %d, %d, %d", geo_x, geo_y, geo_z, hdst); - - input_report_rel(data->input_data, REL_RX, geo_x); - input_report_rel(data->input_data, REL_RY, geo_y); - input_report_rel(data->input_data, REL_RZ, geo_z); + sscanf(sensor_data, "%d %d %d", &geo_x, &geo_y, &geo_z); + LOG(1, "geo_set act %d, %d, %d", geo_x, geo_y, geo_z); + raw_x = sensor_convert_data(geo_x); + raw_y = sensor_convert_data(geo_y); + raw_z = sensor_convert_data(geo_z); + LOG(1, "geo_set raw %d, %d, %d, %d", raw_x, raw_y, raw_z, hdst); + + if (raw_x == 0) { + raw_x = 1; + } + + if (raw_y == 0) { + raw_y = 1; + } + + if (raw_z == 0) { + raw_z = 1; + } + + input_report_rel(data->input_data, REL_RX, raw_x); + input_report_rel(data->input_data, REL_RY, raw_y); + input_report_rel(data->input_data, REL_RZ, raw_z); input_report_rel(data->input_data, REL_HWHEEL, hdst); input_sync(data->input_data); } @@ -250,7 +272,6 @@ static int set_initial_value(struct maru_geo_data *data) { int delay = 0; int ret = 0; - int enable = 0; char sensor_data [__MAX_BUF_SENSOR]; memset(sensor_data, 0, __MAX_BUF_SENSOR); @@ -262,15 +283,6 @@ static int set_initial_value(struct maru_geo_data *data) } delay = sensor_atoi(sensor_data); - - ret = get_sensor_data(sensor_type_geo_enable, sensor_data); - if (ret) { - ERR("failed to get initial enable"); - return ret; - } - - enable = sensor_atoi(sensor_data); - if (delay < 0) { ERR("weird value is set initial delay"); return ret; @@ -278,10 +290,10 @@ static int set_initial_value(struct maru_geo_data *data) atomic_set(&data->poll_delay, delay); - if (enable) { - atomic_set(&data->enable, 1); - schedule_delayed_work(&data->work, 0); - } + memset(sensor_data, 0, sizeof(sensor_data)); + sensor_data[0] = '0'; + set_sensor_data(sensor_type_geo_enable, sensor_data); + atomic_set(&data->enable, 0); return ret; } diff --git a/drivers/maru/sensors/maru_gyro.c b/drivers/maru/sensors/maru_gyro.c index c54268580e19..d43258b676fa 100644 --- a/drivers/maru/sensors/maru_gyro.c +++ b/drivers/maru/sensors/maru_gyro.c @@ -49,6 +49,10 @@ static struct device *gyro_sensor_device; static struct device *l_gyro_sensor_device; #endif +static int gyro_adjust_x = 1; +static int gyro_adjust_y = 1; +static int gyro_adjust_z = 1; + static void maru_gyro_input_work_func(struct work_struct *work) { int poll_time = 200000000; @@ -74,7 +78,22 @@ static void maru_gyro_input_work_func(struct work_struct *work) { mutex_unlock(&data->data_mutex); if (!ret) { sscanf(sensor_data, "%d,%d,%d", &gyro_x, &gyro_y, &gyro_z); - LOG(1, "gyro_set %d, %d, %d", gyro_x, gyro_y, gyro_z); + LOG(1, "gyro_set act %d, %d, %d", gyro_x, gyro_y, gyro_z); + + if (gyro_x == 0) { + gyro_x = gyro_adjust_x; + gyro_adjust_x *= -1; + } + + if (gyro_y == 0) { + gyro_y = gyro_adjust_y; + gyro_adjust_y *= -1; + } + + if (gyro_z == 0) { + gyro_z = gyro_adjust_z; + gyro_adjust_z *= -1; + } input_report_rel(data->input_data, REL_RX, gyro_x); input_report_rel(data->input_data, REL_RY, gyro_y); @@ -262,10 +281,9 @@ static int set_initial_value(struct maru_gyro_data *data) { int delay = 0; int ret = 0; - int enable = 0; char sensor_data [__MAX_BUF_SENSOR]; - memset(sensor_data, 0, __MAX_BUF_SENSOR); + memset(sensor_data, 0, sizeof(sensor_data)); ret = get_sensor_data(sensor_type_gyro_delay, sensor_data); if (ret) { @@ -274,15 +292,6 @@ static int set_initial_value(struct maru_gyro_data *data) } delay = sensor_atoi(sensor_data); - - ret = get_sensor_data(sensor_type_gyro_enable, sensor_data); - if (ret) { - ERR("failed to get initial enable"); - return ret; - } - - enable = sensor_atoi(sensor_data); - if (delay < 0) { ERR("weird value is set initial delay"); return ret; @@ -290,10 +299,11 @@ static int set_initial_value(struct maru_gyro_data *data) atomic_set(&data->poll_delay, delay); - if (enable) { - atomic_set(&data->enable, 1); - schedule_delayed_work(&data->work, 0); - } + memset(sensor_data, 0, sizeof(sensor_data)); + sensor_data[0] = '0'; + + set_sensor_data(sensor_type_gyro_enable, sensor_data); + atomic_set(&data->enable, 0); return ret; } diff --git a/drivers/maru/sensors/maru_hrm.c b/drivers/maru/sensors/maru_hrm.c new file mode 100644 index 000000000000..431b4c0bc93b --- /dev/null +++ b/drivers/maru/sensors/maru_hrm.c @@ -0,0 +1,336 @@ +/* + * Maru Virtio HRM(HeartBeat Rate Monitor) Sensor Device Driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi + * Sangho Park + * YeongKyoon Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include +#include + +#include "maru_virtio_sensor.h" + +struct maru_hrm_data { + struct input_dev *input_data; + struct delayed_work work; + struct mutex data_mutex; + + struct virtio_sensor* vs; + + atomic_t enable; + atomic_t poll_delay; +}; + +static struct device *hrm_sensor_device; + +static void maru_hrm_input_work_func(struct work_struct *work) { + + int poll_time = 200000000; + int enable = 0; + int ret = 0; + int hrm = 0, rri = 0; + char sensor_data[__MAX_BUF_SENSOR]; + struct maru_hrm_data *data = container_of((struct delayed_work *)work, + struct maru_hrm_data, work); + + LOG(1, "maru_hrm_input_work_func starts"); + + memset(sensor_data, 0, __MAX_BUF_SENSOR); + poll_time = atomic_read(&data->poll_delay); + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + if (enable) { + mutex_lock(&data->data_mutex); + ret = get_sensor_data(sensor_type_hrm, sensor_data); + mutex_unlock(&data->data_mutex); + if (!ret) { + sscanf(sensor_data, "%d, %d", &hrm, &rri); + LOG(1, "hrm_set %d %d", hrm, rri); + + input_report_rel(data->input_data, REL_X, hrm + 1); + input_report_rel(data->input_data, REL_Y, rri + 1); + input_report_rel(data->input_data, REL_Z, 1); + input_sync(data->input_data); + } + } + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + LOG(1, "enable: %d, poll_time: %d", enable, poll_time); + if (enable) { + if (poll_time > 0) { + schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time)); + } else { + schedule_delayed_work(&data->work, 0); + } + } + + LOG(1, "maru_hrm_input_work_func ends"); + +} + +static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_HRM_DEVICE_NAME); +} + +static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR); +} + +static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_hrm_enable, buf); +} + +static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_hrm_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + if (value != 0 && value != 1) + return count; + + set_sensor_data(sensor_type_hrm_enable, buf); + + if (value) { + if (atomic_read(&data->enable) != 1) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + + } + } else { + if (atomic_read(&data->enable) != 0) { + atomic_set(&data->enable, 0); + cancel_delayed_work(&data->work); + } + } + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_hrm_delay, buf); +} + +static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_hrm_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + set_sensor_data(sensor_type_hrm_delay, buf); + atomic_set(&data->poll_delay, value); + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static struct device_attribute dev_attr_sensor_name = + __ATTR(name, S_IRUGO, maru_name_show, NULL); + +static struct device_attribute dev_attr_sensor_vendor = + __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL); + +static struct device_attribute *hrm_sensor_attrs [] = { + &dev_attr_sensor_name, + &dev_attr_sensor_vendor, + NULL, +}; + +static struct device_attribute attr_hrm [] = +{ + MARU_ATTR_RW(enable), + MARU_ATTR_RW(poll_delay), +}; + +static struct attribute *maru_hrm_attribute[] = { + &attr_hrm[0].attr, + &attr_hrm[1].attr, + NULL +}; + +static struct attribute_group maru_hrm_attribute_group = { + .attrs = maru_hrm_attribute +}; + +static void hrm_clear(struct maru_hrm_data *data) { + if (data == NULL) + return; + + if (data->input_data) { + sysfs_remove_group(&data->input_data->dev.kobj, + &maru_hrm_attribute_group); + input_free_device(data->input_data); + } + + kfree(data); + data = NULL; +} + +static int set_initial_value(struct maru_hrm_data *data) +{ + int delay = 0; + int ret = 0; + int enable = 0; + char sensor_data [__MAX_BUF_SENSOR]; + + memset(sensor_data, 0, __MAX_BUF_SENSOR); + + ret = get_sensor_data(sensor_type_hrm_delay, sensor_data); + if (ret) { + ERR("failed to get initial delay time"); + return ret; + } + + delay = sensor_atoi(sensor_data); + + ret = get_sensor_data(sensor_type_hrm_enable, sensor_data); + if (ret) { + ERR("failed to get initial enable"); + return ret; + } + + enable = sensor_atoi(sensor_data); + + if (delay < 0) { + ERR("weird value is set initial delay"); + return ret; + } + + atomic_set(&data->poll_delay, delay); + + if (enable) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + } + + return ret; +} + +static int create_input_device(struct maru_hrm_data *data) +{ + int ret = 0; + struct input_dev *input_data = NULL; + + input_data = input_allocate_device(); + if (input_data == NULL) { + ERR("failed initialing input handler"); + hrm_clear(data); + return -ENOMEM; + } + + input_data->name = SENSOR_HRM_INPUT_NAME; + input_data->id.bustype = BUS_I2C; + + set_bit(EV_REL, input_data->evbit); + input_set_capability(input_data, EV_REL, REL_X); + input_set_capability(input_data, EV_REL, REL_Y); + input_set_capability(input_data, EV_REL, REL_Z); + + data->input_data = input_data; + + ret = input_register_device(input_data); + if (ret) { + ERR("failed to register input data"); + hrm_clear(data); + return ret; + } + + input_set_drvdata(input_data, data); + + ret = sysfs_create_group(&input_data->dev.kobj, + &maru_hrm_attribute_group); + if (ret) { + hrm_clear(data); + ERR("failed initialing devices"); + return ret; + } + + return ret; +} + +int maru_hrm_init(struct virtio_sensor *vs) { + int ret = 0; + struct maru_hrm_data *data = NULL; + + INFO("maru_hrm device init starts."); + + data = kmalloc(sizeof(struct maru_hrm_data), GFP_KERNEL); + if (data == NULL) { + ERR("failed to create hrm data."); + return -ENOMEM; + } + + vs->hrm_handle = data; + data->vs = vs; + + mutex_init(&data->data_mutex); + + INIT_DELAYED_WORK(&data->work, maru_hrm_input_work_func); + + // create name & vendor + ret = register_sensor_device(hrm_sensor_device, vs, + hrm_sensor_attrs, DRIVER_HRM_NAME); + if (ret) { + ERR("failed to register hrm device"); + hrm_clear(data); + return -1; + } + + // create input + ret = create_input_device(data); + if (ret) { + ERR("failed to create input device"); + return ret; + } + + // set initial delay & enable + ret = set_initial_value(data); + if (ret) { + ERR("failed to set initial value"); + return ret; + } + + INFO("maru_hrm device init ends."); + + return ret; +} + +int maru_hrm_exit(struct virtio_sensor *vs) { + struct maru_hrm_data *data = NULL; + + data = (struct maru_hrm_data *)vs->hrm_handle; + hrm_clear(data); + INFO("maru_hrm device exit ends."); + return 0; +} diff --git a/drivers/maru/sensors/maru_light.c b/drivers/maru/sensors/maru_light.c index ae77bc95eb45..ecb6f98266ec 100644 --- a/drivers/maru/sensors/maru_light.c +++ b/drivers/maru/sensors/maru_light.c @@ -76,11 +76,11 @@ static void maru_light_input_work_func(struct work_struct *work) { sscanf(sensor_data, "%d", &light); LOG(1, "light_set %d", light); - input_report_rel(data->input_data, REL_RX, light); // LUX - input_report_rel(data->input_data, REL_HWHEEL, 0); // red - input_report_rel(data->input_data, REL_DIAL, 0); // green - input_report_rel(data->input_data, REL_WHEEL, 0); // blue - input_report_rel(data->input_data, REL_MISC, 0); // white + input_report_rel(data->input_data, REL_RX, (light + 1)); // LUX + input_report_rel(data->input_data, REL_HWHEEL, 0); // red + input_report_rel(data->input_data, REL_DIAL, 0); // green + input_report_rel(data->input_data, REL_WHEEL, 0); // blue + input_report_rel(data->input_data, REL_MISC, 0); // white input_sync(data->input_data); } } diff --git a/drivers/maru/sensors/maru_pressure.c b/drivers/maru/sensors/maru_pressure.c new file mode 100644 index 000000000000..1b84f570d108 --- /dev/null +++ b/drivers/maru/sensors/maru_pressure.c @@ -0,0 +1,361 @@ +/* + * Maru Virtio Pressure Sensor Device Driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi + * Sangho Park + * YeongKyoon Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include +#include + +#include "maru_virtio_sensor.h" + +struct maru_pressure_data { + struct input_dev *input_data; + struct delayed_work work; + struct mutex data_mutex; + + struct virtio_sensor* vs; + + atomic_t enable; + atomic_t poll_delay; +}; + +static struct device *pressure_sensor_device; + +#define PRESSURE_ADJUST 193 +static int pressure_convert_data(int number) +{ + return number * 10000 / PRESSURE_ADJUST; +} + +#define TEMP_ADJUST 2 +static short temp_convert_data(int number) +{ + int temp; + temp = number * TEMP_ADJUST; + return (short)temp; +} + +static void maru_pressure_input_work_func(struct work_struct *work) { + + int poll_time = 200000000; + int enable = 0; + int ret = 0; + int pressure = 0; + int temperature = 0; + int raw_pressure; + short raw_temp; + char sensor_data[__MAX_BUF_SENSOR]; + struct maru_pressure_data *data = container_of((struct delayed_work *)work, + struct maru_pressure_data, work); + + LOG(1, "maru_pressure_input_work_func starts"); + + memset(sensor_data, 0, sizeof(sensor_data)); + poll_time = atomic_read(&data->poll_delay); + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + if (enable) { + mutex_lock(&data->data_mutex); + ret = get_sensor_data(sensor_type_pressure, sensor_data); + mutex_unlock(&data->data_mutex); + if (!ret) { + sscanf(sensor_data, "%d, %d", &pressure, &temperature); + LOG(1, "pressure_set %d, %d", pressure, temperature); + + raw_pressure = pressure_convert_data(pressure); + if (temperature == 0) { + temperature = 1; + } + raw_temp = temp_convert_data(temperature); + + LOG(1, "pressure raw pressure %d, temp %d.\n", raw_pressure, raw_temp); + + input_report_rel(data->input_data, REL_HWHEEL, raw_pressure); + input_report_rel(data->input_data, REL_DIAL, 101325); + input_report_rel(data->input_data, REL_WHEEL, raw_temp); + input_sync(data->input_data); + } + } + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + LOG(1, "enable: %d, poll_time: %d", enable, poll_time); + if (enable) { + if (poll_time > 0) { + schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time)); + } else { + schedule_delayed_work(&data->work, 0); + } + } + + LOG(1, "maru_pressure_input_work_func ends"); + +} + +static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_PRESSURE_DEVICE_NAME); +} + +static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR); +} + +static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_pressure_enable, buf); +} + +static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_pressure_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + if (value != 0 && value != 1) + return count; + + set_sensor_data(sensor_type_pressure_enable, buf); + + if (value) { + if (atomic_read(&data->enable) != 1) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + + } + } else { + if (atomic_read(&data->enable) != 0) { + atomic_set(&data->enable, 0); + cancel_delayed_work(&data->work); + } + } + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_pressure_delay, buf); +} + +static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_pressure_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + set_sensor_data(sensor_type_pressure_delay, buf); + atomic_set(&data->poll_delay, value); + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static struct device_attribute dev_attr_sensor_name = + __ATTR(name, S_IRUGO, maru_name_show, NULL); + +static struct device_attribute dev_attr_sensor_vendor = + __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL); + +static struct device_attribute *pressure_sensor_attrs [] = { + &dev_attr_sensor_name, + &dev_attr_sensor_vendor, + NULL, +}; + +static struct device_attribute attr_pressure [] = +{ + MARU_ATTR_RW(enable), + MARU_ATTR_RW(poll_delay), +}; + +static struct attribute *maru_pressure_attribute[] = { + &attr_pressure[0].attr, + &attr_pressure[1].attr, + NULL +}; + +static struct attribute_group maru_pressure_attribute_group = { + .attrs = maru_pressure_attribute +}; + +static void pressure_clear(struct maru_pressure_data *data) { + if (data == NULL) + return; + + if (data->input_data) { + sysfs_remove_group(&data->input_data->dev.kobj, + &maru_pressure_attribute_group); + input_free_device(data->input_data); + } + + kfree(data); + data = NULL; +} + +static int set_initial_value(struct maru_pressure_data *data) +{ + int delay = 0; + int ret = 0; + int enable = 0; + char sensor_data [__MAX_BUF_SENSOR]; + + memset(sensor_data, 0, sizeof(sensor_data)); + + ret = get_sensor_data(sensor_type_pressure_delay, sensor_data); + if (ret) { + ERR("failed to get initial delay time"); + return ret; + } + + delay = sensor_atoi(sensor_data); + + ret = get_sensor_data(sensor_type_pressure_enable, sensor_data); + if (ret) { + ERR("failed to get initial enable"); + return ret; + } + + enable = sensor_atoi(sensor_data); + + if (delay < 0) { + ERR("weird value is set initial delay"); + return ret; + } + + atomic_set(&data->poll_delay, delay); + + if (enable) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + } + + return ret; +} + +static int create_input_device(struct maru_pressure_data *data) +{ + int ret = 0; + struct input_dev *input_data = NULL; + + input_data = input_allocate_device(); + if (input_data == NULL) { + ERR("failed initialing input handler"); + pressure_clear(data); + return -ENOMEM; + } + + input_data->name = SENSOR_PRESSURE_INPUT_NAME; + input_data->id.bustype = BUS_I2C; + + set_bit(EV_REL, input_data->evbit); + input_set_capability(input_data, EV_REL, REL_HWHEEL); + input_set_capability(input_data, EV_REL, REL_DIAL); + input_set_capability(input_data, EV_REL, REL_WHEEL); + + data->input_data = input_data; + + ret = input_register_device(input_data); + if (ret) { + ERR("failed to register input data"); + pressure_clear(data); + return ret; + } + + input_set_drvdata(input_data, data); + + ret = sysfs_create_group(&input_data->dev.kobj, + &maru_pressure_attribute_group); + if (ret) { + pressure_clear(data); + ERR("failed initialing devices"); + return ret; + } + + return ret; +} + +int maru_pressure_init(struct virtio_sensor *vs) { + int ret = 0; + struct maru_pressure_data *data = NULL; + + INFO("maru_pressure device init starts."); + + data = kmalloc(sizeof(struct maru_pressure_data), GFP_KERNEL); + if (data == NULL) { + ERR("failed to create pressure data."); + return -ENOMEM; + } + + vs->pressure_handle = data; + data->vs = vs; + + mutex_init(&data->data_mutex); + + INIT_DELAYED_WORK(&data->work, maru_pressure_input_work_func); + + // create name & vendor + ret = register_sensor_device(pressure_sensor_device, vs, + pressure_sensor_attrs, DRIVER_PRESSURE_NAME); + if (ret) { + ERR("failed to register pressure device"); + pressure_clear(data); + return -1; + } + + // create input + ret = create_input_device(data); + if (ret) { + ERR("failed to create input device"); + return ret; + } + + // set initial delay & enable + ret = set_initial_value(data); + if (ret) { + ERR("failed to set initial value"); + return ret; + } + + INFO("maru_pressure device init ends."); + + return ret; +} + +int maru_pressure_exit(struct virtio_sensor *vs) { + struct maru_pressure_data *data = NULL; + + data = (struct maru_pressure_data *)vs->pressure_handle; + pressure_clear(data); + INFO("maru_pressure device exit ends."); + return 0; +} diff --git a/drivers/maru/sensors/maru_proxi.c b/drivers/maru/sensors/maru_proxi.c index 94bbae3d83b0..1c9d13d33b19 100644 --- a/drivers/maru/sensors/maru_proxi.c +++ b/drivers/maru/sensors/maru_proxi.c @@ -74,11 +74,14 @@ static void maru_proxi_input_work_func(struct work_struct *work) { mutex_unlock(&data->data_mutex); if (!ret) { sscanf(sensor_data, "%d", &proxi); - if (proxi) + if (!proxi) proxi = 1; + else + proxi = 0; + LOG(1, "proxi_set %d", proxi); - input_report_rel(data->input_data, ABS_DISTANCE, proxi); + input_report_abs(data->input_data, ABS_DISTANCE, proxi); input_sync(data->input_data); } } @@ -298,10 +301,12 @@ static int create_input_device(struct maru_proxi_data *data) } input_data->name = SENSOR_PROXI_INPUT_NAME; - input_data->id.bustype = BUS_I2C; + + input_set_drvdata(input_data, data); set_bit(EV_ABS, input_data->evbit); input_set_capability(input_data, EV_ABS, ABS_DISTANCE); + input_set_abs_params(input_data, ABS_DISTANCE, 0, 1, 0, 0); data->input_data = input_data; @@ -312,8 +317,6 @@ static int create_input_device(struct maru_proxi_data *data) return ret; } - input_set_drvdata(input_data, data); - ret = sysfs_create_group(&input_data->dev.kobj, &maru_proxi_attribute_group); if (ret) { diff --git a/drivers/maru/sensors/maru_uv.c b/drivers/maru/sensors/maru_uv.c new file mode 100644 index 000000000000..2c6037d62bf0 --- /dev/null +++ b/drivers/maru/sensors/maru_uv.c @@ -0,0 +1,332 @@ +/* + * Maru Virtio UltraViolet Sensor Device Driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi + * Sangho Park + * YeongKyoon Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include +#include + +#include "maru_virtio_sensor.h" + +struct maru_uv_data { + struct input_dev *input_data; + struct delayed_work work; + struct mutex data_mutex; + + struct virtio_sensor* vs; + + atomic_t enable; + atomic_t poll_delay; +}; + +static struct device *uv_sensor_device; + +static void maru_uv_input_work_func(struct work_struct *work) { + + int poll_time = 200000000; + int enable = 0; + int ret = 0; + int uv = 0; + char sensor_data[__MAX_BUF_SENSOR]; + struct maru_uv_data *data = container_of((struct delayed_work *)work, + struct maru_uv_data, work); + + LOG(1, "maru_uv_input_work_func starts"); + + memset(sensor_data, 0, __MAX_BUF_SENSOR); + poll_time = atomic_read(&data->poll_delay); + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + if (enable) { + mutex_lock(&data->data_mutex); + ret = get_sensor_data(sensor_type_uv, sensor_data); + mutex_unlock(&data->data_mutex); + if (!ret) { + sscanf(sensor_data, "%d", &uv); + LOG(1, "uv_set %d", uv); + + input_report_rel(data->input_data, REL_MISC, (uv + 1)); + input_sync(data->input_data); + } + } + + mutex_lock(&data->data_mutex); + enable = atomic_read(&data->enable); + mutex_unlock(&data->data_mutex); + + LOG(1, "enable: %d, poll_time: %d", enable, poll_time); + if (enable) { + if (poll_time > 0) { + schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time)); + } else { + schedule_delayed_work(&data->work, 0); + } + } + + LOG(1, "maru_uv_input_work_func ends"); + +} + +static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_UV_DEVICE_NAME); +} + +static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR); +} + +static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_uv_enable, buf); +} + +static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_uv_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + if (value != 0 && value != 1) + return count; + + set_sensor_data(sensor_type_uv_enable, buf); + + if (value) { + if (atomic_read(&data->enable) != 1) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + + } + } else { + if (atomic_read(&data->enable) != 0) { + atomic_set(&data->enable, 0); + cancel_delayed_work(&data->work); + } + } + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return get_data_for_show(sensor_type_uv_delay, buf); +} + +static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_data = to_input_dev(dev); + struct maru_uv_data *data = input_get_drvdata(input_data); + int value = simple_strtoul(buf, NULL, 10); + + set_sensor_data(sensor_type_uv_delay, buf); + atomic_set(&data->poll_delay, value); + + return strnlen(buf, __MAX_BUF_SENSOR); +} + +static struct device_attribute dev_attr_sensor_name = + __ATTR(name, S_IRUGO, maru_name_show, NULL); + +static struct device_attribute dev_attr_sensor_vendor = + __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL); + +static struct device_attribute *uv_sensor_attrs [] = { + &dev_attr_sensor_name, + &dev_attr_sensor_vendor, + NULL, +}; + +static struct device_attribute attr_uv [] = +{ + MARU_ATTR_RW(enable), + MARU_ATTR_RW(poll_delay), +}; + +static struct attribute *maru_uv_attribute[] = { + &attr_uv[0].attr, + &attr_uv[1].attr, + NULL +}; + +static struct attribute_group maru_uv_attribute_group = { + .attrs = maru_uv_attribute +}; + +static void uv_clear(struct maru_uv_data *data) { + if (data == NULL) + return; + + if (data->input_data) { + sysfs_remove_group(&data->input_data->dev.kobj, + &maru_uv_attribute_group); + input_free_device(data->input_data); + } + + kfree(data); + data = NULL; +} + +static int set_initial_value(struct maru_uv_data *data) +{ + int delay = 0; + int ret = 0; + int enable = 0; + char sensor_data [__MAX_BUF_SENSOR]; + + memset(sensor_data, 0, __MAX_BUF_SENSOR); + + ret = get_sensor_data(sensor_type_uv_delay, sensor_data); + if (ret) { + ERR("failed to get initial delay time"); + return ret; + } + + delay = sensor_atoi(sensor_data); + + ret = get_sensor_data(sensor_type_uv_enable, sensor_data); + if (ret) { + ERR("failed to get initial enable"); + return ret; + } + + enable = sensor_atoi(sensor_data); + + if (delay < 0) { + ERR("weird value is set initial delay"); + return ret; + } + + atomic_set(&data->poll_delay, delay); + + if (enable) { + atomic_set(&data->enable, 1); + schedule_delayed_work(&data->work, 0); + } + + return ret; +} + +static int create_input_device(struct maru_uv_data *data) +{ + int ret = 0; + struct input_dev *input_data = NULL; + + input_data = input_allocate_device(); + if (input_data == NULL) { + ERR("failed initialing input handler"); + uv_clear(data); + return -ENOMEM; + } + + input_data->name = SENSOR_UV_INPUT_NAME; + input_data->id.bustype = BUS_I2C; + + set_bit(EV_REL, input_data->evbit); + input_set_capability(input_data, EV_REL, REL_MISC); + + data->input_data = input_data; + + ret = input_register_device(input_data); + if (ret) { + ERR("failed to register input data"); + uv_clear(data); + return ret; + } + + input_set_drvdata(input_data, data); + + ret = sysfs_create_group(&input_data->dev.kobj, + &maru_uv_attribute_group); + if (ret) { + uv_clear(data); + ERR("failed initialing devices"); + return ret; + } + + return ret; +} + +int maru_uv_init(struct virtio_sensor *vs) { + int ret = 0; + struct maru_uv_data *data = NULL; + + INFO("maru_uv device init starts."); + + data = kmalloc(sizeof(struct maru_uv_data), GFP_KERNEL); + if (data == NULL) { + ERR("failed to create uv data."); + return -ENOMEM; + } + + vs->uv_handle = data; + data->vs = vs; + + mutex_init(&data->data_mutex); + + INIT_DELAYED_WORK(&data->work, maru_uv_input_work_func); + + // create name & vendor + ret = register_sensor_device(uv_sensor_device, vs, + uv_sensor_attrs, DRIVER_UV_NAME); + if (ret) { + ERR("failed to register uv device"); + uv_clear(data); + return -1; + } + + // create input + ret = create_input_device(data); + if (ret) { + ERR("failed to create input device"); + return ret; + } + + // set initial delay & enable + ret = set_initial_value(data); + if (ret) { + ERR("failed to set initial value"); + return ret; + } + + INFO("maru_uv device init ends."); + + return ret; +} + +int maru_uv_exit(struct virtio_sensor *vs) { + struct maru_uv_data *data = NULL; + + data = (struct maru_uv_data *)vs->uv_handle; + uv_clear(data); + INFO("maru_uv device exit ends."); + return 0; +} diff --git a/drivers/maru/sensors/maru_virtio_sensor.c b/drivers/maru/sensors/maru_virtio_sensor.c index 63c71dfc6b88..d47bf58bd5ee 100644 --- a/drivers/maru/sensors/maru_virtio_sensor.c +++ b/drivers/maru/sensors/maru_virtio_sensor.c @@ -316,6 +316,30 @@ static void device_init(struct virtio_sensor *vs) ERR("failed to init haptic with error %d", ret); } } + + if (vs->sensor_capability & sensor_cap_pressure) { + ret = maru_pressure_init(vs); + if (ret) { + vs->sensor_fail_init |= sensor_cap_pressure; + ERR("failed to init pressure with error %d", ret); + } + } + + if (vs->sensor_capability & sensor_cap_uv) { + ret = maru_uv_init(vs); + if (ret) { + vs->sensor_fail_init |= sensor_cap_uv; + ERR("failed to init uv with error %d", ret); + } + } + + if (vs->sensor_capability & sensor_cap_hrm) { + ret = maru_hrm_init(vs); + if (ret) { + vs->sensor_fail_init |= sensor_cap_hrm; + ERR("failed to init hrm with error %d", ret); + } + } } static void device_exit(struct virtio_sensor *vs) @@ -354,6 +378,21 @@ static void device_exit(struct virtio_sensor *vs) !(vs->sensor_fail_init & sensor_cap_haptic)) { maru_haptic_exit(vs); } + + if (vs->sensor_capability & sensor_cap_pressure && + !(vs->sensor_fail_init & sensor_cap_pressure)) { + maru_pressure_exit(vs); + } + + if (vs->sensor_capability & sensor_cap_uv && + !(vs->sensor_fail_init & sensor_cap_uv)) { + maru_uv_exit(vs); + } + + if (vs->sensor_capability & sensor_cap_hrm && + !(vs->sensor_fail_init & sensor_cap_hrm)) { + maru_hrm_exit(vs); + } } static void cleanup(struct virtio_device* dev) { diff --git a/drivers/maru/sensors/maru_virtio_sensor.h b/drivers/maru/sensors/maru_virtio_sensor.h index 12c75eb42a60..06533bcba68b 100644 --- a/drivers/maru/sensors/maru_virtio_sensor.h +++ b/drivers/maru/sensors/maru_virtio_sensor.h @@ -69,17 +69,31 @@ enum sensor_types { sensor_type_rotation_vector_delay, sensor_type_mag, sensor_type_tilt, + sensor_type_pressure, + sensor_type_pressure_enable, + sensor_type_pressure_delay, + sensor_type_uv, + sensor_type_uv_enable, + sensor_type_uv_delay, + sensor_type_hrm, + sensor_type_hrm_heart, + sensor_type_hrm_rri, + sensor_type_hrm_enable, + sensor_type_hrm_delay, sensor_type_max }; enum sensor_capabilities { - sensor_cap_accel = 0x01, - sensor_cap_geo = 0x02, - sensor_cap_gyro = 0x04, - sensor_cap_light = 0x08, - sensor_cap_proxi = 0x10, - sensor_cap_rotation_vector = 0x20, - sensor_cap_haptic = 0x40 + sensor_cap_accel = 0x0001, + sensor_cap_geo = 0x0002, + sensor_cap_gyro = 0x0004, + sensor_cap_light = 0x0008, + sensor_cap_proxi = 0x0010, + sensor_cap_rotation_vector = 0x0020, + sensor_cap_haptic = 0x0040, + sensor_cap_pressure = 0x0080, + sensor_cap_uv = 0x0100, + sensor_cap_hrm = 0x0200 }; #define __MAX_BUF_SIZE 1024 @@ -122,6 +136,9 @@ struct virtio_sensor { void* proxi_handle; void* rotation_vector_handle; void* haptic_handle; + void* pressure_handle; + void* uv_handle; + void* hrm_handle; }; #define MARU_DEVICE_ATTR(_name) \ @@ -181,6 +198,18 @@ int get_sensor_data(int type, char* data); #define SENSOR_HAPTIC_INPUT_NAME "haptic_sensor" +#define DRIVER_PRESSURE_NAME "pressure" +#define SENSOR_PRESSURE_INPUT_NAME "pressure_sensor" +#define MARU_PRESSURE_DEVICE_NAME "maru_sensor_pressure_1" + +#define DRIVER_UV_NAME "ultraviolet" +#define SENSOR_UV_INPUT_NAME "uv_sensor" +#define MARU_UV_DEVICE_NAME "maru_sensor_uv_1" + +#define DRIVER_HRM_NAME "hrm" +#define SENSOR_HRM_INPUT_NAME "hrm_lib_sensor" +#define MARU_HRM_DEVICE_NAME "maru_sensor_hrm_1" + // It locates /sys/module/maru_virtio_sensor/parameters/sensor_driver_debug extern int sensor_driver_debug; @@ -239,4 +268,22 @@ int maru_rotation_vector_exit(struct virtio_sensor *vs); int maru_haptic_init(struct virtio_sensor *vs); int maru_haptic_exit(struct virtio_sensor *vs); +/* + * Pressure device + */ +int maru_pressure_init(struct virtio_sensor *vs); +int maru_pressure_exit(struct virtio_sensor *vs); + +/* + * UV(UltraViolet) device + */ +int maru_uv_init(struct virtio_sensor *vs); +int maru_uv_exit(struct virtio_sensor *vs); + +/* + * HRM(Heart Beat Rate) device + */ +int maru_hrm_init(struct virtio_sensor *vs); +int maru_hrm_exit(struct virtio_sensor *vs); + #endif