From: Junhao Xie <bigfoot@classfun.cn>
To: devicetree@vger.kernel.org, linux-hwmon@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org,
linux-pm@vger.kernel.org, linux-rtc@vger.kernel.org,
linux-watchdog@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org
Cc: Jean Delvare <jdelvare@suse.com>,
Guenter Roeck <linux@roeck-us.net>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Pavel Machek <pavel@ucw.cz>,
Lee Jones <lee@kernel.org>, Sebastian Reichel <sre@kernel.org>,
Alexandre Belloni <alexandre.belloni@bootlin.com>,
Wim Van Sebroeck <wim@linux-watchdog.org>,
Heiko Stuebner <heiko@sntech.de>, Chukun Pan <amadeus@jmu.edu.cn>,
Junhao Xie <bigfoot@classfun.cn>
Subject: [PATCH 4/9] power: supply: photonicat-supply: Add Photonicat PMU battery and charger
Date: Fri, 6 Sep 2024 17:36:25 +0800 [thread overview]
Message-ID: <20240906093630.2428329-5-bigfoot@classfun.cn> (raw)
In-Reply-To: <20240906093630.2428329-1-bigfoot@classfun.cn>
Photonicat PMU supports battery and charger power supply.
The MCU only provides voltage meter.
Signed-off-by: Junhao Xie <bigfoot@classfun.cn>
---
drivers/power/supply/Kconfig | 12 ++
drivers/power/supply/Makefile | 1 +
drivers/power/supply/photonicat-supply.c | 250 +++++++++++++++++++++++
3 files changed, 263 insertions(+)
create mode 100644 drivers/power/supply/photonicat-supply.c
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index bcfa63fb9f1e..4d2fcf568810 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -455,6 +455,18 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config PHOTONICAT_POWER
+ tristate "Photonicat PMU power supply driver"
+ depends on MFD_PHOTONICAT_PMU
+ help
+ Photonicat PMU supports battery and charger power supply.
+ The MCU only provides voltage meter.
+
+ Say Y here to enable support for Photonicat PMU power supply.
+
+ This driver can also be built as a module. If so, the module will be
+ called photonicat-supply.
+
config BATTERY_RX51
tristate "Nokia RX-51 (N900) battery driver"
depends on TWL4030_MADC
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 8dcb41545317..81ada9bb6438 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_PHOTONICAT_POWER) += photonicat-supply.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
diff --git a/drivers/power/supply/photonicat-supply.c b/drivers/power/supply/photonicat-supply.c
new file mode 100644
index 000000000000..e6861a3904fe
--- /dev/null
+++ b/drivers/power/supply/photonicat-supply.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Junhao Xie <bigfoot@classfun.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/mfd/photonicat-pmu.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+enum pcat_supply_type {
+ PCAT_SUPPLY_BATTERY,
+ PCAT_SUPPLY_CHARGER,
+};
+
+struct pcat_supply {
+ struct device *dev;
+ struct pcat_pmu *pmu;
+ struct notifier_block nb;
+ struct power_supply *psy;
+ struct power_supply_desc desc;
+ struct power_supply_battery_info *bat_info;
+ enum pcat_supply_type type;
+ u16 supply_microvolt;
+ struct completion initial_report;
+};
+
+static int pcat_pmu_get_capacity(struct pcat_supply *supply)
+{
+ int uv;
+
+ if (supply->type != PCAT_SUPPLY_BATTERY)
+ return 0;
+ uv = supply->supply_microvolt * 1000;
+
+ return power_supply_batinfo_ocv2cap(supply->bat_info, uv, 20);
+}
+
+static int pcat_pmu_get_energy(struct pcat_supply *supply)
+{
+ int capacity;
+
+ if (supply->type != PCAT_SUPPLY_BATTERY)
+ return 0;
+ capacity = pcat_pmu_get_capacity(supply);
+ if (capacity < 0)
+ return 0;
+
+ return supply->bat_info->energy_full_design_uwh / 100 * capacity;
+}
+
+static int pcat_pmu_get_status(struct pcat_supply *supply)
+{
+ if (supply->type != PCAT_SUPPLY_BATTERY)
+ return 0;
+
+ if (pcat_pmu_get_capacity(supply) < 100) {
+ if (power_supply_am_i_supplied(supply->psy))
+ return POWER_SUPPLY_STATUS_CHARGING;
+ else
+ return POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+
+ return POWER_SUPPLY_STATUS_FULL;
+}
+
+static int pcat_pmu_get_supply_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pcat_supply *supply = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = pcat_pmu_get_capacity(supply);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = supply->supply_microvolt > 1000;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ val->intval = supply->bat_info->energy_full_design_uwh;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ val->intval = pcat_pmu_get_energy(supply);
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = pcat_pmu_get_status(supply);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = supply->bat_info->voltage_max_design_uv;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+ val->intval = supply->bat_info->voltage_min_design_uv;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = supply->supply_microvolt * 1000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property pcat_charger_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property pcat_battery_props[] = {
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static int pcat_supply_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct pcat_supply *supply = container_of(nb, struct pcat_supply, nb);
+ struct pcat_data_cmd_status *status = pcat_data_get_data(data);
+
+ if (action != PCAT_CMD_STATUS_REPORT)
+ return NOTIFY_DONE;
+
+ switch (supply->type) {
+ case PCAT_SUPPLY_BATTERY:
+ supply->supply_microvolt = status->battery_microvolt;
+ break;
+ case PCAT_SUPPLY_CHARGER:
+ supply->supply_microvolt = status->charger_microvolt;
+ break;
+ }
+
+ complete(&supply->initial_report);
+
+ return NOTIFY_DONE;
+}
+
+static int pcat_supply_probe(struct platform_device *pdev)
+{
+ int ret;
+ const char *label;
+ const char *supply_type;
+ struct device *dev = &pdev->dev;
+ struct pcat_supply *supply;
+ struct power_supply_config psy_cfg = {};
+
+ supply = devm_kzalloc(dev, sizeof(*supply), GFP_KERNEL);
+ if (!supply)
+ return -ENOMEM;
+
+ supply->dev = dev;
+ supply->pmu = dev_get_drvdata(dev->parent);
+ supply->nb.notifier_call = pcat_supply_notify;
+ init_completion(&supply->initial_report);
+ psy_cfg.drv_data = supply;
+ psy_cfg.of_node = dev->of_node;
+ platform_set_drvdata(pdev, supply);
+
+ ret = of_property_read_string(dev->of_node, "type", &supply_type);
+ if (ret)
+ return dev_err_probe(dev, ret, "No supply type property\n");
+
+ ret = of_property_read_string(dev->of_node, "label", &label);
+ if (ret)
+ return dev_err_probe(dev, ret, "No label property\n");
+
+ if (!strcmp(supply_type, "battery")) {
+ supply->type = PCAT_SUPPLY_BATTERY;
+ supply->desc.type = POWER_SUPPLY_TYPE_BATTERY;
+ supply->desc.properties = pcat_battery_props;
+ supply->desc.num_properties = ARRAY_SIZE(pcat_battery_props);
+ } else if (!strcmp(supply_type, "charger")) {
+ supply->type = PCAT_SUPPLY_CHARGER;
+ supply->desc.type = POWER_SUPPLY_TYPE_MAINS;
+ supply->desc.properties = pcat_charger_props;
+ supply->desc.num_properties = ARRAY_SIZE(pcat_charger_props);
+ } else
+ return dev_err_probe(dev, -EINVAL, "Unknown supply type %s\n",
+ supply_type);
+
+ ret = pcat_pmu_register_notify(supply->pmu, &supply->nb);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(&supply->initial_report,
+ msecs_to_jiffies(3000))) {
+ ret = dev_err_probe(dev, -ETIMEDOUT,
+ "timeout waiting for initial report\n");
+ goto error;
+ }
+
+ dev_info(dev, "Voltage: %u mV\n", supply->supply_microvolt);
+
+ supply->desc.name = label;
+ supply->desc.get_property = pcat_pmu_get_supply_property;
+
+ supply->psy = devm_power_supply_register(dev, &supply->desc, &psy_cfg);
+ if (IS_ERR(supply->psy)) {
+ ret = PTR_ERR(supply->psy);
+ dev_err_probe(dev, ret, "Failed to register supply\n");
+ goto error;
+ }
+
+ if (supply->type == PCAT_SUPPLY_BATTERY) {
+ ret = power_supply_get_battery_info(supply->psy,
+ &supply->bat_info);
+ if (ret) {
+ dev_err_probe(dev, ret, "Unable to get battery info\n");
+ goto error;
+ }
+ }
+
+ return 0;
+error:
+ pcat_pmu_unregister_notify(supply->pmu, &supply->nb);
+ return ret;
+}
+
+static void pcat_supply_remove(struct platform_device *pdev)
+{
+ struct pcat_supply *supply = platform_get_drvdata(pdev);
+
+ pcat_pmu_unregister_notify(supply->pmu, &supply->nb);
+}
+
+static const struct of_device_id pcat_supply_dt_ids[] = {
+ { .compatible = "ariaboard,photonicat-pmu-supply", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pcat_supply_dt_ids);
+
+static struct platform_driver pcat_supply_driver = {
+ .driver = {
+ .name = "photonicat-supply",
+ .of_match_table = pcat_supply_dt_ids,
+ },
+ .probe = pcat_supply_probe,
+ .remove = pcat_supply_remove,
+};
+module_platform_driver(pcat_supply_driver);
+
+MODULE_AUTHOR("Junhao Xie <bigfoot@classfun.cn>");
+MODULE_DESCRIPTION("Photonicat PMU Power Supply");
+MODULE_LICENSE("GPL");
--
2.46.0
next prev parent reply other threads:[~2024-09-06 9:38 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-06 9:36 [PATCH 0/9] Introduce Photonicat power management MCU driver Junhao Xie
2024-09-06 9:36 ` [PATCH 1/9] mfd: Add driver for Photonicat power management MCU Junhao Xie
2024-09-06 9:43 ` Krzysztof Kozlowski
2024-09-06 10:40 ` Junhao Xie
2024-09-07 8:10 ` Markus Elfring
2024-09-07 14:46 ` Junhao Xie
2024-09-07 8:44 ` Markus Elfring
2024-09-07 14:33 ` Junhao Xie
2024-09-08 8:14 ` Krzysztof Kozlowski
2024-09-12 7:55 ` Lee Jones
2024-09-06 9:36 ` [PATCH 2/9] power: reset: add Photonicat PMU poweroff driver Junhao Xie
2024-09-06 9:44 ` Krzysztof Kozlowski
2024-09-06 10:05 ` Junhao Xie
2024-09-06 9:36 ` [PATCH 3/9] watchdog: Add Photonicat PMU watchdog driver Junhao Xie
2024-09-06 11:52 ` Guenter Roeck
2024-09-06 13:41 ` Junhao Xie
2024-09-06 9:36 ` Junhao Xie [this message]
2024-09-06 9:36 ` [PATCH 5/9] rtc: Add Photonicat PMU real-time clock Junhao Xie
2024-09-06 9:36 ` [PATCH 6/9] hwmon: Add support for Photonicat PMU board temperature sensor Junhao Xie
2024-09-06 11:41 ` Guenter Roeck
2024-09-06 13:49 ` Junhao Xie
2024-09-06 14:33 ` Guenter Roeck
2024-09-06 9:36 ` [PATCH 7/9] leds: add Photonicat PMU LED driver Junhao Xie
2024-10-02 15:35 ` Lee Jones
2024-11-08 3:48 ` Junhao Xie
2024-09-06 9:36 ` [PATCH 8/9] dt-bindings: Add documentation for Photonicat PMU Junhao Xie
2024-09-06 9:51 ` Krzysztof Kozlowski
2024-09-07 14:27 ` Junhao Xie
2024-09-08 8:13 ` Krzysztof Kozlowski
2024-09-06 9:36 ` [PATCH 9/9] arm64: dts: rockchip: add Photonicat PMU support for Ariaboard Photonicat Junhao Xie
2024-09-06 9:53 ` Krzysztof Kozlowski
2024-09-06 13:56 ` Junhao Xie
2024-09-06 9:45 ` [PATCH 0/9] Introduce Photonicat power management MCU driver Krzysztof Kozlowski
2024-09-06 10:20 ` Junhao Xie
2024-09-08 9:30 ` Chukun Pan
2024-09-11 6:23 ` Junhao Xie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240906093630.2428329-5-bigfoot@classfun.cn \
--to=bigfoot@classfun.cn \
--cc=alexandre.belloni@bootlin.com \
--cc=amadeus@jmu.edu.cn \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=heiko@sntech.de \
--cc=jdelvare@suse.com \
--cc=krzk+dt@kernel.org \
--cc=lee@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=linux-rtc@vger.kernel.org \
--cc=linux-watchdog@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=pavel@ucw.cz \
--cc=robh@kernel.org \
--cc=sre@kernel.org \
--cc=wim@linux-watchdog.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox