From nobody Fri Jun 19 09:06:15 2026 Received: from mail-lf1-f49.google.com (mail-lf1-f49.google.com [209.85.167.49]) (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 5F5F8372689 for ; Sat, 25 Apr 2026 18:20:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777141203; cv=none; b=mnnL6oC5+nUMS3O4VfSxr5W8itgkLJPXAYnzAIe7nLXfnP+z+6dIZonj3AlPVhFrMkx1HusablVXQk0ZW30Mu9EWwCCY+Vn1ZrHsx6PBvugDhBUhaZTd+QT4fUiv0GxQD36YUYY50amvE0RrKkZeYHkjJgDJ03OY2DodxgBSels= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777141203; c=relaxed/simple; bh=+gXx26kToc5Qsn+X5xpx5KaXlfJuV83OpMJgOHZcMo4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qzS1869hHLo01bqsOzbFGaVubPuhUOz0XuC5/NADLHF63VTI4M9Aw8Eq2OvLEWZaQ/6H/JVwbMlt/X+VOYYVIxdpgkapXJudEjTyRXib2i+IW7ASX1WQdYcibKFAPvaswba+KXDiTrs93zS6AjgiYHypGtCrMEFnsQY5MldhTV8= 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=opgvh6ff; arc=none smtp.client-ip=209.85.167.49 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="opgvh6ff" Received: by mail-lf1-f49.google.com with SMTP id 2adb3069b0e04-5a283c44478so14669726e87.3 for ; Sat, 25 Apr 2026 11:20:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777141199; x=1777745999; 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=pFgTexS82Aes4S2KA8waYF2yU7gR1eiSJ6BQPR26m30=; b=opgvh6ffORU3cLe/1PaQ+favvlB7G4jQIe586uew3y1GJCK4KNz5+y0yfY5dRoyT3d JeOnmNscJg4pwE31ro848Lt0BH71viwmQq/bvPeZ87UT7UoVw5eLDeNQQ+pLEVd+QrMl i8eLLWA1xQR3lBjnY3lRQCX7tQ3x53k0v87q8YVr2+QsCesXDt6YzFE4/yFCHm7mMVgQ vsP9RwFZZF7vy68aWEihSudVUvfR+rJe9LO5WZSK02Bm9utHAW7K/8EWxVypGVxQ25v1 B/0rAekKxvjTaKc4I852cbiPJDFGf11PmBjjXpMHMgUrOksLBRVKmYbfm2Mw2pUlW/bs z85g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777141199; x=1777745999; 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=pFgTexS82Aes4S2KA8waYF2yU7gR1eiSJ6BQPR26m30=; b=mrQcpw273kM0sfA2x8sTyKkLm7v4uiYDg7ybli0HTGsasbttKeBGtRpRQLcmEJHF4a Q/Sp1m8u9JOJiZ0eqLGLuMRKNComnAWVyd42GBT9ECBvBfdWJIATLG5TlgG6MLUxy3CG zixdwMSgJclWWANwSczZQV0xAIgwmi7MROe9KTMe1njj/olB5jyWHEURNlhCviuVN6a9 2pBWjndJTvHLcyNJILFYNRvabhYyOJNmCb7cJvsG9ze3PeRVV6ZKVjjj8Zna5NZffLEK 3QCe/Pb2DRwGa0TfYzMI5z7xgj5j0vPrnmoFXuYqpPEZxlr84Gw/xP6nwrnOzVcQ2m6r jBEQ== X-Forwarded-Encrypted: i=1; AFNElJ9/6ugU2ezBIUnd+JdPF5Y2Nan2k6t3IJ2gdhY6jul70SxA5uoCQmrcudM0Qu3gIgugMFDzTDT54ZPPUF8=@vger.kernel.org X-Gm-Message-State: AOJu0YxsYuVUchjmTcK8ATC1nX7q9NF6ZJDLX+F+kwJ0j7QfPGNfcXgF DmcZQv05aLLdKgDptrP6rY4sFxvTUuDa4F8eDcimhYN3MnH5L+x0GsC8 X-Gm-Gg: AeBDieshy+Crn8pODjADGx98o0b8i1aqEqUfY35ewlsyo0naX+/4a6TGtqTCsTIey4d jUQCA/YJzVVOWOunwhgjmHjNXKCWyLXSY0mRTcQvn3pza0rdx574y1MsCTJPL5nC+PkDQXwXHYI gdQTXuqHdt22MubeKG+VxVXsvKL0vvzWthN/WCZEw6spoVU3gJd5pPQGmYW84mOPHM5dmbv4uPl RW5SPH6pRzGxzXUbPBcMHQoBBktqnox2qTvYgJOeFlFGwBeoYJINQXssft8stcISRoBQvQYHRZz tLs/vYAxpWWeTI5EctBEf84mKRjkhlFwJ7sxMJqX0cQD/FPAXvcvSBi3JcK7PCSd5rq97nzgjEt d2n9QQNFlTJ7qNUzqUdpTQDfWYOmig91AYgMzcBVLZSTKjYzgZBwRkoTLWWOGfU2sOOD/hsRe0k i6bcclWF7YVdJ0Mm4jgbthpCs= X-Received: by 2002:a05:6512:3b25:b0:5a2:a8ab:ab4d with SMTP id 2adb3069b0e04-5a4172daacfmr11631274e87.22.1777141199206; Sat, 25 Apr 2026 11:19:59 -0700 (PDT) Received: from xeon ([188.163.112.56]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a4187e7ad0sm6836577e87.58.2026.04.25.11.19.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 25 Apr 2026 11:19:58 -0700 (PDT) From: Svyatoslav Ryhel To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Sebastian Reichel , Svyatoslav Ryhel , =?UTF-8?q?Jonas=20Schw=C3=B6bel?= Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Subject: [PATCH v1 1/2] dt-bindings: embedded-controller: Document Surface RT EC Date: Sat, 25 Apr 2026 21:19:35 +0300 Message-ID: <20260425181940.144028-2-clamor95@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260425181940.144028-1-clamor95@gmail.com> References: <20260425181940.144028-1-clamor95@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 Document Embedded Controller used in Microsoft Surface RT tablets for monitoring battery properties and charger status. Signed-off-by: Svyatoslav Ryhel --- .../microsoft,surface-rt-ec.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/embedded-controller/m= icrosoft,surface-rt-ec.yaml diff --git a/Documentation/devicetree/bindings/embedded-controller/microsof= t,surface-rt-ec.yaml b/Documentation/devicetree/bindings/embedded-controlle= r/microsoft,surface-rt-ec.yaml new file mode 100644 index 000000000000..0fee574a3015 --- /dev/null +++ b/Documentation/devicetree/bindings/embedded-controller/microsoft,surfa= ce-rt-ec.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/embedded-controller/microsoft,surface-r= t-ec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microsoft Surface RT fuel gauge and charger EC + +maintainers: + - Jonas Schw=C3=B6bel + - Svyatoslav Ryhel + +description: + An Embedded Controller used in Microsoft Surface RT for monitoring + battery properties and charger status. + +allOf: + - $ref: /schemas/power/supply/power-supply.yaml# + +properties: + compatible: + const: microsoft,surface-rt-ec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + enable-gpios: + maxItems: 1 + + monitored-battery: true + +required: + - compatible + - reg + - interrupts + - enable-gpios + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + embedded-controller@a { + compatible =3D "microsoft,surface-rt-ec"; + reg =3D <0x0a>; + + interrupt-parent =3D <&gpio>; + interrupts =3D <74 IRQ_TYPE_EDGE_RISING>; + + enable-gpios =3D <&gpio 88 GPIO_ACTIVE_HIGH>; + monitored-battery =3D <&battery>; + }; + }; +... --=20 2.51.0 From nobody Fri Jun 19 09:06:15 2026 Received: from mail-lf1-f53.google.com (mail-lf1-f53.google.com [209.85.167.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 18731374E66 for ; Sat, 25 Apr 2026 18:20:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777141205; cv=none; b=b/3MBwVRahgPxKZUUOWznZwAYsWhIksb/UOnIlO5XUInogFcIJKX7CChRqe10czlOO125VvIhuK3vr3bqNtj7Cg6CFkTgh3lQqDFqpeX/aMliVmWLoM1Z5eZaNes0b/U2m/B5q8M17YVpVNXs8gBJshLTu9lcoiW2hnnvZf7G3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777141205; c=relaxed/simple; bh=ovJEPROnI8oh4UHcj7s+NPF18CGcWd83JDwVTZ1XfAw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cOMzZSjiNcepccNhT8JaVm3bVvZZGlb3hWyQg8xt91xbC0z/1Pr/uWW/4jQJ1FM9LHJRomXMHZHJ2JQ/nVRqsgrejs2ScbzOL2L/XPldE2z5XVNHmBv/hVgfBMHmKXxVhDWhMXhs4QhQr6MHKupROh0L59JlPf4BUo1TAAz6W3I= 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=Dz27hceA; arc=none smtp.client-ip=209.85.167.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="Dz27hceA" Received: by mail-lf1-f53.google.com with SMTP id 2adb3069b0e04-5a525aedb24so8145431e87.2 for ; Sat, 25 Apr 2026 11:20:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777141201; x=1777746001; 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=fZxkYKD9FUW7bYFOXcNc8k+x6ZwaHjKGNbEr5Wj6tBU=; b=Dz27hceADMEJf/tetEocfZGFDQ9KMGeHetM+d6E+t62XxixDPreiVh7Ge6POZTRUEA BOT8sG3ZW3XPRHBFPVdXDNRSi70opc65JyhkksK+Y5l8+9ZsCVyzKrTn8CgeF9C7advy Cb2teYgCdD4EhPs2/9W43hrPmFDukkHimqRDEifZkEY8bO5nYPGLaXJAtWNbQeDiagHb OKJ4Od4d71VlwCFDRowy8SXQmON4S+2+Tysp86ei1tDwPm0kMbe0jk05ZJ1XmSNdJOQM 8JuNEZAYokNCD1J6zYhi85aFrcO1WoOhHoxTHYGv6Ls4WPSeLSNMOQUdejgu1p8GShvu rYOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777141201; x=1777746001; 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=fZxkYKD9FUW7bYFOXcNc8k+x6ZwaHjKGNbEr5Wj6tBU=; b=sFg9cjAFuL5IUYhU6eSK9NgvZenU/VdhhKQW3RlzvZicin9Vc9FLBIGXTdlcszZ4IU DtbXmBqHDClLZNR627FIW+L83RGfdiNCSCTyD/W9NZJVmjyVX7PWhFIykFWA8FNUDnzF W98fCRQWKYwGb9X13ywzwWTBodH41Agy/njTiDco2eD8ou70D5VJcU62bYXQ8xrEUmyB pCboZVnzJMaEX9M4GVM3cnsdiejkdR4He8GEruj+a9PdX/aX/u60LPPFt8kZT6xI6CGl FGo48lmhABLykN8y7yEC1IdVGVZ+qArXWQNzk01z0PkJXm7Yf1+o8yaa27avUfr6nAE8 LyJA== X-Forwarded-Encrypted: i=1; AFNElJ95ar2GHxpyUUp5Q3Ykiue+S481+QntlMsjXkCwdVtBzSvH0rZUJIzASW3d3eMb+b2iN2DmY/kQ4xk7N9s=@vger.kernel.org X-Gm-Message-State: AOJu0Ywr5ner4KCY3rI+XnGCae/okH2APIGo5Fzei0j7XobUmzyWSJTt FStsPy6IDwZI8yPDH7wvGnrLWgeQGZdFT1QD9UMunlqxxgTksXhSb6dn X-Gm-Gg: AeBDieuELSkAsowwQNIdoGhOPrHL+hpXuY0un/iirZfBAzjc9Bt/ycC3xY7zFH+ISQZ HgMgw/kQArypnboMpPqGiNKdrTkyvCR3iKb1qMBK+y2suRWhBAPASFtGAWICweBaA7zgwelAvyt wJA9OahPFy6WOwb2NJFlL4X0eHHhUeyylScEmTbCrSXs+rQEZumv73konO1A3d2PnLzsRgS7x4R nqx83z+UEEXtlRKAA/ZUHGuVEePAje65WTJMtYTq3z4qmyeKGuVpCWHoHO/kxQ7B80uEpm0YnTx QbigJJq0pTyYtqoG7tZu5b5DYRLhCrU0Ykir9xCL4XPuc7UkoFuYJX9/zVZ5ibjC2W7xz4TGrKm d9UdSLE6bM3VOVui/pYHnfLM4cgod2RIlxJ2mGdV3IsC05HabO0NX1bSRT76/1HqN0+NynRh3Oy hP/FRq0he+eIMU+iIeSobJhcU= X-Received: by 2002:a05:6512:3ba5:b0:5a3:c690:b4a6 with SMTP id 2adb3069b0e04-5a4172b71f6mr12764580e87.7.1777141200435; Sat, 25 Apr 2026 11:20:00 -0700 (PDT) Received: from xeon ([188.163.112.56]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a4187e7ad0sm6836577e87.58.2026.04.25.11.19.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 25 Apr 2026 11:19:59 -0700 (PDT) From: Svyatoslav Ryhel To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Sebastian Reichel , Svyatoslav Ryhel , =?UTF-8?q?Jonas=20Schw=C3=B6bel?= Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Subject: [PATCH v1 2/2] power: supply: Add support for Surface RT battery and charger Date: Sat, 25 Apr 2026 21:19:36 +0300 Message-ID: <20260425181940.144028-3-clamor95@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260425181940.144028-1-clamor95@gmail.com> References: <20260425181940.144028-1-clamor95@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 From: Jonas Schw=C3=B6bel Add support for Embedded Controller found in the Microsoft Surface RT and used to monitor battery cell and charger input status and properties. Controller works both for UEFI and APX booting. [wmjb: added POWER_SUPPLY_PROP_CHARGE_NOW support] Signed-off-by: wmjb Signed-off-by: Jonas Schw=C3=B6bel Signed-off-by: Svyatoslav Ryhel --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/surface-rt-ec.c | 415 +++++++++++++++++++++++++++ 3 files changed, 427 insertions(+) create mode 100644 drivers/power/supply/surface-rt-ec.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 4d04de6586ae..13661d3d39b4 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -1168,6 +1168,17 @@ config BATTERY_UG3105 device is off or suspended, the functionality of this driver is limited to reporting capacity only. =20 +config BATTERY_CHARGER_SURFACE_RT + tristate "Battery & Charger driver for Microsoft Surface RT" + depends on I2C && GPIOLIB + help + UEFI/APX driver for the 1st-generation Microsoft Surface RT + battery. Driver supports reading battery properties and + charger status. + + This driver can also be built as a module. If so, the module + will be called surface-rt-ec. + config CHARGER_QCOM_SMB2 tristate "Qualcomm PMI8998 PMIC charger driver" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 3959b974ec84..ebd3beef4c84 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_RN5T618_POWER) +=3D rn5t618_power.o obj-$(CONFIG_BATTERY_ACER_A500) +=3D acer_a500_battery.o obj-$(CONFIG_BATTERY_SURFACE) +=3D surface_battery.o obj-$(CONFIG_CHARGER_SURFACE) +=3D surface_charger.o +obj-$(CONFIG_BATTERY_CHARGER_SURFACE_RT) +=3D surface-rt-ec.o obj-$(CONFIG_BATTERY_UG3105) +=3D ug3105_battery.o obj-$(CONFIG_CHARGER_QCOM_SMB2) +=3D qcom_smbx.o obj-$(CONFIG_FUEL_GAUGE_MM8013) +=3D mm8013.o diff --git a/drivers/power/supply/surface-rt-ec.c b/drivers/power/supply/su= rface-rt-ec.c new file mode 100644 index 000000000000..30e3cc0dc258 --- /dev/null +++ b/drivers/power/supply/surface-rt-ec.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register Addresses (B=3Dbyte; W=3Dword; S=3Dstring) */ +#define REGB_STATUS 0x02 +#define REGW_VOLTAGE_NOW 0x20 +#define REGW_CURRENT_NOW 0x24 +#define REGW_CAPACITY 0x28 +#define REGW_CHARGE_NOW 0x2a +#define REGW_CHARGE_FULL 0x2c +#define REGW_CYCLE_COUNT 0x3a +#define REGW_CHARGE_FULL_DESIGN 0x3c +#define REGW_VOLTAGE_MAX_DESIGN 0x3e +#define REGW_SERIAL_NUMBER 0x44 +#define REGS_MANUFACTURER 0x46 +#define REGS_MODEL_NAME 0x52 +#define REGS_TECHNOLOGY 0x5a +#define REGB_ONLINE 0x67 + +struct srt_ec_device { + struct i2c_client *client; + + struct power_supply *bat; + struct power_supply *psy; + + struct gpio_desc *enable_gpiod; + struct delayed_work poll_work; + + unsigned int technology; + unsigned int capacity; + + const char *serial; + char manufacturer[13]; + char model_name[10]; +}; + +static const enum power_supply_property srt_bat_power_supply_props[] =3D { + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_SERIAL_NUMBER, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +static const enum power_supply_property srt_psy_power_supply_props[] =3D { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, +}; + +static int srt_bat_get_string(struct i2c_client *client, char *buf, u8 reg) +{ + struct i2c_msg msg[2]; + + msg[0].addr =3D client->addr; + msg[0].flags =3D 0; + msg[0].buf =3D ® + msg[0].len =3D 1; + + msg[1].addr =3D client->addr; + msg[1].flags =3D I2C_M_RD; + msg[1].buf =3D buf; + + switch (reg) { + case REGS_MANUFACTURER: + msg[1].len =3D 12; + break; + + case REGS_MODEL_NAME: + msg[1].len =3D 9; + break; + + case REGS_TECHNOLOGY: + msg[1].len =3D 4; + break; + + default: + return -EINVAL; + } + + return i2c_transfer(client->adapter, msg, 2); +} + +static int srt_bat_get_value(struct i2c_client *client, int reg, int *val) +{ + int ret; + + switch (reg) { + case REGW_CHARGE_NOW: + case REGW_CHARGE_FULL_DESIGN: + case REGW_CHARGE_FULL: + case REGW_VOLTAGE_MAX_DESIGN: + case REGW_VOLTAGE_NOW: + ret =3D i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + *val =3D ret * 1000; + break; + + case REGW_CURRENT_NOW: + ret =3D i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + *val =3D (s16)ret * 1000; + break; + + case REGW_CAPACITY: + case REGW_CYCLE_COUNT: + ret =3D i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + *val =3D ret; + break; + + case REGB_STATUS: + ret =3D i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + return ret; + + if (ret & BIT(0)) + *val =3D POWER_SUPPLY_STATUS_CHARGING; + else + *val =3D POWER_SUPPLY_STATUS_DISCHARGING; + break; + + case REGB_ONLINE: + ret =3D i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + return ret; + + *val =3D (ret & BIT(1)) >> 1; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int srt_bat_power_supply_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct srt_ec_device *srt =3D power_supply_get_drvdata(psy); + struct i2c_client *client =3D srt->client; + int ret =3D 0; + + switch (psp) { + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval =3D srt->manufacturer; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval =3D srt->model_name; + break; + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + val->strval =3D srt->serial; + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret =3D srt_bat_get_value(client, REGW_CAPACITY, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret =3D srt_bat_get_value(client, REGW_CHARGE_NOW, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret =3D srt_bat_get_value(client, REGW_CHARGE_FULL, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret =3D srt_bat_get_value(client, REGW_CHARGE_FULL_DESIGN, + &val->intval); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret =3D srt_bat_get_value(client, REGW_CURRENT_NOW, &val->intval); + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + ret =3D srt_bat_get_value(client, REGW_CYCLE_COUNT, &val->intval); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval =3D 1; + break; + case POWER_SUPPLY_PROP_ONLINE: + ret =3D srt_bat_get_value(client, REGB_ONLINE, &val->intval); + break; + case POWER_SUPPLY_PROP_STATUS: + if (srt->capacity < 100) + ret =3D srt_bat_get_value(client, REGB_STATUS, &val->intval); + else + val->intval =3D POWER_SUPPLY_STATUS_FULL; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval =3D srt->technology; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + ret =3D srt_bat_get_value(client, REGW_VOLTAGE_MAX_DESIGN, + &val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret =3D srt_bat_get_value(client, REGW_VOLTAGE_NOW, &val->intval); + break; + default: + return -EINVAL; + } + + return ret; +} + +static int srt_psy_power_supply_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct srt_ec_device *srt =3D power_supply_get_drvdata(psy); + struct i2c_client *client =3D srt->client; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_PRESENT: + ret =3D i2c_smbus_read_byte_data(client, REGB_ONLINE); + if (ret < 0) + return ret; + + val->intval =3D ret & BIT(0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void srt_bat_poll_work(struct work_struct *work) +{ + struct srt_ec_device *srt =3D + container_of(work, struct srt_ec_device, poll_work.work); + int ret, capacity; + + ret =3D srt_bat_get_value(srt->client, REGW_CAPACITY, &capacity); + if (!ret && capacity !=3D srt->capacity) { + srt->capacity =3D capacity; + power_supply_changed(srt->bat); + } + + /* continuously send uevent notification */ + schedule_delayed_work(&srt->poll_work, 30 * HZ); +} + +static irqreturn_t srt_psy_detect_irq(int irq, void *dev_id) +{ + struct srt_ec_device *srt =3D dev_id; + + power_supply_changed(srt->psy); + + return IRQ_HANDLED; +} + +static const struct power_supply_desc srt_bat_power_supply_desc =3D { + .name =3D "surface-rt-battery", + .type =3D POWER_SUPPLY_TYPE_BATTERY, + .properties =3D srt_bat_power_supply_props, + .num_properties =3D ARRAY_SIZE(srt_bat_power_supply_props), + .get_property =3D srt_bat_power_supply_get_property, + .external_power_changed =3D power_supply_changed, +}; + +static const struct power_supply_desc srt_psy_power_supply_desc =3D { + .name =3D "surface-rt-ac-adapter", + .type =3D POWER_SUPPLY_TYPE_MAINS, + .properties =3D srt_psy_power_supply_props, + .num_properties =3D ARRAY_SIZE(srt_psy_power_supply_props), + .get_property =3D srt_psy_power_supply_get_property, +}; + +static char *battery_supplied_to[] =3D { "surface-rt-battery" }; + +static int srt_ec_probe(struct i2c_client *client) +{ + struct power_supply_config bat_cfg =3D {}; + struct power_supply_config psy_cfg =3D {}; + struct device *dev =3D &client->dev; + struct srt_ec_device *srt; + char str_buf[4]; + int ret; + + srt =3D devm_kzalloc(dev, sizeof(*srt), GFP_KERNEL); + if (!srt) + return -ENOMEM; + + i2c_set_clientdata(client, srt); + srt->client =3D client; + + srt->enable_gpiod =3D devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(srt->enable_gpiod)) + return dev_err_probe(dev, PTR_ERR(srt->enable_gpiod), + "failed to get enable gpio\n"); + + /* wait till EC is ready */ + usleep_range(1000, 1500); + + ret =3D i2c_smbus_read_word_data(client, REGW_SERIAL_NUMBER); + if (ret < 0) + return ret; + + srt->serial =3D devm_kasprintf(dev, GFP_KERNEL, "%04x", ret); + + ret =3D srt_bat_get_string(client, srt->manufacturer, REGS_MANUFACTURER); + if (ret < 0) + return ret; + + ret =3D srt_bat_get_string(client, srt->model_name, REGS_MODEL_NAME); + if (ret < 0) + return ret; + + ret =3D srt_bat_get_string(client, str_buf, REGS_TECHNOLOGY); + if (ret < 0) + return ret; + + if (!strncmp(str_buf, "LION", 4)) + srt->technology =3D POWER_SUPPLY_TECHNOLOGY_LION; + else + srt->technology =3D POWER_SUPPLY_TECHNOLOGY_UNKNOWN; + + bat_cfg.drv_data =3D srt; + bat_cfg.fwnode =3D dev_fwnode(dev); + + srt->bat =3D devm_power_supply_register(dev, &srt_bat_power_supply_desc, + &bat_cfg); + if (IS_ERR(srt->bat)) + return dev_err_probe(dev, PTR_ERR(srt->bat), + "failed to register battery power supply\n"); + + psy_cfg.drv_data =3D srt; + psy_cfg.fwnode =3D dev_fwnode(dev); + psy_cfg.supplied_to =3D battery_supplied_to; + psy_cfg.num_supplicants =3D ARRAY_SIZE(battery_supplied_to); + + srt->psy =3D devm_power_supply_register(dev, &srt_psy_power_supply_desc, + &psy_cfg); + if (IS_ERR(srt->psy)) + return dev_err_probe(dev, PTR_ERR(srt->psy), + "failed to register AC power supply\n"); + + ret =3D devm_request_threaded_irq(dev, client->irq, NULL, srt_psy_detect_= irq, + IRQF_ONESHOT, client->name, srt); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to request interrupt\n"); + + ret =3D devm_delayed_work_autocancel(dev, &srt->poll_work, srt_bat_poll_w= ork); + if (ret < 0) + return ret; + + schedule_delayed_work(&srt->poll_work, HZ); + + return 0; +} + +static int srt_ec_suspend(struct device *dev) +{ + struct srt_ec_device *srt =3D dev_get_drvdata(dev); + + cancel_delayed_work_sync(&srt->poll_work); + + return 0; +} + +static int srt_ec_resume(struct device *dev) +{ + struct srt_ec_device *srt =3D dev_get_drvdata(dev); + + schedule_delayed_work(&srt->poll_work, HZ); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(srt_ec_pm_ops, srt_ec_suspend, srt_ec_resu= me); + +static const struct of_device_id srt_ec_of_match[] =3D { + { .compatible =3D "microsoft,surface-rt-ec" }, + { } +}; +MODULE_DEVICE_TABLE(of, srt_ec_of_match); + +static struct i2c_driver srt_ec_driver =3D { + .driver =3D { + .name =3D "surface-rt-ec", + .of_match_table =3D srt_ec_of_match, + .pm =3D &srt_ec_pm_ops, + }, + .probe =3D srt_ec_probe, +}; +module_i2c_driver(srt_ec_driver); + +MODULE_AUTHOR("Jonas Schw=C3=B6bel "); +MODULE_DESCRIPTION("Surface RT Embedded Controller driver"); +MODULE_LICENSE("GPL"); --=20 2.51.0