diff -Naur a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa-common.dtsi b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa-common.dtsi
--- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa-common.dtsi	2026-07-09 10:02:23.823845708 +0200
+++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa-common.dtsi	2026-07-09 10:02:23.825845760 +0200
@@ -495,7 +513,14 @@
 			regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
 		};
 
-		/* L2 and L4 are unused. */
+		/* L2 is unused. */
+
+		vreg_l4c_1p8: ldo4 {
+			regulator-name = "vreg_l4c_1p8";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1980000>;
+			regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+		};
 
 		vreg_l3c_1p2: ldo3 {
 			regulator-name = "vreg_l3c_1p2";
@@ -671,6 +678,27 @@
 	};
 };
 
+&i2c2 {
+	status = "okay";
+
+	nanosic_803: nanosic803@4c {
+		compatible = "nanosic,803";
+		status = "okay";
+		reg = <0x4c>;
+		reset-gpios = <&tlmm 141 0x00>;
+		sleep-gpios = <&tlmm 155 0x00>;
+		vdd-gpios = <&tlmm 127 0x00>;
+		irq-gpios = <&tlmm 100 0x6001>;
+		touchpad-resolution-x = <2879>;
+		touchpad-resolution-y = <1799>;
+		tablet-mode-gpios = <&tlmm 121 GPIO_ACTIVE_LOW>;
+		pinctrl-0 = <&hall_sensor_fold_default>;
+		pinctrl-names = "default";
+		vdd_1v8-supply = <&vreg_l4c_1p8>;
+		vdd_3v3-supply = <&vreg_l10c_3p3>;
+	};
+};
+
 &i2c3 {
 	clock-frequency = <400000>;
 	status = "okay";
diff -Naur a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig	2026-07-09 10:02:23.811845393 +0200
+++ b/drivers/input/keyboard/Kconfig	2026-07-09 10:02:23.817826227 +0200
@@ -797,4 +797,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called cypress-sf.
 
+config KEYBOARD_XIAOMI_NANOSIC803
+	tristate "Xiaomi nanosic 803 keyboard/touchpad support"
+	depends on I2C
+	help
+	  Say Y here if you want to enable support for Xiaomi nanosic 803 keyboard/touchpad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nanosic_803.
 endif
diff -Naur a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- a/drivers/input/keyboard/Makefile	2026-07-09 10:02:23.817845550 +0200
+++ b/drivers/input/keyboard/Makefile	2026-07-09 10:02:23.820813491 +0200
@@ -70,3 +70,4 @@
 obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY)	+= tm2-touchkey.o
 obj-$(CONFIG_KEYBOARD_TWL4030)		+= twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
