From: Dudley Du <dudley.dulixin@gmail.com>
To: dmitry.torokhov@gmail.com, rydberg@euromail.se
Cc: Dudley Du <dudley.dulixin@gmail.com>,
bleung@google.com, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v11 07/19] input: cyapa: add sysfs interfaces supported in the cyapa driver
Date: Wed, 19 Nov 2014 16:37:39 +0800 [thread overview]
Message-ID: <1416386271-28167-8-git-send-email-dudley.dulixin@gmail.com> (raw)
In-Reply-To: <1416386271-28167-1-git-send-email-dudley.dulixin@gmail.com>
Add device's basic control and features supported in cyapa driver through
sysfs file system interfaces. These interfaces are commonly used in
pre- and after production, for trackpad device state checking, managing
and firmware image updating.
These interfaces including mode, firmware_version and product_id interfaces
for reading firmware version and trackpad device product id values,
and including update_fw interface to command firmware image update
process. Also including baseline and calibrate interfaces for
reading and checking trackpad device's sensors states.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.c | 301 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 301 insertions(+)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 64bb067..305dffe 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -32,6 +32,8 @@
#define CYAPA_ADAPTER_FUNC_SMBUS 2
#define CYAPA_ADAPTER_FUNC_BOTH 3
+#define CYAPA_FW_NAME "cyapa.bin"
+
const char unique_str[] = "CYTRA";
/* Returns 0 on success, else negative errno on failure. */
@@ -475,6 +477,25 @@ int cyapa_detect(struct cyapa *cyapa)
return 0;
}
+static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
+{
+ if (!cyapa->opened) {
+ if (cyapa->operational && cyapa->ops->set_power_mode)
+ cyapa->ops->set_power_mode(cyapa,
+ PWR_MODE_FULL_ACTIVE, 0);
+ enable_irq(cyapa->client->irq);
+ }
+}
+
+static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
+{
+ if (!cyapa->opened) {
+ disable_irq(cyapa->client->irq);
+ if (cyapa->operational && cyapa->ops->set_power_mode)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
+ }
+}
+
/*
* Sysfs Interface.
*/
@@ -704,6 +725,273 @@ static int cyapa_start_runtime(struct cyapa *cyapa)
}
#endif /* CONFIG_PM_RUNTIME */
+static ssize_t cyapa_show_fm_ver(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int error;
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+ error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
+ cyapa->fw_min_ver);
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error;
+}
+
+static ssize_t cyapa_show_product_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int size;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+ size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
+ mutex_unlock(&cyapa->state_sync_lock);
+ return size;
+}
+
+static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name)
+{
+ struct device *dev = &cyapa->client->dev;
+ const struct firmware *fw;
+ int error;
+
+ error = request_firmware(&fw, fw_name, dev);
+ if (error) {
+ dev_err(dev, "Could not load firmware from %s: %d\n",
+ fw_name, error);
+ return error;
+ }
+
+ if (cyapa->ops->check_fw) {
+ error = cyapa->ops->check_fw(cyapa, fw);
+ if (error) {
+ dev_err(dev, "Invalid CYAPA firmware image: %s\n",
+ fw_name);
+ goto done;
+ }
+ } else {
+ dev_err(dev, "No valid device ops->check_fw handler set.\n");
+ error = -ENODEV;
+ goto done;
+ }
+
+ /*
+ * Resume the potentially suspended device because doing FW
+ * update on a device not in the FULL mode has a chance to
+ * fail.
+ */
+ pm_runtime_get_sync(dev);
+
+ if (cyapa->ops->bl_enter) {
+ error = cyapa->ops->bl_enter(cyapa);
+ if (error)
+ goto err_detect;
+ }
+
+ if (cyapa->ops->bl_activate) {
+ error = cyapa->ops->bl_activate(cyapa);
+ if (error)
+ goto err_detect;
+ }
+
+ if (cyapa->ops->bl_initiate) {
+ error = cyapa->ops->bl_initiate(cyapa, fw);
+ if (error)
+ goto err_detect;
+ }
+
+ if (cyapa->ops->update_fw) {
+ error = cyapa->ops->update_fw(cyapa, fw);
+ if (error)
+ goto err_detect;
+ }
+
+ if (cyapa->ops->bl_verify_app_integrity) {
+ error = cyapa->ops->bl_verify_app_integrity(cyapa);
+ if (error)
+ goto err_detect;
+ }
+
+err_detect:
+ pm_runtime_put_noidle(dev);
+
+done:
+ release_firmware(fw);
+ return error;
+}
+
+static ssize_t cyapa_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ char fw_name[64];
+ int error;
+
+ if (count > 64) {
+ dev_err(dev, "File name too long\n");
+ return -EINVAL;
+ }
+
+ memcpy(fw_name, buf, count);
+ if (fw_name[count - 1] == '\n')
+ fw_name[count - 1] = '\0';
+ else
+ fw_name[count] = '\0';
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ /* Require IRQ support for firmware update commands. */
+ cyapa_enable_irq_for_cmd(cyapa);
+
+ if (cyapa->operational)
+ cyapa->operational = false;
+
+ error = cyapa_firmware(cyapa, fw_name);
+ if (error)
+ dev_err(dev, "firmware update failed: %d\n", error);
+ else
+ dev_dbg(dev, "firmware update successfully done.\n");
+
+ cyapa_disable_irq_for_cmd(cyapa);
+
+ /*
+ * Redetect trackpad device states because firmware update process
+ * will reset trackpad device into bootloader mode.
+ */
+ cyapa_detect(cyapa);
+
+ mutex_unlock(&cyapa->state_sync_lock);
+
+ return error ? error : count;
+}
+
+static ssize_t cyapa_calibrate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ /* Require IRQ support for force calibrate commands. */
+ cyapa_enable_irq_for_cmd(cyapa);
+
+ if (!cyapa->ops->calibrate_store) {
+ dev_err(dev, "Calibrate operation not supported.\n");
+ error = -ENOTSUPP;
+ } else {
+ error = cyapa->ops->calibrate_store(dev, attr, buf, count);
+ }
+
+ cyapa_disable_irq_for_cmd(cyapa);
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error < 0 ? error : count;
+}
+
+static ssize_t cyapa_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ ssize_t error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ /* Require IRQ support for read baseline commands. */
+ cyapa_enable_irq_for_cmd(cyapa);
+
+ if (!cyapa->ops->show_baseline) {
+ dev_err(dev, "Calibrate operation not supported.\n");
+ error = -ENOTSUPP;
+ } else {
+ error = cyapa->ops->show_baseline(dev, attr, buf);
+ }
+
+ cyapa_disable_irq_for_cmd(cyapa);
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error;
+}
+
+static char *cyapa_state_to_string(struct cyapa *cyapa)
+{
+ switch (cyapa->state) {
+ case CYAPA_STATE_BL_BUSY:
+ return "bootloader busy";
+ case CYAPA_STATE_BL_IDLE:
+ return "bootloader idle";
+ case CYAPA_STATE_BL_ACTIVE:
+ return "bootloader active";
+ case CYAPA_STATE_GEN5_BL:
+ return "bootloader";
+ case CYAPA_STATE_OP:
+ case CYAPA_STATE_GEN5_APP:
+ return "operational";
+ default:
+ return "invalid mode";
+ }
+}
+
+static ssize_t cyapa_show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int size;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
+ cyapa->gen, cyapa_state_to_string(cyapa));
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return size;
+}
+
+static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store);
+static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL);
+static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store);
+static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL);
+
+static struct attribute *cyapa_sysfs_entries[] = {
+ &dev_attr_firmware_version.attr,
+ &dev_attr_product_id.attr,
+ &dev_attr_update_fw.attr,
+ &dev_attr_baseline.attr,
+ &dev_attr_calibrate.attr,
+ &dev_attr_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group cyapa_sysfs_group = {
+ .attrs = cyapa_sysfs_entries,
+};
+
+static void cyapa_remove_sysfs_group(void *data)
+{
+ struct cyapa *cyapa = data;
+
+ sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
+}
+
/*
* Returns:
* 0 Driver and device initialization successfully done.
@@ -775,6 +1063,19 @@ static int cyapa_probe(struct i2c_client *client,
return error;
}
+ error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group);
+ if (error) {
+ dev_err(dev, "failed to create sysfs entries: %d\n", error);
+ return error;
+ }
+
+ error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
+ if (error) {
+ cyapa_remove_sysfs_group(cyapa);
+ dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
+ return error;
+ }
+
#ifdef CONFIG_PM_SLEEP
if (device_can_wakeup(dev)) {
error = sysfs_merge_group(&client->dev.kobj,
--
1.9.1
next prev parent reply other threads:[~2014-11-19 8:40 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-19 8:37 [PATCH v11 00/19] input: cyapa: instruction of cyapa patches Dudley Du
2014-11-19 8:37 ` [PATCH v11 01/19] input: cyapa: modify code to following kernel code style Dudley Du
2014-11-19 8:37 ` [PATCH v11 02/19] input: cyapa: add device resource management infrastructure support Dudley Du
2014-11-19 8:37 ` [PATCH v11 03/19] input: cyapa: re-design driver to support multi-trackpad in one driver Dudley Du
2014-11-19 8:37 ` [PATCH v11 04/19] input: cyapa: add gen5 trackpad device basic functions support Dudley Du
2014-11-19 8:37 ` [PATCH v11 05/19] input: cyapa: add power management interfaces supported for the device Dudley Du
2014-11-19 8:37 ` [PATCH v11 06/19] input: cyapa: add runtime " Dudley Du
2014-11-19 8:37 ` Dudley Du [this message]
2014-11-19 8:37 ` [PATCH v11 08/19] input: cyapa: add gen3 trackpad device firmware update function support Dudley Du
2014-11-19 8:37 ` [PATCH v11 09/19] input: cyapa: add gen3 trackpad device read baseline " Dudley Du
2014-11-19 8:37 ` [PATCH v11 10/19] input: cyapa: add gen3 trackpad device force re-calibrate " Dudley Du
2014-11-19 8:37 ` [PATCH v11 11/19] input: cyapa: add gen5 trackpad device firmware update " Dudley Du
2014-11-19 8:37 ` [PATCH v11 12/19] input: cyapa: add gen5 trackpad device read baseline " Dudley Du
2014-11-19 8:37 ` [PATCH v11 13/19] input: cyapa: add gen5 trackpad device force re-calibrate " Dudley Du
2014-11-19 8:37 ` [PATCH v11 14/19] input: cyapa: add read firmware image debugfs interface support Dudley Du
2014-11-19 8:37 ` [PATCH v11 15/19] input: cyapa: add gen3 trackpad device read firmware image function support Dudley Du
2014-11-19 8:37 ` [PATCH v11 16/19] input: cyapa: add gen5 " Dudley Du
2014-11-19 8:37 ` [PATCH v11 17/19] input: cyapa: add read sensors raw data debugfs interface support Dudley Du
2014-11-19 8:37 ` [PATCH v11 18/19] input: cyapa: add gen5 trackpad device read raw data function support Dudley Du
2014-11-19 8:37 ` [PATCH v11 19/19] input: cyapa: add acpi device id supported Dudley Du
2014-11-21 8:56 ` [PATCH v11 00/19] input: cyapa: instruction of cyapa patches Jeremiah Mahler
2014-11-24 3:06 ` Dudley Du
2014-11-24 8:50 ` Jeremiah Mahler
2014-11-25 10:07 ` [BUG] [PATCH] next: cyapa: fix inop touchpad after resume on Acer C720 Jeremiah Mahler
2014-11-26 6:01 ` Dudley Du
2014-11-26 19:59 ` Jeremiah Mahler
2014-11-26 6:16 ` Dudley Du
2014-11-26 20:02 ` Jeremiah Mahler
2014-11-27 5:45 ` Dudley Du
2014-11-27 9:05 ` Jeremiah Mahler
2014-11-27 18:16 ` Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1416386271-28167-8-git-send-email-dudley.dulixin@gmail.com \
--to=dudley.dulixin@gmail.com \
--cc=bleung@google.com \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rydberg@euromail.se \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).