summaryrefslogtreecommitdiff
path: root/drivers/staging/greybus/vibrator.c
diff options
context:
space:
mode:
authorAnn Chen <chen_ann@projectara.com>2016-08-17 16:38:56 +0800
committerGreg Kroah-Hartman <gregkh@google.com>2016-08-18 13:36:28 +0200
commit0900845ab741dd7b0b8b3f03ded0ffc6a348dd90 (patch)
treefa6035ddf11ca3d0a96de04c580ba79cdc4c6ac8 /drivers/staging/greybus/vibrator.c
parent5f62eab04ab7d78afd8acf00c48a7a1539794e1f (diff)
greybus: Add workqueue to handle vibrator timeout
In the beginning, module side can control the vibrator timeout value, it can disable vibrator until timeout. But after Runtime PM control added in, AP side didn't know when module can be suspended, the vibrator task will be interrupted by suspending event. Because of this problem, the module can not be in charge of counting down the timeout value, it is now up to the AP to manage this. So add workqueue to handle the vibrator timeout. Signed-off-by: Ann Chen <chen_ann@projectara.com> Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/vibrator.c')
-rw-r--r--drivers/staging/greybus/vibrator.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/staging/greybus/vibrator.c b/drivers/staging/greybus/vibrator.c
index db5583962101..7296a4dd0a0c 100644
--- a/drivers/staging/greybus/vibrator.c
+++ b/drivers/staging/greybus/vibrator.c
@@ -21,36 +21,27 @@ struct gb_vibrator_device {
struct gb_connection *connection;
struct device *dev;
int minor; /* vibrator minor number */
+ struct delayed_work delayed_work;
};
/* Greybus Vibrator operation types */
#define GB_VIBRATOR_TYPE_ON 0x02
#define GB_VIBRATOR_TYPE_OFF 0x03
-struct gb_vibrator_on_request {
- __le16 timeout_ms;
-};
-
-static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
+static int turn_off(struct gb_vibrator_device *vib)
{
- struct gb_vibrator_on_request request;
struct gb_bundle *bundle = vib->connection->bundle;
int ret;
- ret = gb_pm_runtime_get_sync(bundle);
- if (ret)
- return ret;
-
- request.timeout_ms = cpu_to_le16(timeout_ms);
- ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON,
- &request, sizeof(request), NULL, 0);
+ ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF,
+ NULL, 0, NULL, 0);
gb_pm_runtime_put_autosuspend(bundle);
return ret;
}
-static int turn_off(struct gb_vibrator_device *vib)
+static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
{
struct gb_bundle *bundle = vib->connection->bundle;
int ret;
@@ -59,12 +50,29 @@ static int turn_off(struct gb_vibrator_device *vib)
if (ret)
return ret;
- ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF,
+ /* Vibrator was switched ON earlier */
+ if (cancel_delayed_work_sync(&vib->delayed_work))
+ turn_off(vib);
+
+ ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON,
NULL, 0, NULL, 0);
+ if (ret) {
+ gb_pm_runtime_put_autosuspend(bundle);
+ return ret;
+ }
- gb_pm_runtime_put_autosuspend(bundle);
+ schedule_delayed_work(&vib->delayed_work, msecs_to_jiffies(timeout_ms));
- return ret;
+ return 0;
+}
+
+static void gb_vibrator_worker(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct gb_vibrator_device *vib =
+ container_of(delayed_work, struct gb_vibrator_device, delayed_work);
+
+ turn_off(vib);
}
static ssize_t timeout_store(struct device *dev, struct device_attribute *attr,
@@ -174,6 +182,8 @@ static int gb_vibrator_probe(struct gb_bundle *bundle,
}
#endif
+ INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker);
+
gb_pm_runtime_put_autosuspend(bundle);
return 0;
@@ -199,6 +209,9 @@ static void gb_vibrator_disconnect(struct gb_bundle *bundle)
if (ret)
gb_pm_runtime_get_noresume(bundle);
+ if (cancel_delayed_work_sync(&vib->delayed_work))
+ turn_off(vib);
+
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0)
sysfs_remove_group(&vib->dev->kobj, vibrator_groups[0]);
#endif