summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/hideep.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/hideep.c')
-rw-r--r--drivers/input/touchscreen/hideep.c67
1 files changed, 40 insertions, 27 deletions
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index e9547ee29756..a73369e15dda 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -17,7 +17,7 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HIDEEP_TS_NAME "HiDeep Touchscreen"
#define HIDEEP_I2C_NAME "hideep_ts"
@@ -35,6 +35,7 @@
#define HIDEEP_EVENT_ADDR 0x240
/* command list */
+#define HIDEEP_WORK_MODE 0x081e
#define HIDEEP_RESET_CMD 0x9800
/* event bit */
@@ -271,9 +272,14 @@ static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val)
#define SW_RESET_IN_PGM(clk) \
{ \
+ __be32 data = cpu_to_be32(0x01); \
hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \
hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \
- hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x01); \
+ /* \
+ * The first write may already cause a reset, use a raw \
+ * write for the second write to avoid error logging. \
+ */ \
+ hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \
}
#define SET_FLASH_PIO(ce) \
@@ -467,9 +473,9 @@ static int hideep_program_nvm(struct hideep_ts *ts,
u32 addr = 0;
int error;
- error = hideep_nvm_unlock(ts);
- if (error)
- return error;
+ error = hideep_nvm_unlock(ts);
+ if (error)
+ return error;
while (ucode_len > 0) {
xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
@@ -922,8 +928,7 @@ static ssize_t hideep_fw_version_show(struct device *dev,
ssize_t len;
mutex_lock(&ts->dev_mutex);
- len = scnprintf(buf, PAGE_SIZE, "%04x\n",
- be16_to_cpu(ts->dwz_info.release_ver));
+ len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver));
mutex_unlock(&ts->dev_mutex);
return len;
@@ -937,8 +942,7 @@ static ssize_t hideep_product_id_show(struct device *dev,
ssize_t len;
mutex_lock(&ts->dev_mutex);
- len = scnprintf(buf, PAGE_SIZE, "%04x\n",
- be16_to_cpu(ts->dwz_info.product_id));
+ len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id));
mutex_unlock(&ts->dev_mutex);
return len;
@@ -948,18 +952,30 @@ static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL);
static DEVICE_ATTR(product_id, 0664, hideep_product_id_show, NULL);
static DEVICE_ATTR(update_fw, 0664, NULL, hideep_update_fw);
-static struct attribute *hideep_ts_sysfs_entries[] = {
+static struct attribute *hideep_ts_attrs[] = {
&dev_attr_version.attr,
&dev_attr_product_id.attr,
&dev_attr_update_fw.attr,
NULL,
};
+ATTRIBUTE_GROUPS(hideep_ts);
-static const struct attribute_group hideep_ts_attr_group = {
- .attrs = hideep_ts_sysfs_entries,
-};
+static void hideep_set_work_mode(struct hideep_ts *ts)
+{
+ /*
+ * Reset touch report format to the native HiDeep 20 protocol if requested.
+ * This is necessary to make touchscreens which come up in I2C-HID mode
+ * work with this driver.
+ *
+ * Note this is a kernel internal device-property set by x86 platform code,
+ * this MUST not be used in devicetree files without first adding it to
+ * the DT bindings.
+ */
+ if (device_property_read_bool(&ts->client->dev, "hideep,force-native-protocol"))
+ regmap_write(ts->reg, HIDEEP_WORK_MODE, 0x00);
+}
-static int __maybe_unused hideep_suspend(struct device *dev)
+static int hideep_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -970,7 +986,7 @@ static int __maybe_unused hideep_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hideep_resume(struct device *dev)
+static int hideep_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -982,12 +998,14 @@ static int __maybe_unused hideep_resume(struct device *dev)
return error;
}
+ hideep_set_work_mode(ts);
+
enable_irq(client->irq);
return 0;
}
-static SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
static const struct regmap_config hideep_regmap_config = {
.reg_bits = 16,
@@ -997,8 +1015,7 @@ static const struct regmap_config hideep_regmap_config = {
.max_register = 0xffff,
};
-static int hideep_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hideep_probe(struct i2c_client *client)
{
struct hideep_ts *ts;
int error;
@@ -1059,6 +1076,8 @@ static int hideep_probe(struct i2c_client *client,
return error;
}
+ hideep_set_work_mode(ts);
+
error = hideep_init_input(ts);
if (error)
return error;
@@ -1072,18 +1091,11 @@ static int hideep_probe(struct i2c_client *client,
return error;
}
- error = devm_device_add_group(&client->dev, &hideep_ts_attr_group);
- if (error) {
- dev_err(&client->dev,
- "failed to add sysfs attributes: %d\n", error);
- return error;
- }
-
return 0;
}
static const struct i2c_device_id hideep_i2c_id[] = {
- { HIDEEP_I2C_NAME, 0 },
+ { HIDEEP_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, hideep_i2c_id);
@@ -1107,9 +1119,10 @@ MODULE_DEVICE_TABLE(of, hideep_match_table);
static struct i2c_driver hideep_driver = {
.driver = {
.name = HIDEEP_I2C_NAME,
+ .dev_groups = hideep_ts_groups,
.of_match_table = of_match_ptr(hideep_match_table),
.acpi_match_table = ACPI_PTR(hideep_acpi_id),
- .pm = &hideep_pm_ops,
+ .pm = pm_sleep_ptr(&hideep_pm_ops),
},
.id_table = hideep_i2c_id,
.probe = hideep_probe,