diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index b379ed7628781..06642e4ce9c63 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,8 @@
#include <asm/unaligned.h>
+#define MAX_NUM_TOP_ROW_KEYS 15
+
/**
* struct cros_ec_keyb - Structure representing EC keyboard device
*
@@ -35,6 +37,7 @@
* @row_shift: log2 or number of rows, rounded up
* @keymap_data: Matrix keymap data used to convert to keyscan values
* @ghost_filter: true to enable the matrix key-ghosting filter
+ * @has_custom_top_row_keys: true if the keyboard has custom top row keys
* @valid_keys: bitmap of existing keys for each matrix column
* @old_kb_state: bitmap of keys pressed last scan
* @dev: Device pointer
@@ -49,6 +52,7 @@ struct cros_ec_keyb {
int row_shift;
const struct matrix_keymap_data *keymap_data;
bool ghost_filter;
+ bool has_custom_top_row_keys;
uint8_t *valid_keys;
uint8_t *old_kb_state;
@@ -587,6 +591,65 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
return 0;
}
+static ssize_t function_row_physmap_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t size = 0;
+ u8 i;
+ u16 code;
+ u32 top_row_key_code[MAX_NUM_TOP_ROW_KEYS] = {0};
+ struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+
+ if (of_property_read_variable_u32_array(dev->of_node,
+ "function-row-physmap",
+ top_row_key_code,
+ 0,
+ MAX_NUM_TOP_ROW_KEYS) > 0)
+ return 0;
+
+ ckdev->has_custom_top_row_keys = true;
+
+ for (i = 0; i < MAX_NUM_TOP_ROW_KEYS; i++) {
+ if (!top_row_key_code[i])
+ break;
+ code = MATRIX_SCAN_CODE(KEY_ROW(top_row_key_code[i]),
+ KEY_COL(top_row_key_code[i]),
+ ckdev->row_shift);
+ size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ", code);
+ }
+ size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
+
+ return size;
+}
+
+static DEVICE_ATTR_RO(function_row_physmap);
+
+static struct attribute *cros_ec_keyb_attrs[] = {
+ &dev_attr_function_row_physmap.attr,
+ NULL,
+};
+
+static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+
+ if (attr == &dev_attr_function_row_physmap.attr &&
+ !ckdev->has_custom_top_row_keys)
+ return 0;
+
+ return attr->mode;
+}
+
+static const struct attribute_group cros_ec_keyb_attr_group = {
+ .is_visible = cros_ec_keyb_attr_is_visible,
+ .attrs = cros_ec_keyb_attrs,
+};
+
+
static int cros_ec_keyb_probe(struct platform_device *pdev)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);@@ -617,6 +680,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
return err;
}
+ err = sysfs_create_group(&dev->kobj, &cros_ec_keyb_attr_group);
+ if (err) {
+ dev_err(dev, "failed to create attributes. err=%d\n", err);
+ return err;
+ }
+
ckdev->notifier.notifier_call = cros_ec_keyb_work;
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
&ckdev->notifier);@@ -632,6 +701,9 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
static int cros_ec_keyb_remove(struct platform_device *pdev)
{
struct cros_ec_keyb *ckdev = dev_get_drvdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+
+ sysfs_remove_group(&dev->kobj, &cros_ec_keyb_attr_group);
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
&ckdev->notifier);--
2.26.2