@@ -31,6 +31,7 @@
#include <linux/platform_data/zforce_ts.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
+#include <linux/workqueue.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
@@ -98,6 +99,12 @@ struct zforce_point {
int prblty;
};
+enum zforce_state {
+ ZF_STATE_UNINITIALZED = 0,
+ ZF_STATE_PROBE_COMPLETE,
+ ZF_STATE_DEV_OPENED,
+};
+
/*
* @client the i2c_client
* @input the input device
@@ -138,6 +145,11 @@ struct zforce_ts {
struct mutex command_mutex;
int command_waiting;
int command_result;
+
+ struct work_struct ts_workq;
+ int notification;
+
+ enum zforce_state state;
};
static int zforce_command(struct zforce_ts *ts, u8 cmd)
@@ -188,6 +200,7 @@ static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len)
buf[1], buf[2]);
ts->command_waiting = buf[2];
+ reinit_completion(&ts->command_done);
mutex_lock(&ts->access_mutex);
ret = i2c_master_send(client, buf, len);
@@ -471,6 +484,15 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
dev_dbg(&client->dev, "completing command 0x%x\n", cmd);
ts->command_result = result;
complete(&ts->command_done);
+ } else if (cmd == NOTIFICATION_BOOTCOMPLETE) {
+ dev_dbg(&client->dev, "got notification 0x%x\n", cmd);
+
+ /* abourt previous waiting command if any available */
+ ts->command_result = -ECONNABORTED;
+ ts->notification = cmd;
+ complete(&ts->command_done);
+
+ queue_work(system_long_wq, &ts->ts_workq);
} else {
dev_dbg(&client->dev, "command %d not for us\n", cmd);
}
@@ -596,11 +618,85 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * This device is used in automotive environment. In this
+ * we should never fail. Some connection issues caused by vibration
+ * should be ignored and can be recoverable.
+ */
+static void zforce_boot(struct zforce_ts *ts)
+{
+ struct device *dev = &ts->client->dev;
+ int ret;
+
+ /* need to start device to get version information */
+ ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
+ if (ret)
+ dev_err(dev, "unable to initialize, %d\n", ret);
+
+ switch (ts->state) {
+ case ZF_STATE_UNINITIALZED:
+ ret = zforce_command_wait(ts, COMMAND_STATUS);
+ if (ret)
+ dev_err(dev, "couldn't get status, %d\n", ret);
+ /* fallthrough, we need zforce_stop to complete. */
+ case ZF_STATE_PROBE_COMPLETE:
+ /* stop device and put it into sleep until it is opened */
+ ret = zforce_stop(ts);
+ if (ret)
+ dev_err(dev, "couldn't stop zforce, %d\n", ret);
+
+ ts->state = ZF_STATE_PROBE_COMPLETE;
+ break;
+ case ZF_STATE_DEV_OPENED:
+ ret = zforce_start(ts);
+ if (ret)
+ dev_err(dev, "Failed to restart, %d\n", ret);
+ break;
+ }
+}
+
+static void zforce_notification_queue(struct work_struct *work)
+{
+ struct zforce_ts *ts = container_of(work, struct zforce_ts, ts_workq);
+ struct i2c_client *client = ts->client;
+ struct input_dev *input = ts->input;
+
+ if (device_may_wakeup(&client->dev)) {
+ if (!ts->suspending)
+ pm_stay_awake(&client->dev);
+ else
+ pm_wakeup_event(&client->dev, 500);
+ }
+
+ mutex_lock(&input->mutex);
+
+ switch (ts->notification) {
+ case NOTIFICATION_BOOTCOMPLETE:
+ zforce_boot(ts);
+ break;
+ default:
+ dev_err(&client->dev,
+ "unknown notification: %#x\n", ts->notification);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ if (!ts->suspending && device_may_wakeup(&client->dev))
+ pm_relax(&client->dev);
+}
+
static int zforce_input_open(struct input_dev *dev)
{
struct zforce_ts *ts = input_get_drvdata(dev);
+ int ret;
+
+ ret = zforce_start(ts);
+ if (ret)
+ return ret;
- return zforce_start(ts);
+ ts->state = ZF_STATE_DEV_OPENED;
+
+ return 0;
}
static void zforce_input_close(struct input_dev *dev)
@@ -613,6 +709,8 @@ static void zforce_input_close(struct input_dev *dev)
if (ret)
dev_warn(&client->dev, "stopping zforce failed\n");
+ ts->state = ZF_STATE_PROBE_COMPLETE;
+
return;
}
@@ -875,6 +973,7 @@ static int zforce_probe(struct i2c_client *client,
input_set_drvdata(ts->input, ts);
init_completion(&ts->command_done);
+ INIT_WORK(&ts->ts_workq, zforce_notification_queue);
/*
* The zforce pulls the interrupt low when it has data ready.
@@ -894,33 +993,11 @@ static int zforce_probe(struct i2c_client *client,
i2c_set_clientdata(client, ts);
+ ts->state = ZF_STATE_UNINITIALZED;
+
/* let the controller boot */
zforce_reset_deassert(ts);
- ts->command_waiting = NOTIFICATION_BOOTCOMPLETE;
- if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
- dev_warn(&client->dev, "bootcomplete timed out\n");
-
- /* need to start device to get version information */
- ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
- if (ret) {
- dev_err(&client->dev, "unable to initialize, %d\n", ret);
- return ret;
- }
-
- /* this gets the firmware version among other information */
- ret = zforce_command_wait(ts, COMMAND_STATUS);
- if (ret < 0) {
- dev_err(&client->dev, "couldn't get status, %d\n", ret);
- zforce_stop(ts);
- return ret;
- }
-
- /* stop device and put it into sleep until it is opened */
- ret = zforce_stop(ts);
- if (ret < 0)
- return ret;
-
device_set_wakeup_capable(&client->dev, true);
ret = input_register_device(input_dev);