From nobody Tue Apr 7 09:05:26 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1230F1E1A3D for ; Sat, 14 Mar 2026 01:32:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773451935; cv=none; b=t6RKQnGUjc6PXSVA7QMZ+uDA56bHW66lGAlTquTt2xMzB2FfsyIlcEVgG4NSaZUYnlN+lM0opbON2wgXamjSgVDdB3M6Y18KCOVi9W/fsQmDL3rYKDgZ106FYpH0isav24vOcQEXlNS8lZXWtr3y3HJoftbQn6BJYzg5DIi3rg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773451935; c=relaxed/simple; bh=mUxCPP/m7AMSSH1pxHzOmtIKNsUap3vsjNULA0fzP4Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LQ8RzXM5yLLx4GziJGvruDq3ONzpHAqosj7HUiXPP3nVfjXGYQrdQZXF9l3V85+tB+Uo9LhjVZP9QPfh3w6n8SrIPKbsuVCCyX9fjjxwe/v2CeO4svwQ8w0NprVjAdGr8zvc1tbqxPno7UoSqDistLFjoovoG9RzzkOP/3jiRms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Pf7Ujhb8; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Pf7Ujhb8" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-439aeed8a5bso2884260f8f.3 for ; Fri, 13 Mar 2026 18:32:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773451931; x=1774056731; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iR0JNXye1PQ32tEpIdRTYUVyYik8LC1u1H+imbfX1oQ=; b=Pf7Ujhb8dtVkmMW1sYsmFyRiaTAg+CNq/Kje8X6lJgZTbaMtsSpsd/xOmfxnbOfpfd xRlwOCJDaZz+Btk8wQCnls32+3PTli+M2NwqaNOeeAnshzswbZFcablBSyQxjnUky86Q 9xPCWjQ8GPb080Ab2bucOWYip66HCaVd0LYfNiEuMxzwb7hNYI4yZdzgxVukpCDd0pYk 0wLajObpNsEup5MfL6bBHe2E+ch2DJkCph9hKhYheH1p2KONv2M1m2FgdBNPo/5oCSxk hRfExYrFYL1ymx/qmT/Eni/lKEuweArN1EPxIX7pb1+B87/09RD8F4M05Yp92UPlSjiW UJIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773451931; x=1774056731; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=iR0JNXye1PQ32tEpIdRTYUVyYik8LC1u1H+imbfX1oQ=; b=j+LD4BIL1iXKYpPaLzFlOqimFcKaKuwGfkxx7VVm/fRLk7m9Gx8AZ3d95WcFeXdot5 qStYXMYMgFLR1rrSIa++d8JS4RJf/I1qo6zkldmXkFHjMBp44mPV9Wt0YCZXCC29ummJ ygZlyY1IDTWOGyrSVyeK9ZSjOfyuROZd5MsFvTGx8AxixkeVcdNoVVba+UzEVopHUSKV JqxgeaaQ/IfVxuaeF5Jylvj6aV5y8yH2M6XrkQ2fDwfpCEvP3Qru7YrWBDfkfNU8Xp06 xdmGKD/Afu3VkWkLhJTkUCiz5v3FBPfrmal7mBeIVqcaWAPIcHvbqKNyxB1EgW9NmC+3 dfJA== X-Forwarded-Encrypted: i=1; AJvYcCXsc1oga+sJkEZlp1H/T0/ua0S5KRHPQnNhQUkhuLtSTaVwa3znmhG/Or/HirRLLHjO0GHm4ZZIL42dt38=@vger.kernel.org X-Gm-Message-State: AOJu0YwDukOLmrq/MaZNJa+bpKi/qW4LIfn9YuSETghKbQNpTbI6kHEx 9c5tBqNi2Tyq0cwPT6g19TihyCWA0pyf+kk+RlYkGLg0mquDrQt44CUD X-Gm-Gg: ATEYQzy6ElZl5JblG2ImwRIAmlubN06DR1OO6at8bBZJr8iZznguwWziAP0B0SEwtC5 nPHJKNPmZCRc/bEKabhEw2mpuX5L/rXvDD/mIsaDM14gNvDsNeHxAEdnZWPFUkKMhXiTS4qD0dY K4Vyf/5HfBXZvPZtm2Tn09LxPv7OV7oLmdcP/+wHVYNtx7WlagAPDTWIC5jMbsQxwqkpW7n+LFS AMbEgNFjCtNXTuCGMXHW7IfyNfS1S3CzyYkZuk1yluzVsZazxQh7W14fZUJ8B44WBZ8MF5i/uaW hLyEbetiUjGcS+hhj+NMiZ1PtnRG94PN0QFbo2qAj+evX9gTJ9M2+6BonZeBBx/cvYJAohngbuW yH2P0FXQxTR3b6pyKrTrgO+QblwbD+cPQYUHYuAo12FNDTg84amxoqyL49OmUb6VqWPN4nWYrEm KKABmQ6j5y8EMYt2mjczhZlQVkF2NkrJQmySNqHVJyz6RZZYXfsQWNO7up9ZoGFChXxfsMZr24p pR31S8xPUNUeo6BKtA6DESqkuKaup6VgJzPraoTzoL3+ihSZN0Vad0ctE5F7TXT86IzPlDBpk4Z 7i1SBLPFDuU= X-Received: by 2002:a05:6000:2501:b0:439:ba4d:bf40 with SMTP id ffacd0b85a97d-43a04dc831fmr10711463f8f.43.1773451931220; Fri, 13 Mar 2026 18:32:11 -0700 (PDT) Received: from scambox.localdomain (5-198-68-184.static.kc.net.uk. [5.198.68.184]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-439fe22529csm21876575f8f.31.2026.03.13.18.32.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 Mar 2026 18:32:10 -0700 (PDT) From: Edward Blair To: linux-i2c@vger.kernel.org, linux-usb@vger.kernel.org Cc: heikki.krogerus@linux.intel.com, gregkh@linuxfoundation.org, wsa+renesas@sang-engineering.com, westeri@kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Edward Blair Subject: [PATCH 1/2] i2c: acpi: skip generic I2C device when vendor-specific sibling exists Date: Sat, 14 Mar 2026 01:31:55 +0000 Message-ID: <20260314013157.7181-2-edward.blair@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260314013157.7181-1-edward.blair@gmail.com> References: <20260314013157.7181-1-edward.blair@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some BIOS implementations (notably ASUS Z690/Z790/X670E motherboards) declare both a generic UCSI device (MSFT8000) and a vendor-specific device (e.g., ITE8853) as ACPI children of the same I2C controller, both referencing the same I2C slave address. During ACPI I2C enumeration, whichever device is walked first claims the address, causing the second to fail with -EBUSY. When the generic MSFT8000 device registers first, the vendor-specific driver cannot bind, losing access to device-specific features like GPIO interrupt resources that are only declared on the vendor-specific ACPI device. Fix this by checking, before registering a known generic I2C device, whether a sibling ACPI device exists at the same address on the same adapter. If so, skip the generic device to let the vendor-specific one register instead. Signed-off-by: Edward Blair --- drivers/i2c/i2c-core-acpi.c | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 2cbd31f77..87582eac7 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -137,6 +137,17 @@ static const struct acpi_device_id i2c_acpi_ignored_de= vice_ids[] =3D { {} }; =20 +/* + * Generic I2C device IDs that may be duplicated by vendor-specific device= s. + * When a vendor-specific sibling exists at the same address, the generic + * device is skipped to avoid -EBUSY address conflicts. + */ +static const struct acpi_device_id i2c_acpi_generic_device_ids[] =3D { + /* Microsoft UCSI - often paired with vendor-specific UCSI device */ + { "MSFT8000" }, + {} +}; + struct i2c_acpi_irq_context { int irq; bool wake_capable; @@ -274,6 +285,76 @@ static int i2c_acpi_get_info(struct acpi_device *adev, return 0; } =20 +struct i2c_acpi_sibling_check { + struct acpi_device *self; + struct i2c_adapter *adapter; + unsigned short addr; + bool found; +}; + +static int i2c_acpi_check_sibling_addr(struct acpi_device *adev, void *dat= a) +{ + struct i2c_acpi_sibling_check *check =3D data; + struct i2c_acpi_lookup lookup; + struct i2c_board_info info; + + if (adev =3D=3D check->self) + return 0; + + /* Only yield to vendor-specific devices, not other generic ones */ + if (!acpi_match_device_ids(adev, i2c_acpi_generic_device_ids)) + return 0; + + memset(&lookup, 0, sizeof(lookup)); + lookup.info =3D &info; + lookup.index =3D -1; + + if (i2c_acpi_do_lookup(adev, &lookup)) + return 0; + + if (!device_match_acpi_handle(&check->adapter->dev, + lookup.adapter_handle)) + return 0; + + if (info.addr =3D=3D check->addr) { + check->found =3D true; + return 1; + } + + return 0; +} + +/* + * Check whether this generic ACPI device has a vendor-specific sibling at= the + * same I2C address. Some BIOS implementations (e.g., ASUS Z690/Z790/X670E) + * declare both a generic UCSI device (MSFT8000) and a vendor-specific dev= ice + * (e.g., ITE8853) at the same address. Skip the generic one so the vendor + * driver can bind with proper interrupt and device-specific resources. + */ +static bool i2c_acpi_has_vendor_sibling(struct acpi_device *adev, + struct i2c_adapter *adapter, + struct i2c_board_info *info) +{ + struct acpi_device *parent; + struct i2c_acpi_sibling_check check; + + if (acpi_match_device_ids(adev, i2c_acpi_generic_device_ids)) + return false; + + parent =3D acpi_dev_parent(adev); + if (!parent) + return false; + + check.self =3D adev; + check.adapter =3D adapter; + check.addr =3D info->addr; + check.found =3D false; + + acpi_dev_for_each_child(parent, i2c_acpi_check_sibling_addr, &check); + + return check.found; +} + static void i2c_acpi_register_device(struct i2c_adapter *adapter, struct acpi_device *adev, struct i2c_board_info *info) @@ -302,6 +383,13 @@ static acpi_status i2c_acpi_add_device(acpi_handle han= dle, u32 level, if (!adev || i2c_acpi_get_info(adev, &info, adapter, NULL)) return AE_OK; =20 + if (i2c_acpi_has_vendor_sibling(adev, adapter, &info)) { + dev_info(&adapter->dev, + "skipping %s in favor of vendor-specific device at 0x%02x\n", + dev_name(&adev->dev), info.addr); + return AE_OK; + } + i2c_acpi_register_device(adapter, adev, &info); =20 return AE_OK; --=20 2.53.0 From nobody Tue Apr 7 09:05:26 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC012214812 for ; Sat, 14 Mar 2026 01:32:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773451935; cv=none; b=p6Pz/3uXVkj/qeYK2erwaBquZlluQRyOjSx6qAqrPRcbMxwDjRCnrL6/kAzqIQwqgcicg4Dh7Eq45Vn17H7SqDpQr7oO1CRJvA46YauZKBx7TRprVvivTm9f5eUZSNirVGlwtN1bALR+oVRIwM6GR0JX8+OX4b/71tsvKGbl9oQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773451935; c=relaxed/simple; bh=p8T4E7480ILfoOrSFfqVs8pQWFIFxD+u2YFQz9fnNxo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jbK7YqbMEOOIKm2SNSihCmktA+warWIw5YaVeTtieJFb1JQGwivILv6H3w5WnsS3o77auvU5UzybZncM1xTjH0f2gD32Je5TS4clyjyIdj1LOVhu5ffMrkLJYVIgOLLSx1Baq/o5TqaEdinD29AFdMmRFt48xfRIrXWlkg/0dUs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FA1DBfzM; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FA1DBfzM" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-439b9cf8cb5so3102629f8f.0 for ; Fri, 13 Mar 2026 18:32:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773451932; x=1774056732; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=jvDWBNZNK1PJ+DFXrEgOI7FkazNpTVvzpyU4Do+y01s=; b=FA1DBfzMSq9HUDJmjQ3PFv0cBwqahnZsxgMIu0G0GzM9t6J8+vpwuLdf3H1hP2Ir6n JeG1Fh2uMIg41kydTFU5zELzenDn5EQF//AOx9pp3yQkbjGAeLoCwCW5hxig61Q32TvD rftXzBTk7l8KuiM5401ZPhgTbqxvr++ku/UI80rEmpcrQ1ssdXJPTbJnp+5haD3CxGOf addpHiWxKbICG7DRtIkvnic1r/aBEM98F8nfFVo89+ZgdEs3eHLFcXdMga4A+bzKbWwL xRIgBUWaAJ3fpmDELudj2L+g7SjNTrdj/tf+j0CgHpycE7uHEE/0M7Bsuhg8iGvMv/U5 6KlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773451932; x=1774056732; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=jvDWBNZNK1PJ+DFXrEgOI7FkazNpTVvzpyU4Do+y01s=; b=HKkG3FV8+BqDdFhQYaN+mDYoTkJ+PLXCYtAafAwBbQawpXOCSGg8BUQyEFH+DFqI61 3Xxpb98S1Um6sEHjbSUNiFI7ZEUK0r8dX3Z2MiopbFlGKewz7nSDqrw5UmK9sUrN4UnT 3pO0Qu8MFkdZUkEHx6FZbzNLdEiBVRwbVw7lQ3kCu3sAja8nKeTZM/txDfWckHN6GUgL sN3PBbQR+8YK5cw3wQc3wnbS6aVZW+G0UT4uIdJ7OWBFKXLZpza4jST5KAkojtY8ThGz UKT34X8YcwkHBj63ZQ8mkT7TQFRdBy3e8p+9x03VhqrAWco7OwY3xcg9pLJi003OoKpu OZWQ== X-Forwarded-Encrypted: i=1; AJvYcCXSZLGAct4jzdFJpmN1gdZJhuDsNw9qt7ne4yQb2BspLQqkbMuHLngBIYJpT2Gt71KoT/XaTFVAZWaX6Zw=@vger.kernel.org X-Gm-Message-State: AOJu0Yx/kWcqQ4w2NNr6n9i53JEJd4jPtdsguFULFMJ2NNZRe+p7xxno CcSLGA+OORzsRyOuMqTSoRWvi8U1PK9Oer5/cpwW+5LmJ4vx6CTYJxEs X-Gm-Gg: ATEYQzwGnQWFqNMSlkp/A8LvkKztkOZ/+RiO3rEVqW7VjTTbyC5OUX5AWsOHhJ2ZDvu dM8+LUIv7+yPty3q5KRnyMzNEiIMGxM/Q5i1+/051TyyQhKVd5nucd10a0qv76KV9zWtEMcj7qd +rSIZ9F/JE2KU0V0N7SmuPlOmXnF9oFGMjbocnmg6ul7C6dLquCkilRe7gBUPZFGoduYm1DS0Zl IYuio6HBDGaskwlMI7zmBsjhGXOGRJ3KZSCt+BHem7AkgjpZPS8KT5qAtBtVxCglVSqO1BNECJx rCYwQ8Q72Rdc/nqFy9AnHzcOuP9RwujJbUKRQ9f/oNkRRSTdRRtk3mIgROX5BY/2vW1vaOayeXS 4mbhKKblxBLy7J2yffDUMYBBwu5KbYbOJZTjM2czqxZO8Rco7XwTUw8FvdGVABFEQFsWX91ZitQ QNGS2cftklf+xEvskcICeHJt3mOShvAjfG8ouHuWUy37+/V6YWW7rI6Ki3CEz+mxzT9iVDhODMT OlRRd/weoyHP/zF4ZOOSw5ALEXaZ9AiVVr9bP7GizXoksJVrVzYdF8rFWFOnxU7rTqvJ8LWF1O+ BikGrFBkKrw= X-Received: by 2002:a05:6000:1787:b0:439:c677:5145 with SMTP id ffacd0b85a97d-43a04d880e8mr9903496f8f.22.1773451932107; Fri, 13 Mar 2026 18:32:12 -0700 (PDT) Received: from scambox.localdomain (5-198-68-184.static.kc.net.uk. [5.198.68.184]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-439fe22529csm21876575f8f.31.2026.03.13.18.32.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 Mar 2026 18:32:11 -0700 (PDT) From: Edward Blair To: linux-i2c@vger.kernel.org, linux-usb@vger.kernel.org Cc: heikki.krogerus@linux.intel.com, gregkh@linuxfoundation.org, wsa+renesas@sang-engineering.com, westeri@kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, Edward Blair Subject: [PATCH 2/2] usb: typec: ucsi: add ITE885x I2C transport driver Date: Sat, 14 Mar 2026 01:31:56 +0000 Message-ID: <20260314013157.7181-3-edward.blair@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260314013157.7181-1-edward.blair@gmail.com> References: <20260314013157.7181-1-edward.blair@gmail.com> 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 Add a UCSI transport driver for ITE8853/ITE8800-ITE8805 USB Type-C controllers, commonly found on ASUS Z690/Z790/X670E motherboards. These controllers implement the UCSI protocol over I2C with ITE-proprietary register offsets and dedicated interrupt registers: - CCI at 0x84, MESSAGE_IN at 0x88, CONTROL at 0x98 - INT_STATUS at 0xBD, INT_ACK at 0xBC - GPIO interrupt (level-triggered, active-low) The ITE8853 does not accept PPM_RESET over I2C (the Windows driver handles it internally), so the driver intercepts this command and returns a synthetic reset-complete response. Tested on ASUS ROG Strix Z790-E Gaming WiFi with ITE8853 at I2C address 0x40 on the DesignWare I2C controller. Signed-off-by: Edward Blair --- drivers/usb/typec/ucsi/Kconfig | 11 ++ drivers/usb/typec/ucsi/Makefile | 1 + drivers/usb/typec/ucsi/ucsi_ite.c | 285 ++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 drivers/usb/typec/ucsi/ucsi_ite.c diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 87dd992a4..455272b5a 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -104,4 +104,15 @@ 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_ITE + tristate "UCSI Interface Driver for ITE885x" + depends on I2C + help + This driver enables UCSI support on platforms that expose an ITE8853 + or ITE8800-ITE8805 USB Type-C controller over I2C, commonly found + on ASUS Z690/Z790/X670E motherboards. + + To compile the driver as a module, choose M here: the module will be + called ucsi_ite. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makef= ile index c7e38bf01..9bc1d6bbb 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_ITE) +=3D ucsi_ite.o diff --git a/drivers/usb/typec/ucsi/ucsi_ite.c b/drivers/usb/typec/ucsi/ucs= i_ite.c new file mode 100644 index 000000000..400b844a1 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_ite.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UCSI I2C transport driver for ITE885x USB-C controllers + * + * ITE8853/ITE8800-ITE8805 are UCSI-compliant USB-C controllers found on + * ASUS Z690/Z790/X670E motherboards. They communicate via I2C with + * ITE-proprietary register offsets and interrupt registers. + * + * Note: Some BIOS implementations declare both MSFT8000 (generic UCSI) and + * ITE8853 (vendor-specific) ACPI devices at the same I2C address. The i2c + * core skips the generic device when a vendor-specific sibling exists, + * allowing this driver to bind to the ITE8853 client with proper IRQ. + */ + +#include +#include +#include +#include + +#include "ucsi.h" + +/* ITE-specific I2C register offsets */ +#define ITE_REG_CCI 0x84 +#define ITE_REG_MESSAGE_IN 0x88 +#define ITE_REG_CONTROL 0x98 +#define ITE_REG_INT_ACK 0xbc +#define ITE_REG_INT_STATUS 0xbd + +/* INT_STATUS register bits */ +#define ITE_INT_VENDOR_ALERT BIT(0) +#define ITE_INT_CCI BIT(1) + +/* INT_ACK register values */ +#define ITE_ACK_VENDOR 0x01 +#define ITE_ACK_CCI 0x02 + +struct ucsi_ite { + struct device *dev; + struct i2c_client *client; + struct ucsi *ucsi; +}; + +static int ucsi_ite_read(struct ucsi_ite *ite, u8 reg, void *val, size_t l= en) +{ + struct i2c_msg msgs[] =3D { + { + .addr =3D ite->client->addr, + .flags =3D 0, + .len =3D 1, + .buf =3D ®, + }, + { + .addr =3D ite->client->addr, + .flags =3D I2C_M_RD, + .len =3D len, + .buf =3D val, + }, + }; + int ret; + + ret =3D i2c_transfer(ite->client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret !=3D ARRAY_SIZE(msgs)) { + dev_err(ite->dev, "i2c read 0x%02x failed: %d\n", reg, ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int ucsi_ite_write(struct ucsi_ite *ite, u8 reg, const void *val, + size_t len) +{ + struct i2c_msg msg =3D { + .addr =3D ite->client->addr, + .flags =3D 0, + }; + u8 *buf; + int ret; + + buf =3D kmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] =3D reg; + memcpy(&buf[1], val, len); + msg.len =3D len + 1; + msg.buf =3D buf; + + ret =3D i2c_transfer(ite->client->adapter, &msg, 1); + kfree(buf); + if (ret !=3D 1) { + dev_err(ite->dev, "i2c write 0x%02x failed: %d\n", reg, ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int ucsi_ite_read_version(struct ucsi *ucsi, u16 *version) +{ + /* + * The ITE8853 does not expose a UCSI VERSION register over I2C. + * The Windows driver never reads it. Report UCSI 1.0. + */ + *version =3D UCSI_VERSION_1_0; + return 0; +} + +static int ucsi_ite_read_cci(struct ucsi *ucsi, u32 *cci) +{ + struct ucsi_ite *ite =3D ucsi_get_drvdata(ucsi); + + return ucsi_ite_read(ite, ITE_REG_CCI, cci, sizeof(*cci)); +} + +static int ucsi_ite_read_message_in(struct ucsi *ucsi, void *val, size_t l= en) +{ + struct ucsi_ite *ite =3D ucsi_get_drvdata(ucsi); + + return ucsi_ite_read(ite, ITE_REG_MESSAGE_IN, val, len); +} + +static int ucsi_ite_async_control(struct ucsi *ucsi, u64 command) +{ + struct ucsi_ite *ite =3D ucsi_get_drvdata(ucsi); + + return ucsi_ite_write(ite, ITE_REG_CONTROL, &command, sizeof(command)); +} + +static int ucsi_ite_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size) +{ + /* + * The ITE8853 handles PPM_RESET internally and does not accept it + * over I2C =E2=80=94 the Windows driver never sends it. Fake a successful + * reset so the UCSI core can proceed with initialization. + */ + if ((command & 0xff) =3D=3D UCSI_PPM_RESET) { + if (cci) + *cci =3D UCSI_CCI_RESET_COMPLETE; + return 0; + } + + return ucsi_sync_control_common(ucsi, command, cci, data, size); +} + +static const struct ucsi_operations ucsi_ite_ops =3D { + .read_version =3D ucsi_ite_read_version, + .read_cci =3D ucsi_ite_read_cci, + .poll_cci =3D ucsi_ite_read_cci, + .read_message_in =3D ucsi_ite_read_message_in, + .sync_control =3D ucsi_ite_sync_control, + .async_control =3D ucsi_ite_async_control, +}; + +static irqreturn_t ucsi_ite_irq(int irq, void *data) +{ + struct ucsi_ite *ite =3D data; + u8 status; + u32 cci; + u8 ack; + int ret; + + ret =3D ucsi_ite_read(ite, ITE_REG_INT_STATUS, &status, sizeof(status)); + if (ret) + return IRQ_NONE; + + if (!(status & (ITE_INT_CCI | ITE_INT_VENDOR_ALERT))) + return IRQ_NONE; + + if (status & ITE_INT_CCI) { + ack =3D ITE_ACK_CCI; + ucsi_ite_write(ite, ITE_REG_INT_ACK, &ack, sizeof(ack)); + + ret =3D ucsi_ite_read(ite, ITE_REG_CCI, &cci, sizeof(cci)); + if (!ret) + ucsi_notify_common(ite->ucsi, cci); + } + + if (status & ITE_INT_VENDOR_ALERT) { + ack =3D ITE_ACK_VENDOR; + ucsi_ite_write(ite, ITE_REG_INT_ACK, &ack, sizeof(ack)); + } + + return IRQ_HANDLED; +} + +static int ucsi_ite_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + struct ucsi_ite *ite; + int ret; + + ite =3D devm_kzalloc(dev, sizeof(*ite), GFP_KERNEL); + if (!ite) + return -ENOMEM; + + ite->dev =3D dev; + ite->client =3D client; + i2c_set_clientdata(client, ite); + + ite->ucsi =3D ucsi_create(dev, &ucsi_ite_ops); + if (IS_ERR(ite->ucsi)) + return PTR_ERR(ite->ucsi); + + ucsi_set_drvdata(ite->ucsi, ite); + + ret =3D request_threaded_irq(client->irq, NULL, ucsi_ite_irq, + IRQF_ONESHOT, dev_name(dev), ite); + if (ret) { + dev_err(dev, "failed to request IRQ: %d\n", ret); + goto err_destroy; + } + + ret =3D ucsi_register(ite->ucsi); + if (ret) { + dev_err(dev, "failed to register UCSI: %d\n", ret); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(client->irq, ite); +err_destroy: + ucsi_destroy(ite->ucsi); + return ret; +} + +static void ucsi_ite_remove(struct i2c_client *client) +{ + struct ucsi_ite *ite =3D i2c_get_clientdata(client); + + ucsi_unregister(ite->ucsi); + free_irq(client->irq, ite); + ucsi_destroy(ite->ucsi); +} + +static int ucsi_ite_suspend(struct device *dev) +{ + struct ucsi_ite *ite =3D dev_get_drvdata(dev); + + disable_irq(ite->client->irq); + + return 0; +} + +static int ucsi_ite_resume(struct device *dev) +{ + struct ucsi_ite *ite =3D dev_get_drvdata(dev); + + enable_irq(ite->client->irq); + + return ucsi_resume(ite->ucsi); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_ite_pm, ucsi_ite_suspend, + ucsi_ite_resume); + +static const struct acpi_device_id ucsi_ite_acpi_ids[] =3D { + { "ITE8853" }, + { "ITE8800" }, + { "ITE8801" }, + { "ITE8802" }, + { "ITE8803" }, + { "ITE8804" }, + { "ITE8805" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ucsi_ite_acpi_ids); + +static struct i2c_driver ucsi_ite_driver =3D { + .driver =3D { + .name =3D "ucsi_ite", + .acpi_match_table =3D ucsi_ite_acpi_ids, + .pm =3D pm_sleep_ptr(&ucsi_ite_pm), + }, + .probe =3D ucsi_ite_probe, + .remove =3D ucsi_ite_remove, +}; +module_i2c_driver(ucsi_ite_driver); + +MODULE_AUTHOR("Edward Blair "); +MODULE_DESCRIPTION("UCSI I2C transport driver for ITE885x USB-C controller= s"); +MODULE_LICENSE("GPL"); --=20 2.53.0