From nobody Fri Oct 2 13:10:16 2026 Received: from ironport.ite.com.tw (60-251-196-230.hinet-ip.hinet.net [60.251.196.230]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DBEBE3E7BB0; Fri, 31 Jul 2026 10:02:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.251.196.230 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785492150; cv=none; b=HP1NtX+TAbpJyGrVVrZ9ZYNKzJsVjmzlW13AyeP8z3e+SjC3CaAwppThvS40HaDoaSfheEkK33WrVDf1nwFfI4csuQ6c8zFrgWNGKf5+ctIPw2e8YpmtCT3huMGAX55NiFYMeyPQWGJ7OLAf8+5H0OJ6W+FkIyourpB3hq7oyqA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785492150; c=relaxed/simple; bh=IZPAxIKUCc6svbkSeBMwX1RX+AQy58Z6xCNDoGq/Ric=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=rVP6/HzQLdQfGklk1JbvOxsW8XeBFVsP4KMqIOJv2jg3luP2gA1HZdFkN70OfYA2wgCEvZbkxcop/fhAwarlGjCip/X2jmq5rEskHeDmbSpsLHY35QKzcTdgRt3XEAUDI9He3Hp9SvAwQcbCcd8OFmmjwDQmNFM/csvit17P034= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ite.com.tw; spf=pass smtp.mailfrom=ite.com.tw; dkim=pass (2048-bit key) header.d=ite.com.tw header.i=@ite.com.tw header.b=kHSzSjfJ; arc=none smtp.client-ip=60.251.196.230 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ite.com.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ite.com.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ite.com.tw header.i=@ite.com.tw header.b="kHSzSjfJ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ite.com.tw; s=dkim; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=x/zXcSSIniSdyLwC9Nz372K+ayiRmOI5iQTyTGTNpQQ=; b=kHSzSjfJAwG5VizMmFmbb18PNgUaMmwpUsQv70lR/PgB+g4b8xKvzfi5 keTBIFVid4l9LNPOksqxpT8ZxekL8yGGGTKlBO3cDNQqq0sG4tKmclj3s fHXDW4rLB4x3Z3EHmLQKlp+oiy7zUe/V6SHxXgHA9IA5xnHexfWQVr3J+ c+cEI0Z97c5iRJyP2wqlbW9LizRLKujfBItgfCn5ymhdBJGyj2ydfIIVo UFs1bk5itmgWwNDtEc+Zsae6ivXVFblJVJAAYjRBvD1lQ++25Mxr0najR d5jNNYNn1u347vPzqyDnS44wZPQtiTJWZ5sI+jViB9Kz+ohXGm3z7Bq05 w==; X-CSE-ConnectionGUID: 5drS5tONTHWxGQNiq4lNmw== X-CSE-MsgGUID: ey/n6KIhSX2dE7DBqbA9Eg== Received: from unknown (HELO mse.ite.com.tw) ([192.168.35.30]) by ironport.ite.com.tw with ESMTP; 31 Jul 2026 18:01:52 +0800 Received: from hscmail1.internal.ite.com.tw (HSCMAIL1.internal.ite.com.tw [192.168.35.58]) by mse.ite.com.tw with ESMTP id 66VA1knq005672; Fri, 31 Jul 2026 18:01:46 +0800 (+08) (envelope-from amber.kao@ite.com.tw) Received: from [127.0.1.1] (192.168.37.107) by HSCMAIL1.internal.ite.com.tw (192.168.35.58) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.37; Fri, 31 Jul 2026 18:01:44 +0800 From: Amber Kao Date: Fri, 31 Jul 2026 18:02:03 +0800 Subject: [PATCH v6 1/2] dt-bindings: usb: Add ITE IT8851/IT8853 Type-C PD controllers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260731-ucsi-itepd-v6-1-d25ae12b181f@ite.com.tw> References: <20260731-ucsi-itepd-v6-0-d25ae12b181f@ite.com.tw> In-Reply-To: <20260731-ucsi-itepd-v6-0-d25ae12b181f@ite.com.tw> To: Jeson Yang , Yaode Fang , Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heikki Krogerus CC: , , , Amber Kao , Bling Chiang , Eric Su , Doreen Lin , Krzysztof Kozlowski X-Mailer: b4 0.15.2 X-ClientProxiedBy: TPEMAIL1.internal.ite.com.tw (192.168.15.58) To HSCMAIL1.internal.ite.com.tw (192.168.35.58) X-TM-SNTS-SMTP: ACDA380D6A546B158E8E437BD98DCD71ACE3CAFF1442ADD27F660B008A14B08D2002:8 X-MAIL: mse.ite.com.tw 66VA1knq005672 Add device tree binding for the ITE IT8851 and IT8853 I2C-based USB Type-C Power Delivery controllers. The IT8851 supports one Type-C port; the IT8853 is the two-port variant sharing the same interface. Add a MAINTAINERS entry for the binding. Cc: Yaode Fang Cc: Jeson Yang Cc: Bling Chiang Cc: Eric Su Cc: Doreen Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Amber Kao --- .../devicetree/bindings/usb/ite,it8851.yaml | 151 +++++++++++++++++= ++++ MAINTAINERS | 8 ++ 2 files changed, 159 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/ite,it8851.yaml b/Docume= ntation/devicetree/bindings/usb/ite,it8851.yaml new file mode 100644 index 000000000000..246d34734b4a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ite,it8851.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ite,it8851.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ITE IT8851/IT8853 USB Type-C Power Delivery Controller + +maintainers: + - Jeson Yang + +description: + The ITE IT8851 is an I2C-based USB Type-C Power Delivery (PD) controller + supporting one Type-C port. + The IT8853 is the two-port variant sharing the same programming interfac= e. + +properties: + compatible: + oneOf: + - const: ite,it8851 + - items: + - const: ite,it8853 + - const: ite,it8851 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + wakeup-source: true + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^connector@[01]$': + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +anyOf: + - required: + - connector@0 + - required: + - connector@1 + +allOf: + - if: + not: + properties: + compatible: + contains: + const: ite,it8853 + then: + properties: + connector@1: false + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + typec@40 { + compatible =3D "ite,it8853", "ite,it8851"; + reg =3D <0x40>; + interrupts-extended =3D <&tlmm 129 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; + + #address-cells =3D <1>; + #size-cells =3D <0>; + + connector@0 { + compatible =3D "usb-c-connector"; + reg =3D <0>; + label =3D "USB-C-0"; + power-role =3D "dual"; + data-role =3D "dual"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + endpoint { + remote-endpoint =3D <&eud_con>; + }; + }; + + port@1 { + reg =3D <1>; + endpoint { + remote-endpoint =3D <&redriver_ss_out>; + }; + }; + + port@2 { + reg =3D <2>; + endpoint { + remote-endpoint =3D <&fsa4480_sbu_mux>; + }; + }; + }; + }; + + connector@1 { + compatible =3D "usb-c-connector"; + reg =3D <1>; + label =3D "USB-C-1"; + power-role =3D "dual"; + data-role =3D "dual"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + endpoint { + remote-endpoint =3D <&usb1_hs_con>; + }; + }; + port@1 { + reg =3D <1>; + endpoint { + remote-endpoint =3D <&redriver1_ss_out>; + }; + }; + port@2 { + reg =3D <2>; + endpoint { + remote-endpoint =3D <&sbu_mux1>; + }; + }; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 461a3eed6129..ec0eeea79b9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13720,6 +13720,14 @@ T: git https://gitlab.freedesktop.org/drm/misc/ker= nel.git F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml F: drivers/gpu/drm/bridge/ite-it66121.c =20 +ITE IT8851 TYPE-C PD CONTROLLER DRIVER +M: Amber Kao +R: Jeson Yang +R: Yaode Fang +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/usb/ite,it8851.yaml + IVTV VIDEO4LINUX DRIVER M: Andy Walls L: linux-media@vger.kernel.org --=20 2.53.0 From nobody Fri Oct 2 13:10:16 2026 Received: from ironport.ite.com.tw (60-251-196-230.hinet-ip.hinet.net [60.251.196.230]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7AEBA3BED78; Fri, 31 Jul 2026 10:01:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.251.196.230 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785492137; cv=none; b=Y5UiQLcJ0Ss0DAebZxcoMSXro2Cy8XIh1iJeiY4Q4zD/PxEG0Kv6pf1ZhiOk0bg+U+XI7RkNPnhqzFQzoPzs+eByhGHLo4n7tjCQUVEwpaus63zBChpu44agv+h33SQDe5YHoiaKaqrRiB3+s57q2sdH07Xm/ZfB5bwHpIAb+3I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785492137; c=relaxed/simple; bh=WkEp3+KOKFjSM00NHE+Zqkjl31hejSX392orgnxxnx8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=shv4ustgOnDBWEm06qx+6N7hH2nEsUivQes9+oPIzRATLNE8smY4uOOySIXotOkJa//fJtNHIUCJM0d6MbXo5HzdAA1YRuPE6OJVqYN63bXIFDoAerE+hWGLCPB8VnaUxIt3wPK56+0tebNJdW9JCEYVSRiTklnKkck8cbzitm0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ite.com.tw; spf=pass smtp.mailfrom=ite.com.tw; dkim=pass (2048-bit key) header.d=ite.com.tw header.i=@ite.com.tw header.b=QEMhE7oK; arc=none smtp.client-ip=60.251.196.230 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ite.com.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ite.com.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ite.com.tw header.i=@ite.com.tw header.b="QEMhE7oK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ite.com.tw; s=dkim; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=+eNVIAM3DD8HhF06zVlzHuhCgRy2YlCPD3Ty3d+9DCQ=; b=QEMhE7oKsGDlEZGmsqyxr65FVk5lelroJ2U2Hw4FC1QYyq2Pn8TqIFoT dmLmrX4KjypPkaFgu50pPdD9ouB68YgxM2gw825LN+PS4ZhnycLlAaXg9 B/HpNGeSlyPgMlXGvagBuPOYgRnuGmmZxtD2WcI8HVc16dHcmSsC7p7oQ mjWfLWYLRiGCAZI/aKG4sMkbuTnXfvux7oxnHJ1Ht8YSh5iopwHznQDvN rmbQodbzxYrQsC/PPm4YBrSr3iAJVp0mFYcQgo3C1SFqCz9zQPVmWCmOW GNUpSix6OltLP92KBoTvx2QYfeadY2HzJkj5h3tTMFQZA3EBJ1karvTRR Q==; X-CSE-ConnectionGUID: 1FsLzIGqQkyhO2ItmxICTA== X-CSE-MsgGUID: VdsrvA4NRNugBYGZRPKKkg== Received: from unknown (HELO mse.ite.com.tw) ([192.168.35.30]) by ironport.ite.com.tw with ESMTP; 31 Jul 2026 18:01:47 +0800 Received: from hscmail1.internal.ite.com.tw (HSCMAIL1.internal.ite.com.tw [192.168.35.58]) by mse.ite.com.tw with ESMTP id 66VA1j5T005654; Fri, 31 Jul 2026 18:01:45 +0800 (+08) (envelope-from amber.kao@ite.com.tw) Received: from [127.0.1.1] (192.168.37.107) by HSCMAIL1.internal.ite.com.tw (192.168.35.58) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.37; Fri, 31 Jul 2026 18:01:45 +0800 From: Amber Kao Date: Fri, 31 Jul 2026 18:02:04 +0800 Subject: [PATCH v6 2/2] usb: typec: ucsi: Add ITE IT8851/IT8853 Type-C PD controller driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260731-ucsi-itepd-v6-2-d25ae12b181f@ite.com.tw> References: <20260731-ucsi-itepd-v6-0-d25ae12b181f@ite.com.tw> In-Reply-To: <20260731-ucsi-itepd-v6-0-d25ae12b181f@ite.com.tw> To: Jeson Yang , Yaode Fang , Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heikki Krogerus CC: , , , Amber Kao , Bling Chiang , Eric Su , Doreen Lin X-Mailer: b4 0.15.2 X-ClientProxiedBy: TPEMAIL1.internal.ite.com.tw (192.168.15.58) To HSCMAIL1.internal.ite.com.tw (192.168.35.58) X-TM-SNTS-SMTP: DCA964DBD1085541BC131C75AE307D23B685B32256F94C82463ACB595BB0B7532002:8 X-MAIL: mse.ite.com.tw 66VA1j5T005654 Add a UCSI driver for the ITE IT8851 and IT8853 I2C-based USB Type-C Power Delivery controllers. The controller signals UCSI through a shared interrupt line; events are read and acknowledged via vendor-specific registers, and UCSI events are forwarded to the UCSI core. Add the driver file to the MAINTAINERS entry. Cc: Yaode Fang Cc: Jeson Yang Cc: Bling Chiang Cc: Eric Su Cc: Doreen Lin Signed-off-by: Amber Kao --- MAINTAINERS | 1 + drivers/usb/typec/ucsi/Kconfig | 10 + drivers/usb/typec/ucsi/Makefile | 1 + drivers/usb/typec/ucsi/ucsi_itepd.c | 364 ++++++++++++++++++++++++++++++++= ++++ 4 files changed, 376 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ec0eeea79b9e..1e76e299e6c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13727,6 +13727,7 @@ R: Yaode Fang L: linux-usb@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/usb/ite,it8851.yaml +F: drivers/usb/typec/ucsi/ucsi_itepd.c =20 IVTV VIDEO4LINUX DRIVER M: Andy Walls diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 87dd992a4b9e..0f10dac9b34b 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -104,4 +104,14 @@ config UCSI_HUAWEI_GAOKUN To compile the driver as a module, choose M here: the module will be called ucsi_huawei_gaokun. =20 +config UCSI_ITEPD + tristate "UCSI Interface Driver for ITE IT8851/IT8853" + depends on I2C + help + This driver enables UCSI support on platforms that expose an + ITE IT8851/IT8853 Type-C Power Delivery controller over an I2C interfac= e. + + To compile the driver as a module, choose M here: the module + will be called ucsi_itepd. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makef= ile index c7e38bf01350..0903a1fd486b 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_UCSI_PMIC_GLINK) +=3D ucsi_glink.o obj-$(CONFIG_CROS_EC_UCSI) +=3D cros_ec_ucsi.o obj-$(CONFIG_UCSI_LENOVO_YOGA_C630) +=3D ucsi_yoga_c630.o obj-$(CONFIG_UCSI_HUAWEI_GAOKUN) +=3D ucsi_huawei_gaokun.o +obj-$(CONFIG_UCSI_ITEPD) +=3D ucsi_itepd.o diff --git a/drivers/usb/typec/ucsi/ucsi_itepd.c b/drivers/usb/typec/ucsi/u= csi_itepd.c new file mode 100644 index 000000000000..a639b3d32535 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_itepd.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025-2026, ITE. All Rights Reserved + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ucsi.h" + +#define ITEPD_UCSI_VERSION_REG 0x80 +#define ITEPD_UCSI_CCI_REG 0x84 +#define ITEPD_UCSI_MSG_IN_REG 0x88 +#define ITEPD_UCSI_CONTROL_REG 0x98 + +#define ITEPD_VENDOR_WC_INT 0xbc +#define ITEPD_VENDOR_INT 0xbd +#define ITEPD_ALERT_VDM_EVENT BIT(0) +#define ITEPD_ALERT_UCSI_EVENT BIT(1) + +#define ITEPD_MSG_IN_MAX_LEN 0x28 + +#define ITEPD_EVENT_NONE 0 +#define ITEPD_EVENT_UCSI 1 +#define ITEPD_EVENT_VDM 2 + +struct itepd { + struct i2c_client *client; + struct ucsi *ucsi; + struct mutex i2c_lock; /* Serializes I2C accesses */ + struct mutex event_lock; /* Serializes event processing (IRQ vs poll) */ + struct mutex received_lock; /* Protects cci and msg_in */ + u8 msg_in[ITEPD_MSG_IN_MAX_LEN]; + u32 cci; +}; + +static u8 ucsi_itepd_get_len(u32 cci) +{ + if (cci & UCSI_CCI_COMMAND_COMPLETE) + return UCSI_CCI_LENGTH(cci); + return 0; +} + +static int itepd_read_reg(struct itepd *itepd, u8 reg, void *data, u32 len) +{ + struct i2c_client *client =3D itepd->client; + struct i2c_msg msg[2] =3D { + { + .addr =3D client->addr, + .flags =3D 0, + .len =3D 1, + .buf =3D ®, + }, + { + .addr =3D client->addr, + .flags =3D I2C_M_RD, + .len =3D len, + .buf =3D data, + } + + }; + int ret; + + mutex_lock(&itepd->i2c_lock); + ret =3D i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + mutex_unlock(&itepd->i2c_lock); + if (ret < 0) { + dev_err_ratelimited(&client->dev, "reg 0x%02x read failed: %d\n", + reg, ret); + return ret; + } + + return ret =3D=3D ARRAY_SIZE(msg) ? 0 : -EIO; +} + +static int itepd_write_reg(struct itepd *itepd, u8 reg, const void *data, = u32 len) +{ + struct i2c_client *client =3D itepd->client; + u8 buf[sizeof(u64) + 1]; + struct i2c_msg msg[1] =3D { + { + .addr =3D client->addr, + .flags =3D 0, + .len =3D len + 1, + .buf =3D buf, + } + }; + int ret; + + if (len > sizeof(buf) - 1) + return -EINVAL; + + buf[0] =3D reg; + memcpy(&buf[1], data, len); + + mutex_lock(&itepd->i2c_lock); + ret =3D i2c_transfer(client->adapter, msg, 1); + mutex_unlock(&itepd->i2c_lock); + if (ret < 0) { + dev_err_ratelimited(&client->dev, "reg 0x%02x write failed: %d\n", + reg, ret); + return ret; + } + + return ret =3D=3D 1 ? 0 : -EIO; +} + +static int itepd_process_event(struct itepd *itepd, u32 *cci) +{ + u8 msg_in[ITEPD_MSG_IN_MAX_LEN] =3D {}; + __le32 le_cci; + u8 event, ack; + u8 len =3D 0; + int err =3D 0; + int ret; + + mutex_lock(&itepd->event_lock); + + ret =3D itepd_read_reg(itepd, ITEPD_VENDOR_INT, &event, sizeof(event)); + if (ret) + goto out_unlock; + + event &=3D ITEPD_ALERT_VDM_EVENT | ITEPD_ALERT_UCSI_EVENT; + if (!event) { + mutex_lock(&itepd->received_lock); + *cci =3D itepd->cci; + mutex_unlock(&itepd->received_lock); + ret =3D ITEPD_EVENT_NONE; + goto out_unlock; + } + + if (event & ITEPD_ALERT_UCSI_EVENT) { + err =3D itepd_read_reg(itepd, ITEPD_UCSI_CCI_REG, &le_cci, + sizeof(le_cci)); + if (!err) { + *cci =3D le32_to_cpu(le_cci); + len =3D min_t(u8, ucsi_itepd_get_len(*cci), + sizeof(msg_in)); + if (len) + err =3D itepd_read_reg(itepd, + ITEPD_UCSI_MSG_IN_REG, + msg_in, len); + } + } + + ack =3D event; + ret =3D itepd_write_reg(itepd, ITEPD_VENDOR_WC_INT, &ack, sizeof(ack)); + if (ret) + goto out_unlock; + + if (err) { + ret =3D err; + goto out_unlock; + } + + if (event & ITEPD_ALERT_UCSI_EVENT) { + mutex_lock(&itepd->received_lock); + itepd->cci =3D *cci; + memset(itepd->msg_in, 0, sizeof(itepd->msg_in)); + memcpy(itepd->msg_in, msg_in, len); + mutex_unlock(&itepd->received_lock); + ret =3D ITEPD_EVENT_UCSI; + } else { + mutex_lock(&itepd->received_lock); + *cci =3D itepd->cci; + mutex_unlock(&itepd->received_lock); + ret =3D ITEPD_EVENT_VDM; + } + +out_unlock: + mutex_unlock(&itepd->event_lock); + return ret; +} + +static int ucsi_itepd_read_version(struct ucsi *ucsi, u16 *version) +{ + struct itepd *itepd =3D ucsi_get_drvdata(ucsi); + __le16 le_version; + int ret; + + ret =3D itepd_read_reg(itepd, ITEPD_UCSI_VERSION_REG, &le_version, + sizeof(le_version)); + if (ret) + return ret; + + *version =3D le16_to_cpu(le_version); + + return 0; +} + +static int ucsi_itepd_read_cci(struct ucsi *ucsi, u32 *cci) +{ + struct itepd *itepd =3D ucsi_get_drvdata(ucsi); + + mutex_lock(&itepd->received_lock); + *cci =3D itepd->cci; + mutex_unlock(&itepd->received_lock); + + return 0; +} + +static int ucsi_itepd_poll_cci(struct ucsi *ucsi, u32 *cci) +{ + struct itepd *itepd =3D ucsi_get_drvdata(ucsi); + int ret; + + ret =3D itepd_process_event(itepd, cci); + return ret < 0 ? ret : 0; +} + +static int ucsi_itepd_read_message_in(struct ucsi *ucsi, void *val, size_t= val_len) +{ + struct itepd *itepd =3D ucsi_get_drvdata(ucsi); + + mutex_lock(&itepd->received_lock); + memcpy(val, itepd->msg_in, min(val_len, sizeof(itepd->msg_in))); + mutex_unlock(&itepd->received_lock); + + return 0; +} + +static int ucsi_itepd_async_control(struct ucsi *ucsi, u64 command) +{ + struct itepd *itepd =3D ucsi_get_drvdata(ucsi); + __le64 le_cmd =3D cpu_to_le64(command); + + if (UCSI_COMMAND(command) =3D=3D UCSI_PPM_RESET) { + mutex_lock(&itepd->received_lock); + itepd->cci =3D 0; + mutex_unlock(&itepd->received_lock); + } + + return itepd_write_reg(itepd, ITEPD_UCSI_CONTROL_REG, &le_cmd, + sizeof(le_cmd)); +} + +static const struct ucsi_operations ucsi_itepd_ops =3D { + .read_version =3D ucsi_itepd_read_version, + .read_cci =3D ucsi_itepd_read_cci, + .poll_cci =3D ucsi_itepd_poll_cci, + .read_message_in =3D ucsi_itepd_read_message_in, + .sync_control =3D ucsi_sync_control_common, + .async_control =3D ucsi_itepd_async_control, +}; + +static irqreturn_t itepd_irq_process(struct itepd *itepd) +{ + u32 cci; + int ret; + + ret =3D itepd_process_event(itepd, &cci); + if (ret =3D=3D ITEPD_EVENT_NONE) + return IRQ_NONE; + + if (ret < 0) + return IRQ_HANDLED; + + if (ret =3D=3D ITEPD_EVENT_UCSI) + ucsi_notify_common(itepd->ucsi, cci); + + return IRQ_HANDLED; +} + +static irqreturn_t itepd_irq_thread_fn(int irq, void *data) +{ + struct itepd *itepd =3D data; + + return itepd_irq_process(itepd); +} + +static int itepd_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + struct itepd *itepd; + u32 cci; + int ret; + + if (client->irq <=3D 0) + return dev_err_probe(dev, -ENODEV, "no IRQ provided\n"); + + itepd =3D devm_kzalloc(dev, sizeof(*itepd), GFP_KERNEL); + if (!itepd) + return -ENOMEM; + + itepd->client =3D client; + mutex_init(&itepd->i2c_lock); + mutex_init(&itepd->event_lock); + mutex_init(&itepd->received_lock); + i2c_set_clientdata(client, itepd); + + itepd->ucsi =3D ucsi_create(dev, &ucsi_itepd_ops); + if (IS_ERR(itepd->ucsi)) + return dev_err_probe(dev, PTR_ERR(itepd->ucsi), + "ucsi_create failed\n"); + + ucsi_set_drvdata(itepd->ucsi, itepd); + + ret =3D request_threaded_irq(client->irq, NULL, itepd_irq_thread_fn, + IRQF_ONESHOT, dev_name(dev), itepd); + if (ret) { + dev_err_probe(dev, ret, "request_threaded_irq failed\n"); + goto out_ucsi_destroy; + } + + ret =3D itepd_process_event(itepd, &cci); + if (ret < 0) + dev_warn(dev, "initial event processing failed: %d\n", ret); + + ret =3D ucsi_register(itepd->ucsi); + if (ret) { + dev_err_probe(dev, ret, "failed to register UCSI\n"); + goto out_free_irq; + } + + return 0; + +out_free_irq: + free_irq(client->irq, itepd); +out_ucsi_destroy: + ucsi_destroy(itepd->ucsi); + return ret; +} + +static void itepd_remove(struct i2c_client *client) +{ + struct itepd *itepd =3D i2c_get_clientdata(client); + + ucsi_unregister(itepd->ucsi); + free_irq(client->irq, itepd); + ucsi_destroy(itepd->ucsi); +} + +static const struct of_device_id itepd_of_match_table[] =3D { + { .compatible =3D "ite,it8851" }, + {} +}; +MODULE_DEVICE_TABLE(of, itepd_of_match_table); + +static const struct i2c_device_id itepd_id_table[] =3D { + { "ucsi_itepd", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, itepd_id_table); + +static struct i2c_driver itepd_driver =3D { + .driver =3D { + .name =3D "ucsi_itepd", + .of_match_table =3D itepd_of_match_table, + }, + .probe =3D itepd_probe, + .remove =3D itepd_remove, + .id_table =3D itepd_id_table, +}; +module_i2c_driver(itepd_driver); + +MODULE_AUTHOR("Jeson Yang "); +MODULE_DESCRIPTION("UCSI driver for ITE IT8851 and IT8853 Type-C PD contro= llers"); +MODULE_LICENSE("GPL"); --=20 2.53.0