summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--hw/haptic/CMakeLists.txt25
-rw-r--r--hw/haptic/gpio.c352
3 files changed, 378 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 01bda9c..bc89dd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,3 +13,4 @@ ADD_SUBDIRECTORY(hw/usb_gadget)
ADD_SUBDIRECTORY(hw/usb_client)
ADD_SUBDIRECTORY(hw/usb_cfs_client)
ADD_SUBDIRECTORY(hw/thermal)
+ADD_SUBDIRECTORY(hw/haptic)
diff --git a/hw/haptic/CMakeLists.txt b/hw/haptic/CMakeLists.txt
new file mode 100644
index 0000000..f8fac63
--- /dev/null
+++ b/hw/haptic/CMakeLists.txt
@@ -0,0 +1,25 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(hal-backend-device-haptic C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+INCLUDE_DIRECTORIES(../common)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(haptic_pkgs REQUIRED
+ dlog
+ glib-2.0
+ libsyscommon
+ capi-system-peripheral-io)
+
+FOREACH(flag ${haptic_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_LIBRARY(${PROJECT_NAME} MODULE gpio.c)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${haptic_pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /hal/lib COMPONENT RuntimeLibraries)
diff --git a/hw/haptic/gpio.c b/hw/haptic/gpio.c
new file mode 100644
index 0000000..67ba19a
--- /dev/null
+++ b/hw/haptic/gpio.c
@@ -0,0 +1,352 @@
+/*
+ * feedbackd
+ *
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <peripheral_io.h>
+#include <libsyscommon/list.h>
+#include <hal/device/hal-haptic-interface.h>
+
+#include "common.h"
+
+#define GPIO_I2C_BUS_INDEX 1
+#define MAX_HAPIC 1
+#define DRV2605L_DEFAULT_ADDR 0x5A
+
+#define START_CMD_CODE 1
+#define STOP_CMD_CODE 0
+
+#define DRV2605L_REGISTER_STATUS 0x00
+#define DRV2605L_REGISTER_MODE 0x01
+#define DRV2605L_REGISTER_RTPINPUT 0x02
+#define DRV2605L_REGISTER_LIBRARY 0x03
+#define DRV2605L_REGISTER_WAVESEQ1 0x04
+#define DRV2605L_REGISTER_WAVESEQ2 0x05
+#define DRV2605L_REGISTER_WAVESEQ3 0x06
+#define DRV2605L_REGISTER_WAVESEQ4 0x07
+#define DRV2605L_REGISTER_WAVESEQ5 0x08
+#define DRV2605L_REGISTER_WAVESEQ6 0x09
+#define DRV2605L_REGISTER_WAVESEQ7 0x0A
+#define DRV2605L_REGISTER_WAVESEQ8 0x0B
+#define DRV2605L_REGISTER_GO 0x0C
+
+/**
+ * Mode register
+ */
+#define MODE_INTERNAL_TRIGGER 0
+#define MODE_EXTERNAL_TRIGGER_EDGE 1
+#define MODE_EXTERNAL_TRIGGER_LEVEL 2
+#define MODE_PWM_INPUT_ANALOG_INPUT 3
+#define MODE_AUDIO_TO_VIBE 4
+#define MODE_REALTIME_PLAYBACK 5
+#define MODE_DIAGNOSTICS 6
+#define MODE_AUTO_CALIBRATION 7
+/**
+ * Library register
+ */
+#define EMPTY_LIBRARY 0
+#define TS2200_LIBRARY_A 1
+#define TS2200_LIBRARY_B 2
+#define TS2200_LIBRARY_C 3
+#define TS2200_LIBRARY_D 4
+#define TS2200_LIBRARY_E 5
+#define LRA_LIBRARY_E 6
+#define TS2200_LIBRARY_F 7
+
+#define MAX_LEVEL 2
+#define MAX_INTENSITY 10000
+
+static peripheral_i2c_h device_handle = NULL;
+
+static GList *handle_list;
+static int unique_number;
+
+static bool state = false;
+static guint stop_timer = 0;
+
+static int gpio_haptic_stop_device(int handle);
+
+static bool find_from_list(int handle)
+{
+ GList *elem;
+
+ elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)handle);
+ if (elem)
+ return true;
+
+ return false;
+}
+
+static gboolean gpio_haptic_timer_cb(void *data)
+{
+ int handle = (int)(long)data;
+ bool found;
+
+ _I("Stop vibration by timer.");
+
+ found = find_from_list(handle);
+ if (!found)
+ return G_SOURCE_REMOVE;
+
+ if (device_handle == NULL) {
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ return -EIO;
+ }
+ }
+
+ /* stop playing */
+ peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
+
+ stop_timer = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static int gpio_haptic_get_device_count(int *count)
+{
+ _I("HAL: The max number of DRV2605L is %d.", (int)MAX_HAPIC);
+ if (count)
+ *count = MAX_HAPIC;
+
+ return 0;
+}
+
+/**
+ * Only one handle
+ * return device_handle
+ */
+static int gpio_haptic_open_device(int *handle)
+{
+ int n;
+ bool found = false;
+ GList *elem;
+
+ if (!handle)
+ return -EINVAL;
+
+ /* if it is the first element */
+ n = SYS_G_LIST_LENGTH(handle_list);
+ if (n == 0) {
+ _I("Peripheral Device Open.");
+ if (device_handle == NULL) {
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ return -EIO;
+ }
+ }
+ }
+
+ if (unique_number == INT_MAX)
+ unique_number = 0;
+
+ while (found != true) {
+ ++unique_number;
+ elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+ if (!elem)
+ found = true;
+ }
+
+ /* add info to local list */
+ SYS_G_LIST_APPEND(handle_list, (gpointer)(long)unique_number);
+
+ *handle = unique_number;
+ return 0;
+}
+
+static int gpio_haptic_close_device(int handle)
+{
+ int r, n;
+ bool found;
+
+ found = find_from_list(handle);
+ if (!found)
+ return -EINVAL;
+
+ if (device_handle == NULL) {
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ return -EIO;
+ }
+ }
+
+ /* stop vibration */
+ r = gpio_haptic_stop_device(handle);
+ if (r < 0)
+ _I("Already stopped or failed to stop effect: %d", r);
+
+ _D("Handle(%d) is closed and timer deleted.", handle);
+ SYS_G_LIST_REMOVE(handle_list, (gpointer)(long)handle);
+
+ /* if it is the last element */
+ n = SYS_G_LIST_LENGTH(handle_list);
+ if (n == 0) {
+ _I("Peripheral Device Close.");
+ if (device_handle != NULL) {
+ if (peripheral_i2c_close(device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to close peripheral I2C.");
+ return -EIO;
+ }
+ device_handle = NULL;
+ }
+ }
+ return 0;
+}
+
+static int gpio_haptic_vibrate_monotone(int handle, int duration, int frequency, int overdrive, int level, int intensity, int priority)
+{
+ bool found;
+ int feedback;
+ int max_level;
+
+ if (level <= 0)
+ return -EINVAL;
+
+ found = find_from_list(handle);
+ if (!found)
+ return -EINVAL;
+
+ if (device_handle == NULL) {
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ return -EIO;
+ }
+ }
+
+ /* Zero(0) is the infinitely vibration value */
+ if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
+ duration = 0;
+
+ if (stop_timer)
+ gpio_haptic_stop_device(handle);
+
+ max_level = (level <= MAX_LEVEL)? MAX_LEVEL: level;
+ if (intensity)
+ feedback = ((level/max_level) * intensity) / 100;
+ else
+ feedback = ((level/max_level) * MAX_INTENSITY) / 100;
+
+ /* play vibration */
+ peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_LIBRARY, TS2200_LIBRARY_A);
+ /* continuously vibrate*/
+ peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_REALTIME_PLAYBACK);
+ peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_RTPINPUT, (uint8_t)feedback);
+
+ /* register timer */
+ if (duration) {
+ //stop_timer = ecore_timer_add(duration/1000.f, gpio_haptic_timer_cb, (void *)(long)handle);
+ stop_timer = g_timeout_add(duration, gpio_haptic_timer_cb, (void *)(long)handle);
+ if (!stop_timer)
+ _E("Failed to add timer callback.");
+ }
+ _D("Device handle(%d) %dms", handle, duration);
+
+ return 0;
+}
+
+static int gpio_haptic_stop_device(int handle)
+{
+ bool found;
+
+ found = find_from_list(handle);
+ if (!found)
+ return -EINVAL;
+
+ if (device_handle == NULL) {
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ return -EIO;
+ }
+ }
+
+ /* stop playing */
+ peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
+
+ if (stop_timer) {
+ //ecore_timer_del(stop_timer);
+ g_source_remove(stop_timer);
+ stop_timer = 0;
+ }
+
+ return 0;
+}
+
+static bool is_valid(void)
+{
+ uint8_t result;
+ peripheral_i2c_h handle;
+
+ if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to open I2C.");
+ state = false;
+ return false;
+ }
+ if (peripheral_i2c_read_register_byte(handle, DRV2605L_REGISTER_STATUS, &result) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to read peripheral I2C.");
+ if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE)
+ _E("Failed to close peripheral I2C.");
+ state = false;
+ return false;
+ }
+ if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE) {
+ _E("Failed to close peripheral I2C.");
+ state = false;
+ return false;
+ }
+
+ state = true;
+ _I("Support gpio haptic device.");
+ return true;
+}
+
+static int haptic_init(void **data)
+{
+ hal_backend_haptic_funcs *haptic_funcs;
+
+ haptic_funcs = calloc(1, sizeof(hal_backend_haptic_funcs));
+ if (!haptic_funcs)
+ return -ENOMEM;
+
+ haptic_funcs->get_device_count = gpio_haptic_get_device_count;
+ haptic_funcs->open_device = gpio_haptic_open_device;
+ haptic_funcs->close_device = gpio_haptic_close_device;
+ haptic_funcs->vibrate_monotone = gpio_haptic_vibrate_monotone;
+ haptic_funcs->stop_device = gpio_haptic_stop_device;
+ haptic_funcs->is_valid = is_valid;
+
+ *data = (void *)haptic_funcs;
+
+ return 0;
+}
+
+static int haptic_exit(void *data)
+{
+ if (!data)
+ return -EINVAL;
+
+ free(data);
+ return 0;
+}
+
+
+hal_backend EXPORT hal_backend_device_haptic_data = {
+ .name = "haptic",
+ .vendor = "ARTIK",
+ .abi_version = HAL_ABI_VERSION_TIZEN_6_5,
+ .init = haptic_init,
+ .exit = haptic_exit,
+};