Received: by 2002:ab2:7b86:0:b0:1f7:5705:b850 with SMTP id q6csp1051264lqh; Sun, 5 May 2024 13:57:28 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWzGW0+DZqfJfD3gU72/H1maeJgXNG3pfozBeYoQ3+Gm/OCYVk+sN1CeVx494YT5au7BhuSvZy/xANlIe+z5TgosDPy3K5+DASWHFFa/g== X-Google-Smtp-Source: AGHT+IG1EdpeiXCF1+NYDcARVN0KDMqNE36+tdQfO4+m3RAysGGd2kwZvhuNB5o3aaliLOSLZ7Hp X-Received: by 2002:ad4:596a:0:b0:6a0:aaca:ecc with SMTP id eq10-20020ad4596a000000b006a0aaca0eccmr10248367qvb.40.1714942648648; Sun, 05 May 2024 13:57:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1714942648; cv=pass; d=google.com; s=arc-20160816; b=BpiM2pP3ain10V9hYqQ7eLGXPTa7P0SccisfEq8lmrUausElIPd4s4RNOL4qA6CFbB bTG1N78SKaJ3lWuRwJpWXXEJFiPeXkgmqnxxsMm1L2sHB5+XFlWrd2AvnesmkuD0w727 mGXUEV8R9tp29+eDlHW6yBEwwj686zTAR34WfKKqnanZJvybpLye9wKzi9r+oq0r6t/F Vonhkr6ItxHe9AoDbQ/WpRpTnkMwAvLv+lCPrubbhNBC4T8Xh5iA2bPzMDtE+Xwkts5s hf5IX7ce3c9ly2Vzv3dCCBPeKhT5nIqbeTmPVfx4QpmUNUwbqU/+bGwEQPLDdCksmxet scfA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=jqaNo/DpeB+KtYf5vBn674DzjK2F3yUR/YRPATgjioY=; fh=xk9RTArcm315XOKmsKEI7McPdt+6dtl+QycaoTzsAsM=; b=0Ylmcms0sEZUZHtzAD2reuhH9IyNQ0U65/qyG/LNaMHK4b2TQFaExRWQQtlifwAAtj NuJxwqhsdLFAIE39dydSm6E8kOgJdFGuIg5cwt1TqXYfSV59KLDjykbYf7EMaJ0QiA0q e71yRxMA/yw+Tj75M/j8/NvjBueHCN8OPhDb++mTmoX+oc/17BlrlS667g/eV046c1xo PrvZLl4qHnaJAJ+22di4HDsr3llDxhabUCzNB/dX5uJJdmCk/b1xBrg6DqwPXN760qvA YV9aiqt1t4x062o7Jo3CelxMpQUcj6LCMWBs8HVh5zSqBmYoAFoB0gKx0RSqEGMQCTgF BR1g==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@weissschuh.net header.s=mail header.b=DlRuY0kr; arc=pass (i=1 spf=pass spfdomain=weissschuh.net dkim=pass dkdomain=weissschuh.net); spf=pass (google.com: domain of linux-kernel+bounces-169145-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-169145-linux.lists.archive=gmail.com@vger.kernel.org" Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id jk11-20020ad45d4b000000b006a0cdbcec31si8069762qvb.225.2024.05.05.13.57.28 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 May 2024 13:57:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-169145-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@weissschuh.net header.s=mail header.b=DlRuY0kr; arc=pass (i=1 spf=pass spfdomain=weissschuh.net dkim=pass dkdomain=weissschuh.net); spf=pass (google.com: domain of linux-kernel+bounces-169145-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-169145-linux.lists.archive=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 543601C211EC for ; Sun, 5 May 2024 20:57:28 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5EDC6762C1; Sun, 5 May 2024 20:57:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b="DlRuY0kr" Received: from todd.t-8ch.de (todd.t-8ch.de [159.69.126.157]) (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 B43CF6DCF5; Sun, 5 May 2024 20:57:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.69.126.157 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714942631; cv=none; b=GIMyGHITKA0hIMdICA/3Y8LxNp2iRII0gVs8slli6YN4+f0qJJdJ/yEvAiCNUHlWM3ktO/Lvpo+B/4ZqoJ9dpHXWlNAvEtCsuHqu0HHF5uy9+INCgb69PpBREVTX5PeK3SxlR9CLm4QzjHf5kc6aooRpABqti0pGwFCe0TYyAp4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714942631; c=relaxed/simple; bh=K/HTrL3dabNlERTmoHaPw5pHxjJqcQ+Gsw+F4RjFMP0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tJGwgBd0sYHu4WFT/fLl7Udx25RfulzNn10C0o1NPZXZd0rY2aNXSy6n9e51Gb1sgW2TNOn7QBWyuO4Bk42SjXLg8Q9KhDvEye7l3YLRVQCXQdd5NLjyQCxvE5UgxVHDiPs0jworj1Qd1GDV5QTLq0wTaRxPaI9cpXGxTledh+8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=weissschuh.net; spf=pass smtp.mailfrom=weissschuh.net; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b=DlRuY0kr; arc=none smtp.client-ip=159.69.126.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=weissschuh.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=weissschuh.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=weissschuh.net; s=mail; t=1714942625; bh=K/HTrL3dabNlERTmoHaPw5pHxjJqcQ+Gsw+F4RjFMP0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DlRuY0kruFOFHwKvP0N13UyDTwS3AxmEGenfQA7/GcAiNW89WUOVe9y4kf7KGai9y 69enMtp0qr9LDruumOdm93IYltTXiHit3ydLwQ5hutz976WgppFbwJ6wz84Nd403yI xIaD7mVR7Hh4+/ozxkbQi4WvGXrwTLsv7vjVDA4E= From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= Date: Sun, 05 May 2024 22:56:35 +0200 Subject: [PATCH 2/2] platform/chrome: cros_ec_framework_laptop: implement battery charge thresholds 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: 8bit Message-Id: <20240505-cros_ec-framework-v1-2-402662d6276b@weissschuh.net> References: <20240505-cros_ec-framework-v1-0-402662d6276b@weissschuh.net> In-Reply-To: <20240505-cros_ec-framework-v1-0-402662d6276b@weissschuh.net> To: Lee Jones , Benson Leung , Guenter Roeck , Tzung-Bi Shih Cc: linux-kernel@vger.kernel.org, chrome-platform@lists.linux.dev, Mario Limonciello , "Dustin L. Howett" , Sebastian Reichel , linux-pm@vger.kernel.org, =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1714942624; l=4885; i=linux@weissschuh.net; s=20221212; h=from:subject:message-id; bh=K/HTrL3dabNlERTmoHaPw5pHxjJqcQ+Gsw+F4RjFMP0=; b=qclKK7GMQPcv8He6mcRlgvXNLOvtIzmaV2pNR/4ps1X7RD1Hy7U0/BTNHLezsHDjaCFfk2tMd Mg7ujhtt64/Ae0d6OGF/53YdoO/4E8BBylcqgUQ9bQZn2a2989pm/pJ X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=KcycQgFPX2wGR5azS7RhpBqedglOZVgRPfdFSPB1LNw= Make use of the non-standard EC command FW_EC_CMD_CHARGE_LIMIT_CONTROL to implement the standard sysfs attribute "charge_control_end_threshold". Tested on a Framework 13 AMD with firmware version 3.05. Signed-off-by: Thomas Weißschuh --- drivers/platform/chrome/cros_ec_framework_laptop.c | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_framework_laptop.c b/drivers/platform/chrome/cros_ec_framework_laptop.c index 8a8bf039fa9c..2693a80df38f 100644 --- a/drivers/platform/chrome/cros_ec_framework_laptop.c +++ b/drivers/platform/chrome/cros_ec_framework_laptop.c @@ -4,18 +4,119 @@ * * Copyright (C) 2024 Thomas Weißschuh */ +#include #include #include #include +#include #include #include #define DRV_NAME "cros-ec-framework" +#define FW_EC_CMD_CHARGE_LIMIT_CONTROL 0x3E03 + +#define FW_EC_CHG_LIMIT_DISABLE BIT(0) +#define FW_EC_CHG_LIMIT_SET BIT(1) +#define FW_EC_CHG_LIMIT_GET BIT(3) +#define FW_EC_CHG_LIMIT_OVERRIDE BIT(7) + struct cros_fwk_priv { struct cros_ec_device *cros_ec; + struct acpi_battery_hook battery_hook; + struct device_attribute end_threshold; +}; + +union cros_fwk_data { + struct { + u8 modes; + u8 max_percentage; + u8 min_percentage; /* not implemented in the EC */ + } __packed req; + struct { + u8 max_percentage; + u8 min_percentage; + } __packed resp; }; +static int cros_fwk_send_cmd(struct cros_ec_device *cros_ec, union cros_fwk_data *arg) +{ + int ret; + struct { + struct cros_ec_command msg; + union cros_fwk_data data; + } __packed buf = { + .msg = { + .version = 0, + .command = FW_EC_CMD_CHARGE_LIMIT_CONTROL, + .insize = sizeof(arg->resp), + .outsize = sizeof(arg->req), + }, + .data.req = arg->req + }; + + ret = cros_ec_cmd_xfer_status(cros_ec, &buf.msg); + if (ret < 0) + return ret; + + arg->resp = buf.data.resp; + + return 0; +} + +static ssize_t charge_control_end_threshold_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cros_fwk_priv *priv = container_of(attr, struct cros_fwk_priv, end_threshold); + union cros_fwk_data arg = { }; + int ret; + + arg.req.modes = FW_EC_CHG_LIMIT_GET; + ret = cros_fwk_send_cmd(priv->cros_ec, &arg); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%u\n", (unsigned int)arg.resp.max_percentage); +} + +static ssize_t charge_control_end_threshold_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cros_fwk_priv *priv = container_of(attr, struct cros_fwk_priv, end_threshold); + union cros_fwk_data arg = { }; + int ret, val; + + ret = kstrtoint(buf, 10, &val); + if (ret < 0) + return ret; + if (val < 1 || val > 100) + return -EINVAL; + + arg.req.modes = FW_EC_CHG_LIMIT_SET; + arg.req.max_percentage = val; + ret = cros_fwk_send_cmd(priv->cros_ec, &arg); + if (ret < 0) + return ret; + + return count; +} + +static int cros_fwk_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct cros_fwk_priv *priv = container_of(hook, struct cros_fwk_priv, battery_hook); + + return device_create_file(&battery->dev, &priv->end_threshold); +} + +static int cros_fwk_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct cros_fwk_priv *priv = container_of(hook, struct cros_fwk_priv, battery_hook); + + device_remove_file(&battery->dev, &priv->end_threshold); + + return 0; +} + static int cros_fwk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -28,6 +129,24 @@ static int cros_fwk_probe(struct platform_device *pdev) return -ENOMEM; priv->cros_ec = cros_ec; + priv->end_threshold = (struct device_attribute)__ATTR_RW(charge_control_end_threshold); + + priv->battery_hook.name = dev_name(dev), + priv->battery_hook.add_battery = cros_fwk_add_battery, + priv->battery_hook.remove_battery = cros_fwk_remove_battery, + + battery_hook_register(&priv->battery_hook); + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int cros_fwk_remove(struct platform_device *pdev) +{ + struct cros_fwk_priv *priv = platform_get_drvdata(pdev); + + battery_hook_unregister(&priv->battery_hook); platform_set_drvdata(pdev, priv); @@ -42,6 +161,7 @@ static const struct platform_device_id cros_fwk_id[] = { static struct platform_driver cros_fwk_driver = { .driver.name = DRV_NAME, .probe = cros_fwk_probe, + .remove = cros_fwk_remove, .id_table = cros_fwk_id, }; -- 2.45.0