+obj-$(CONFIG_KEYBOARD_XIAOMI_NANOSIC803)+= nanosic_803.o
diff -Naur a/drivers/input/keyboard/nanosic_803.c b/drivers/input/keyboard/nanosic_803.c
--- a/drivers/input/keyboard/nanosic_803.c	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/input/keyboard/nanosic_803.c	2026-07-09 10:02:23.822108712 +0200
@@ -0,0 +1,911 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Nanosic 803 keyboard controller driver
+ *
+ *  Copyright (C) 2024 Luka Panio <lukapanio@gmail.com>
+ *
+ *  Based on nano_driver by:
+ *  Bin yuan <bin.yuan@nanosic.com>
+ *  Copyright (C) 2010, Nanosic, Inc
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+
+#define I2C_DATA_LENGTH_READ (68)
+#define I2C_DATA_LENGTH_WRITE (66)
+
+#define TOUCH_TIMEOUT_MS 75
+#define INT_ADDR_MAX_BYTES 4
+
+#define NANOSIC_CLICK_BYTE_OFFSET 4
+
+static const unsigned int hid_to_linux_keycode[] = {
+	[0x04] = KEY_A,
+	[0x05] = KEY_B,
+	[0x06] = KEY_C,
+	[0x07] = KEY_D,
+	[0x08] = KEY_E,
+	[0x09] = KEY_F,
+	[0x0A] = KEY_G,
+	[0x0B] = KEY_H,
+	[0x0C] = KEY_I,
+	[0x0D] = KEY_J,
+	[0x0E] = KEY_K,
+	[0x0F] = KEY_L,
+	[0x10] = KEY_M,
+	[0x11] = KEY_N,
+	[0x12] = KEY_O,
+	[0x13] = KEY_P,
+	[0x14] = KEY_Q,
+	[0x15] = KEY_R,
+	[0x16] = KEY_S,
+	[0x17] = KEY_T,
+	[0x18] = KEY_U,
+	[0x19] = KEY_V,
+	[0x1A] = KEY_W,
+	[0x1B] = KEY_X,
+	[0x1C] = KEY_Y,
+	[0x1D] = KEY_Z,
+	[0x1E] = KEY_1,
+	[0x1F] = KEY_2,
+	[0x20] = KEY_3,
+	[0x21] = KEY_4,
+	[0x22] = KEY_5,
+	[0x23] = KEY_6,
+	[0x24] = KEY_7,
+	[0x25] = KEY_8,
+	[0x26] = KEY_9,
+	[0x27] = KEY_0,
+	[0x28] = KEY_ENTER,
+	[0x29] = KEY_ESC,
+	[0x2A] = KEY_BACKSPACE,
+	[0x2B] = KEY_TAB,
+	[0x2C] = KEY_SPACE,
+	[0x2D] = KEY_MINUS,
+	[0x2E] = KEY_EQUAL,
+	[0x2F] = KEY_LEFTBRACE,
+	[0x30] = KEY_RIGHTBRACE,
+	[0x31] = KEY_BACKSLASH,
+	[0x32] = KEY_GRAVE,
+	[0x33] = KEY_SEMICOLON,
+	[0x34] = KEY_APOSTROPHE,
+	[0x35] = KEY_GRAVE,
+	[0x36] = KEY_COMMA,
+	[0x37] = KEY_DOT,
+	[0x38] = KEY_SLASH,
+	[0x39] = KEY_CAPSLOCK,
+	[0x4f] = KEY_RIGHT,
+	[0x50] = KEY_LEFT,
+	[0x51] = KEY_DOWN,
+	[0x52] = KEY_UP,
+	[0x6f] = KEY_BRIGHTNESSUP,
+	[0x70] = KEY_BRIGHTNESSDOWN,
+	[0xb5] = KEY_NEXTSONG,
+	[0xb6] = KEY_PREVIOUSSONG,
+	[0xcd] = KEY_PLAYPAUSE,
+	[0xe2] = KEY_MUTE,
+	[0xe9] = KEY_VOLUMEUP,
+	[0xea] = KEY_VOLUMEDOWN,
+};
+
+static const uint16_t hid_modifier_to_linux_keycode[8] = {
+    KEY_LEFTCTRL,
+    KEY_LEFTSHIFT,
+    KEY_LEFTALT,
+    KEY_LEFTMETA,
+    KEY_RIGHTCTRL,
+    KEY_RIGHTSHIFT,
+    KEY_RIGHTALT,
+    KEY_RIGHTMETA
+};
+
+static const struct regmap_config nanosic_803_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+struct nanosic_803_priv {
+	struct device *dev;
+	struct i2c_client *client;
+	struct input_dev *keyboard_input_dev;
+	struct input_dev *touchpad_input_dev;
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *sleep_gpio;
+	struct gpio_desc *vdd_gpio;
+	struct gpio_desc *irq_gpio;
+	struct gpio_desc *tablet_mode_gpio;
+	struct regulator *vdd_1v8;
+	struct regulator *vdd_3v3;
+	struct workqueue_struct	*wq;
+	struct work_struct led_work;
+	struct timer_list finger_timer;
+	struct mutex read_mutex;
+	unsigned int irq_number;
+	int tablet_mode_irq;
+	char last_pressed_key[5];
+	char last_modifier_state;
+	char last_fn_key;
+	int slot_mapping[3];
+	bool finger_down;
+	bool is_keyboard_connected;
+	bool is_touchpad_connected;
+	struct input_dev *tablet_mode_input_dev;
+	bool caps_led_on;
+	unsigned long last_touch_time;
+	int last_x, last_y;
+};
+
+static void nanosic_803_wakeup(struct nanosic_803_priv *nanosic_dev)
+{
+	int level = 1;
+	int retry = 3;
+	level = gpiod_get_value(nanosic_dev->irq_gpio);
+
+	if (level <= 0) {
+		mdelay(25);
+		while (retry--) {
+			// Try three times
+			if (gpiod_get_value(nanosic_dev->irq_gpio)) {
+				break;
+			}
+			// Reset wn8030
+			if (retry == 0) {
+				gpiod_set_value(nanosic_dev->reset_gpio, 0);
+				mdelay(100);
+				gpiod_set_value(nanosic_dev->reset_gpio, 1);
+
+				// Delay 500ms for iic ready
+				mdelay(500);
+			}
+			// IRQ low level duration is 1ms
+			mdelay(1);
+		}
+	}
+}
+
+static int nanosic_803_read_version(struct nanosic_803_priv *nanosic_dev)
+{
+	char rsp[I2C_DATA_LENGTH_READ] = {0};
+	char cmd[I2C_DATA_LENGTH_WRITE] = {
+		0x32, 0x00, 0x4F, 0x30, 0x80,
+		0x18, 0x01, 0x00, 0x18
+	};
+	char hex_dump[3 * I2C_DATA_LENGTH_READ + 1] = {0};
+	u8 retry = 0;
+	int ret = -1;
+
+	while (retry++ < 30) {
+		ret = regmap_raw_write(nanosic_dev->regmap, 0, cmd, sizeof(cmd));
+		if (ret < 0) {
+			dev_err(nanosic_dev->dev, "regmap write cmd failed time %d\n", retry);
+			msleep(100);
+			continue;
+		}
+		msleep(2);
+
+		ret = regmap_raw_read(nanosic_dev->regmap, 0, rsp, sizeof(rsp));
+		if (ret == 0) {
+			for (int i = 0; i < sizeof(rsp); i++) {
+				snprintf(&hex_dump[i * 3], 4, "%02x ", rsp[i]);
+			}
+			dev_err(nanosic_dev->dev, "nanosic chip version: %s\n", hex_dump);
+			dev_err(nanosic_dev->dev, "Version read OK\n");
+			break;
+		}
+		msleep(2);
+	}
+
+	return ret;
+}
+
+static int nanosic_i2c_read(struct nanosic_803_priv *nanosic_dev, void *buf, size_t len)
+{
+	struct i2c_adapter *adap;
+	unsigned char addr[INT_ADDR_MAX_BYTES];
+	struct i2c_msg msg[2];
+	int ret;
+
+	addr[0] = nanosic_dev->client->addr;
+
+	adap = i2c_get_adapter(nanosic_dev->client->adapter->nr);
+
+	msg[0].len = 1;
+	msg[0].addr = nanosic_dev->client->addr;
+	msg[0].flags = 0;
+	msg[0].buf = addr;
+
+	msg[1].addr = nanosic_dev->client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = buf;
+
+	ret = i2c_transfer(adap, msg, 2);
+	if (ret < 0) {
+		dev_err(nanosic_dev->dev, "i2c_transfer read error\n");
+		len = -1;
+	}
+
+	//mutex_unlock(&i2c_client->read_mutex);
+
+	return len;
+}
+
+static int nanosic_i2c_write(struct nanosic_803_priv *nanosic_dev, void *buf, size_t len)
+{
+	struct i2c_msg msg;
+	struct i2c_adapter *adap;
+	unsigned char tmp_buf[128] = { 0 };
+	int ret;
+
+	adap = i2c_get_adapter(nanosic_dev->client->adapter->nr);
+
+	tmp_buf[0] = nanosic_dev->client->addr;
+	memcpy(tmp_buf + 1, buf, len);
+
+	msg.addr = nanosic_dev->client->addr;
+	msg.flags = 0;
+	msg.len = len + 1;
+	msg.buf = tmp_buf;
+
+	ret = i2c_transfer(adap, &msg, 1);
+	if (ret < 0) {
+		printk("i2c_transfer write error\n");
+		len = -1;
+	}
+
+	return len;
+}
+
+static void nanosic_sync_caps_led(struct work_struct *work)
+{
+	struct nanosic_803_priv *nanosic_dev = container_of(work, struct nanosic_803_priv, led_work);
+	int i = 0, ret = 0;
+
+	dev_dbg(nanosic_dev->dev, "setting caps led: %d\n", nanosic_dev->caps_led_on);
+	char cmd[I2C_DATA_LENGTH_WRITE] = {
+		0x32, 0x00, 0x4E, 0x31,
+		0x80, 0x38, 0x26, 0x01, nanosic_dev->caps_led_on
+	};
+
+	for (i = 2; i < 9; i++) {
+		cmd[9] += cmd[i];
+	}
+
+	/* cal sum */
+	ret = nanosic_i2c_write(nanosic_dev, cmd, sizeof(cmd));
+	if (ret < 0) {
+		dev_err(nanosic_dev->dev, "could not set caps led");
+	}
+}
+
+static int nanosic_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct nanosic_803_priv *nanosic_dev = input_get_drvdata(dev);
+	bool prev_value = nanosic_dev->caps_led_on;
+
+	dev_dbg(nanosic_dev->dev, "nanosic event type: %d, code: %u, value: %d\n", type, code, value);
+	if (!nanosic_dev)
+		return -EINVAL;
+
+	if (type == EV_LED) {
+		switch (code) {
+			case LED_CAPSL:
+				nanosic_dev->caps_led_on = value;
+				if (value != prev_value)
+					queue_work(nanosic_dev->wq, &nanosic_dev->led_work);
+				break;
+			default:
+				break;
+		}
+	}
+	return 0;
+}
+
+static int nanosic_register_keyboard(struct nanosic_803_priv *nanosic_dev)
+{
+	struct input_dev *keyboard_input_dev;
+	int ret;
+
+	// Allocating keyboard device
+	keyboard_input_dev = devm_input_allocate_device(nanosic_dev->dev);
+	if (!keyboard_input_dev) {
+		ret = -ENOMEM;
+		dev_err(nanosic_dev->dev, "could not allocate keyboard input device: %d\n", ret);
+		return ret;
+	}
+	keyboard_input_dev->name = "Nanosic 803 keyboard";
+	keyboard_input_dev->phys = "input/keyboard";
+	keyboard_input_dev->id.bustype = BUS_I2C;
+	keyboard_input_dev->id.vendor = 0x1234;
+	keyboard_input_dev->id.product = 0x5678;
+	keyboard_input_dev->id.version = 0x0100;
+
+	set_bit(EV_KEY, keyboard_input_dev->evbit);
+	set_bit(EV_REP, keyboard_input_dev->evbit);
+
+	keyboard_input_dev->evbit[0] |= BIT_MASK(EV_LED) |  BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL);
+	keyboard_input_dev->event = nanosic_event;
+
+	input_set_drvdata(keyboard_input_dev, nanosic_dev);
+
+	for (int i = 0; i < KEY_MAX; i++)
+		set_bit(i, keyboard_input_dev->keybit);
+
+	// Registering keyboard device
+	nanosic_dev->keyboard_input_dev = keyboard_input_dev;
+	ret = input_register_device(nanosic_dev->keyboard_input_dev);
+	if (ret)
+		dev_err(nanosic_dev->dev, "failed to register input device: %d\n", ret);
+	return ret;
+}
+
+static int nanosic_register_touchpad(struct nanosic_803_priv *nanosic_dev)
+{
+	struct input_dev *touchpad_input_dev;
+	int ret;
+	unsigned int touchpad_resolution_x, touchpad_resolution_y;
+
+	// Get touchpad resolution
+	if (of_property_read_u32(nanosic_dev->dev->of_node, "touchpad-resolution-x", &touchpad_resolution_x)) {
+		dev_err(nanosic_dev->dev, "Failed to read touchpad-resolution-x from DT\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(nanosic_dev->dev->of_node, "touchpad-resolution-y", &touchpad_resolution_y)) {
+		dev_err(nanosic_dev->dev, "Failed to read touchpad-resolution-y from DT\n");
+		return -EINVAL;
+	}
+
+	// Allocating touchpad device
+	touchpad_input_dev = devm_input_allocate_device(nanosic_dev->dev);
+	if (!touchpad_input_dev) {
+		pr_err("Failed to allocate touchpad input device\n");
+		return -ENOMEM;
+	}
+
+	touchpad_input_dev->name = "Nanosic 803 touchpad";
+	touchpad_input_dev->phys = "input/touchpad";
+	touchpad_input_dev->id.bustype = BUS_I2C;
+	touchpad_input_dev->id.vendor = 0x1234;
+	touchpad_input_dev->id.product = 0x5678;
+	touchpad_input_dev->id.version = 0x0001;
+
+	ret = input_mt_init_slots(touchpad_input_dev, 3, INPUT_MT_POINTER);
+	if (ret) {
+		dev_err(nanosic_dev->dev, "Failed to initialize MT slots: %d\n", ret);
+		return ret;
+	}
+
+	set_bit(INPUT_PROP_POINTER, touchpad_input_dev->propbit);
+	set_bit(EV_ABS, touchpad_input_dev->evbit);
+	input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_X, 0, touchpad_resolution_x, 0, 0);
+	input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_Y, 0, touchpad_resolution_y, 0, 0);
+	input_set_abs_params(touchpad_input_dev, ABS_MT_TRACKING_ID, 0, 3 - 1, 0, 0);
+
+	set_bit(EV_KEY, touchpad_input_dev->evbit);
+	set_bit(BTN_LEFT, touchpad_input_dev->keybit);
+	set_bit(BTN_RIGHT, touchpad_input_dev->keybit);
+
+	input_set_drvdata(touchpad_input_dev, nanosic_dev);
+
+	// Registering touchpad device
+	nanosic_dev->touchpad_input_dev = touchpad_input_dev;
+	ret = input_register_device(nanosic_dev->touchpad_input_dev);
+	if (ret)
+		dev_err(nanosic_dev->dev, "failed to register input device: %d\n", ret);
+	return ret;
+}
+
+static void nanosic_update_tablet_mode(struct nanosic_803_priv *nanosic_dev)
+{
+	bool tablet_mode;
+
+	tablet_mode = !nanosic_dev->is_keyboard_connected ||
+		gpiod_get_value_cansleep(nanosic_dev->tablet_mode_gpio);
+	input_report_switch(nanosic_dev->tablet_mode_input_dev,
+			    SW_TABLET_MODE, tablet_mode);
+	input_sync(nanosic_dev->tablet_mode_input_dev);
+}
+
+static irqreturn_t nanosic_tablet_mode_irq_thread(int irq, void *dev_id)
+{
+	struct nanosic_803_priv *nanosic_dev = dev_id;
+
+	nanosic_update_tablet_mode(nanosic_dev);
+	return IRQ_HANDLED;
+}
+
+static int nanosic_register_tablet_mode(struct nanosic_803_priv *nanosic_dev)
+{
+	struct input_dev *tablet_mode_input_dev;
+	int ret;
+
+	tablet_mode_input_dev = devm_input_allocate_device(nanosic_dev->dev);
+	if (!tablet_mode_input_dev)
+		return -ENOMEM;
+
+	tablet_mode_input_dev->name = "Nanosic 803 tablet mode";
+	tablet_mode_input_dev->phys = "input/tablet-mode";
+	tablet_mode_input_dev->id.bustype = BUS_I2C;
+	input_set_capability(tablet_mode_input_dev, EV_SW, SW_TABLET_MODE);
+
+	nanosic_dev->tablet_mode_input_dev = tablet_mode_input_dev;
+	ret = input_register_device(tablet_mode_input_dev);
+	if (ret)
+		return ret;
+
+	nanosic_update_tablet_mode(nanosic_dev);
+	return 0;
+}
+
+
+static void nanosic_handle_hall(struct nanosic_803_priv *nanosic_dev, char *buf)
+{
+	if (buf[5] == 0x38 && buf[6] == 0x80 && buf[7] == 0xa2) {
+		bool was_keyboard_connected = nanosic_dev->is_keyboard_connected;
+		bool was_touchpad_connected = nanosic_dev->is_touchpad_connected;
+
+		if (buf[12] == 0x23) {
+			dev_dbg(nanosic_dev->dev, "registering input devices\n");
+			nanosic_dev->is_keyboard_connected = true;
+			nanosic_dev->is_touchpad_connected = true;
+			if (nanosic_dev->is_keyboard_connected != was_keyboard_connected)
+				nanosic_register_keyboard(nanosic_dev);
+			if (nanosic_dev->is_touchpad_connected != was_touchpad_connected)
+				nanosic_register_touchpad(nanosic_dev);
+			nanosic_update_tablet_mode(nanosic_dev);
+		} else if (buf[12] == 0x0) {
+			dev_dbg(nanosic_dev->dev, "unregistering input devices\n");
+			nanosic_dev->is_keyboard_connected = false;
+			nanosic_dev->is_touchpad_connected = false;
+			if (nanosic_dev->is_keyboard_connected != was_keyboard_connected)
+				input_unregister_device(nanosic_dev->keyboard_input_dev);
+			if (nanosic_dev->is_touchpad_connected != was_touchpad_connected)
+				input_unregister_device(nanosic_dev->touchpad_input_dev);
+			nanosic_update_tablet_mode(nanosic_dev);
+		}
+	}
+}
+
+static void handle_modifiers(struct nanosic_803_priv *nanosic_dev, char modifiers)
+{
+	char last_modifiers = nanosic_dev->last_modifier_state;
+
+	for (int i = 0; i < 8; i++) {
+		uint8_t current_bit = (modifiers >> i) & 1;
+		uint8_t last_bit = (last_modifiers >> i) & 1;
+
+		if (current_bit && !last_bit) {
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_modifier_to_linux_keycode[i], 1);
+			dev_dbg(nanosic_dev->dev, "Modifier pressed: %d\n", hid_modifier_to_linux_keycode[i]);
+		} else if (!current_bit && last_bit) {
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_modifier_to_linux_keycode[i], 0);
+			dev_dbg(nanosic_dev->dev, "Modifier released: %d\n", hid_modifier_to_linux_keycode[i]);
+		}
+	}
+
+	input_sync(nanosic_dev->keyboard_input_dev);
+
+	nanosic_dev->last_modifier_state = modifiers;
+}
+
+static void nanosic_handle_keyboard(struct nanosic_803_priv *nanosic_dev, char *buf)
+{
+	int i, j;
+	int found;
+
+	handle_modifiers(nanosic_dev, buf[4]);
+
+	for (i = 0; i < 5 && buf[6+i] != 0x00; ++i) {
+		found = 0;
+		for (j = 0; j < 5 && nanosic_dev->last_pressed_key[j] != 0x00; ++j) {
+			if (buf[6+i] == nanosic_dev->last_pressed_key[j]) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			dev_dbg(nanosic_dev->dev, "Key pressed: 0x%02X\n", buf[6+i]);
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_to_linux_keycode[(unsigned char)buf[6+i]], 1);
+			input_sync(nanosic_dev->keyboard_input_dev);
+		}
+	}
+
+	for (i = 0; i < 5 && nanosic_dev->last_pressed_key[i] != 0x00; ++i) {
+		found = 0;
+		for (j = 0; j < 5 && buf[6+j] != 0x00; ++j) {
+			if (nanosic_dev->last_pressed_key[i] == buf[6+j]) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			dev_dbg(nanosic_dev->dev, "Key released: 0x%02X\n", nanosic_dev->last_pressed_key[i]);
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_to_linux_keycode[(unsigned char)nanosic_dev->last_pressed_key[i]], 0);
+			input_sync(nanosic_dev->keyboard_input_dev);
+		}
+	}
+	memcpy(nanosic_dev->last_pressed_key, &buf[6], sizeof(nanosic_dev->last_pressed_key));
+}
+
+static void nanosic_handle_fn_key(struct nanosic_803_priv *nanosic_dev, char *buf)
+{
+	if (buf[4] != nanosic_dev->last_fn_key) {
+		if (nanosic_dev->last_fn_key != 0x00) {
+			dev_dbg(nanosic_dev->dev, "Key released: 0x%02X\n", nanosic_dev->last_fn_key);
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_to_linux_keycode[(unsigned char)nanosic_dev->last_fn_key], 0);
+			input_sync(nanosic_dev->keyboard_input_dev);
+		}
+		if (buf[4] != 0x00) {
+			dev_dbg(nanosic_dev->dev, "Key pressed: 0x%02X\n", buf[4]);
+			input_report_key(nanosic_dev->keyboard_input_dev, hid_to_linux_keycode[(unsigned char)buf[4]], 1);
+			input_sync(nanosic_dev->keyboard_input_dev);
+		}
+		nanosic_dev->last_fn_key = buf[4];
+	}
+}
+
+static void nanosic_touch_timer_callback(struct timer_list *t)
+{
+	struct nanosic_803_priv *nanosic_dev = timer_container_of(nanosic_dev, t, finger_timer);
+
+	if (nanosic_dev->finger_down) {
+		for (int i = 0; i<3; i++) {
+			input_mt_slot(nanosic_dev->touchpad_input_dev, nanosic_dev->slot_mapping[i]);
+			input_mt_report_slot_state(nanosic_dev->touchpad_input_dev, MT_TOOL_FINGER, 0);
+			input_report_abs(nanosic_dev->touchpad_input_dev, ABS_MT_TRACKING_ID, -1);
+			input_sync(nanosic_dev->touchpad_input_dev);
+		}
+        nanosic_dev->finger_down = false;
+    }
+}
+
+static void nanosic_handle_touchpad_mt(struct nanosic_803_priv *nanosic_dev, char *buf)
+{
+	int finger_id, x, y;
+
+	for (int i = 0; i < 3; i++) {
+		int offset = 6 + (i * 6);
+		finger_id = buf[offset];
+		x = (uint16_t)(buf[offset + 1] | (buf[offset + 2] << 8));
+		y = (uint16_t)(buf[offset + 3] | (buf[offset + 4] << 8));
+
+		if (finger_id == 0 && x == 0 && y == 0) {
+			if (nanosic_dev->slot_mapping[i] != -1) {
+				input_mt_slot(nanosic_dev->touchpad_input_dev, nanosic_dev->slot_mapping[i]);
+				input_mt_report_slot_state(nanosic_dev->touchpad_input_dev, MT_TOOL_FINGER, 0);
+				nanosic_dev->slot_mapping[i] = -1;
+			}
+			continue;
+		}
+
+		int slot = nanosic_dev->slot_mapping[i];
+		if (slot == -1) {
+			for (int j = 0; j < 3; j++) {
+				if (nanosic_dev->slot_mapping[j] == -1) {
+					slot = j;
+					nanosic_dev->slot_mapping[i] = slot;
+					break;
+				}
+			}
+			if (slot == -1) {
+				dev_err(nanosic_dev->dev, "No free slots available for finger %d\n", finger_id);
+				continue;
+			}
+		}
+
+		input_mt_slot(nanosic_dev->touchpad_input_dev, slot);
+		input_mt_report_slot_state(nanosic_dev->touchpad_input_dev, MT_TOOL_FINGER, 1);
+		input_report_abs(nanosic_dev->touchpad_input_dev, ABS_MT_POSITION_X, x);
+		input_report_abs(nanosic_dev->touchpad_input_dev, ABS_MT_POSITION_Y, y);
+	}
+
+	input_report_key(nanosic_dev->touchpad_input_dev, BTN_LEFT, (uint16_t)buf[NANOSIC_CLICK_BYTE_OFFSET]);
+	
+	input_mt_sync_frame(nanosic_dev->touchpad_input_dev);
+	input_sync(nanosic_dev->touchpad_input_dev);
+
+	nanosic_dev->finger_down = true;
+	nanosic_dev->last_touch_time = jiffies;
+	mod_timer(&nanosic_dev->finger_timer, jiffies + msecs_to_jiffies(TOUCH_TIMEOUT_MS));
+}
+
+static irqreturn_t nanosic_irq_handler(int irq, void *dev_id)
+{
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t nanosic_interrupt_thread_fn(int irq, void *dev_id)
+{
+	struct nanosic_803_priv *nanosic_dev = dev_id;
+	int ret;
+	char buf[I2C_DATA_LENGTH_READ] = {0};
+	char hex_dump[3 * I2C_DATA_LENGTH_READ + 1] = {0};
+
+	usleep_range(1000, 5000);
+
+	mutex_lock(&nanosic_dev->read_mutex);
+	ret = nanosic_i2c_read(nanosic_dev, buf, sizeof(buf));
+	mutex_unlock(&nanosic_dev->read_mutex);
+	if (ret == 0) {
+		dev_err(nanosic_dev->dev, "Failed to read data on interrupt: %d\n", ret);
+		return IRQ_HANDLED;
+	}
+
+	for (int i = 0; i < ret; i++) {
+		snprintf(&hex_dump[i * 3], 4, "%02x ", buf[i]);
+	}
+	dev_dbg(nanosic_dev->dev, "nanosic message: %s\n", hex_dump);
+
+	if (buf[0] != 0x57 || buf[2] == 0) {
+		dev_dbg(nanosic_dev->dev, "Malformed message\n");
+		/*
+		 * Our hardware might randomly return no message/random data,
+		 * so assume we handled IRQ correctly
+		 */
+		return IRQ_HANDLED;
+	}
+
+	switch (buf[3]) {
+		case 0x05:
+			// Handle keyboard event
+			nanosic_handle_keyboard(nanosic_dev, buf);
+			break;
+		case 0x06:
+			// Handle function keys
+			nanosic_handle_fn_key(nanosic_dev, buf);
+			break;
+		case 0x19:
+			// Handle touchpad event
+			nanosic_handle_touchpad_mt(nanosic_dev, buf);
+			break;
+		case 0x23:
+			// Handle hall event
+			nanosic_handle_hall(nanosic_dev, buf);
+			break;
+	}
+	return IRQ_HANDLED;
+}
+
+static void nanosic_803_reset(struct nanosic_803_priv *nanosic_dev)
+{
+	gpiod_set_value(nanosic_dev->reset_gpio, 0);
+	gpiod_set_value(nanosic_dev->sleep_gpio, 0);
+	gpiod_set_value(nanosic_dev->vdd_gpio, 0);
+	msleep(100);
+	gpiod_set_value(nanosic_dev->vdd_gpio, 1);
+	msleep(2);
+	gpiod_set_value(nanosic_dev->reset_gpio, 1);
+	gpiod_set_value(nanosic_dev->sleep_gpio, 1);
+}
+
+static int nanosic_803_probe(struct i2c_client *client)
+{
+	struct nanosic_803_priv *nanosic_dev;
+	struct device *dev = &client->dev;
+	struct regmap *map;
+	unsigned int ret;
+
+	nanosic_dev = devm_kzalloc(dev, sizeof(*nanosic_dev), GFP_KERNEL);
+	if (!nanosic_dev)
+		return -ENOMEM;
+
+	nanosic_dev->dev = dev;
+	dev_set_drvdata(dev, nanosic_dev);
+
+	nanosic_dev->wq = create_singlethread_workqueue("nanosic_wq");
+	INIT_WORK(&nanosic_dev->led_work, nanosic_sync_caps_led);
+
+	// Get GPIOs
+	nanosic_dev->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(nanosic_dev->reset_gpio)) {
+		dev_err(dev, "Failed to get reset GPIO\n");
+		return PTR_ERR(nanosic_dev->reset_gpio);
+	}
+
+	nanosic_dev->sleep_gpio = devm_gpiod_get(dev, "sleep", GPIOD_OUT_HIGH);
+	if (IS_ERR(nanosic_dev->sleep_gpio)) {
+		dev_err(dev, "Failed to get sleep GPIO\n");
+		return PTR_ERR(nanosic_dev->sleep_gpio);
+	}
+
+	nanosic_dev->vdd_gpio = devm_gpiod_get(dev, "vdd", GPIOD_OUT_HIGH);
+	if (IS_ERR(nanosic_dev->vdd_gpio)) {
+		dev_err(dev, "Failed to get vdd GPIO\n");
+		return PTR_ERR(nanosic_dev->vdd_gpio);
+	}
+
+	nanosic_dev->irq_gpio = devm_gpiod_get(dev, "irq", GPIOD_IN);
+	if (IS_ERR(nanosic_dev->irq_gpio)) {
+		dev_err(dev, "Failed to get irq GPIO\n");
+		return PTR_ERR(nanosic_dev->vdd_gpio);
+	}
+
+	nanosic_dev->tablet_mode_gpio = devm_gpiod_get(dev, "tablet-mode",
+						       GPIOD_IN);
+	if (IS_ERR(nanosic_dev->tablet_mode_gpio)) {
+		dev_err(dev, "Failed to get tablet mode GPIO\n");
+		return PTR_ERR(nanosic_dev->tablet_mode_gpio);
+	}
+
+	// Get regulators
+	nanosic_dev->vdd_1v8 = devm_regulator_get(dev, "vdd_1v8");
+	if (IS_ERR(nanosic_dev->vdd_1v8)) {
+		dev_err(dev, "Failed to get 1.8V regulator\n");
+		return PTR_ERR(nanosic_dev->vdd_1v8);
+	}
+
+	nanosic_dev->vdd_3v3 = devm_regulator_get(dev, "vdd_3v3");
+	if (IS_ERR(nanosic_dev->vdd_3v3)) {
+		dev_err(dev, "Failed to get 3.3V regulator\n");
+		return PTR_ERR(nanosic_dev->vdd_3v3);
+	}
+
+	// Enable regulators
+	ret = regulator_enable(nanosic_dev->vdd_1v8);
+	if (ret) {
+		dev_err(dev, "Failed to enable 1.8V regulator\n");
+		return ret;
+	}
+
+	ret = regulator_enable(nanosic_dev->vdd_3v3);
+	if (ret) {
+		dev_err(dev, "Failed to enable 3.3V regulator\n");
+		return ret;
+	}
+
+	// Reset the chip
+	nanosic_803_reset(nanosic_dev);
+
+	// Wake up the chip
+	nanosic_803_wakeup(nanosic_dev);
+
+	// Set up regmap
+	map = devm_regmap_init_i2c(client, &nanosic_803_regmap_config);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	nanosic_dev->client = client;
+	nanosic_dev->regmap = map;
+
+	mutex_init(&nanosic_dev->read_mutex);
+
+	i2c_set_clientdata(client, nanosic_dev);
+
+	// Try to identify the chip
+	if(nanosic_803_read_version(nanosic_dev)) {
+		dev_err(dev, "Nanosic 803 not found\n");
+		return -ENODEV;
+	}
+
+	ret = nanosic_register_tablet_mode(nanosic_dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register tablet mode switch\n");
+
+	nanosic_dev->tablet_mode_irq = gpiod_to_irq(nanosic_dev->tablet_mode_gpio);
+	if (nanosic_dev->tablet_mode_irq < 0)
+		return nanosic_dev->tablet_mode_irq;
+
+	ret = devm_request_threaded_irq(dev, nanosic_dev->tablet_mode_irq, NULL,
+			nanosic_tablet_mode_irq_thread,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+			"nanosic-tablet-mode", nanosic_dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request tablet mode IRQ\n");
+
+	// Set up IRQ
+	nanosic_dev->irq_number = gpiod_to_irq(nanosic_dev->irq_gpio);
+	if (nanosic_dev->irq_number < 0) {
+		dev_err(nanosic_dev->dev, "Failed to get IRQ for GPIO %d\n", desc_to_gpio(nanosic_dev->irq_gpio));
+		return nanosic_dev->irq_number;
+	}
+
+	ret = request_threaded_irq(nanosic_dev->irq_number,
+		nanosic_irq_handler, nanosic_interrupt_thread_fn,
+		0x6001, "nanosic_irq", nanosic_dev);
+
+	if (ret) {
+		dev_err(nanosic_dev->dev, "Failed to request IRQ %d: %d\n", nanosic_dev->irq_number, ret);
+		return ret;
+	}
+
+	// Set up touchpad in-activity tracking
+	for (int i = 0; i < 3; i++) {
+		nanosic_dev->slot_mapping[i] = -1;
+	}
+
+	timer_setup(&nanosic_dev->finger_timer, nanosic_touch_timer_callback, 0);
+	nanosic_dev->finger_down = false;
+	nanosic_dev->is_keyboard_connected = false;
+	nanosic_dev->is_touchpad_connected = false;
+	return 0;
+}
+
+static int nanosic_803_suspend(struct device *dev)
+{
+	struct nanosic_803_priv *nanosic_dev = dev_get_drvdata(dev);
+	int ret;
+
+	// Actually de-init device
+	gpiod_set_value(nanosic_dev->reset_gpio, 0);
+	gpiod_set_value(nanosic_dev->sleep_gpio, 0);
+	gpiod_set_value(nanosic_dev->vdd_gpio, 0);
+
+	// Turn the regulators off
+	ret = regulator_disable(nanosic_dev->vdd_1v8);
+	if (ret) {
+		dev_err(dev, "Failed to disable 1.8V regulator\n");
+		return ret;
+	}
+
+	ret = regulator_disable(nanosic_dev->vdd_3v3);
+	if (ret) {
+		dev_err(dev, "Failed to disable 3.3V regulator\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int nanosic_803_resume(struct device *dev)
+{
+	struct nanosic_803_priv *nanosic_dev = dev_get_drvdata(dev);
+	int ret;
+
+	// Turn the regulators on
+	ret = regulator_enable(nanosic_dev->vdd_1v8);
+	if (ret) {
+		dev_err(dev, "Failed to disable 1.8V regulator\n");
+		return ret;
+	}
+
+	ret = regulator_enable(nanosic_dev->vdd_3v3);
+	if (ret) {
+		dev_err(dev, "Failed to disable 3.3V regulator\n");
+		return ret;
+	}
+
+	// Reset the chip
+	nanosic_803_reset(nanosic_dev);
+
+	// Wake up the chip
+	nanosic_803_wakeup(nanosic_dev);
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(nanosic_803_pm_ops, nanosic_803_suspend, nanosic_803_resume);
+
+static const struct of_device_id __maybe_unused nanosic_803_of_match[] = {
+	{ .compatible = "nanosic,803", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, nanosic_803_of_match);
+
+static struct i2c_driver nanosic_803_driver = {
+	.driver	= {
+		.name = "nanosic_803",
+		.of_match_table = of_match_ptr(nanosic_803_of_match),
+		.pm = pm_sleep_ptr(&nanosic_803_pm_ops),
+	},
+	.probe = nanosic_803_probe,
+};
+
+module_i2c_driver(nanosic_803_driver);
+
+MODULE_AUTHOR("Luka Panio <lukapanio@gmail.com>");
+MODULE_DESCRIPTION("Driver for nanosic 803 keyboard controller");
+MODULE_LICENSE("GPL v2");
--- a/drivers/input/keyboard/nanosic_803.c
+++ b/drivers/input/keyboard/nanosic_803.c
@@ -342,2 +342,11 @@
-	for (int i = 0; i < KEY_MAX; i++)
-		set_bit(i, keyboard_input_dev->keybit);
+	/* Only advertise the keycodes this driver can actually emit.
+	 * Setting every KEY_ and BTN_ bit makes udev's input_id builtin tag the
+	 * device as ID_INPUT_MOUSE and ID_INPUT_POINTINGSTICK in addition to
+	 * ID_INPUT_KEYBOARD, which confuses userspace, e.g. unl0kr in the
+	 * initramfs classifies the keyboard as a mouse and discards all
+	 * printable key presses. */
+	for (int i = 0; i < ARRAY_SIZE(hid_to_linux_keycode); i++)
+		if (hid_to_linux_keycode[i])
+			set_bit(hid_to_linux_keycode[i], keyboard_input_dev->keybit);
+	for (int i = 0; i < ARRAY_SIZE(hid_modifier_to_linux_keycode); i++)
+		set_bit(hid_modifier_to_linux_keycode[i], keyboard_input_dev->keybit);
