aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 12:19:39 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 12:19:39 +1000
commitd14a2b61db484aefd480ed197af4c2c2e231d87d (patch)
tree0ea1b3db3566ddacd116c42a51a12092e9a08359
parent652d6395480963d54092238fc268e8ae67c10cb5 (diff)
parentb5910897b2eee54a8dc3d354e7ad56cef62e1b3d (diff)
Merge remote-tracking branch 'battery/for-next'
-rw-r--r--Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt27
-rw-r--r--drivers/power/supply/Kconfig7
-rw-r--r--drivers/power/supply/Makefile1
-rw-r--r--drivers/power/supply/axp20x_usb_power.c2
-rw-r--r--drivers/power/supply/cpcap-charger.c83
-rw-r--r--drivers/power/supply/ltc3651-charger.c210
-rw-r--r--drivers/power/supply/power_supply_core.c24
-rw-r--r--drivers/power/supply/power_supply_sysfs.c2
-rw-r--r--include/linux/power_supply.h15
9 files changed, 327 insertions, 44 deletions
diff --git a/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt b/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt
new file mode 100644
index 000000000000..71f2840e8209
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt
@@ -0,0 +1,27 @@
+ltc3651-charger
+
+Required properties:
+ - compatible: "lltc,ltc3651-charger"
+ - lltc,acpr-gpios: Connect to ACPR output. See remark below.
+
+Optional properties:
+ - lltc,fault-gpios: Connect to FAULT output. See remark below.
+ - lltc,chrg-gpios: Connect to CHRG output. See remark below.
+
+The ltc3651 outputs are open-drain type and active low. The driver assumes the
+GPIO reports "active" when the output is asserted, so if the pins have been
+connected directly, the GPIO flags should be set to active low also.
+
+The driver will attempt to aquire interrupts for all GPIOs to detect changes in
+line state. If the system is not capabale of providing interrupts, the driver
+cannot report changes and userspace will need to periodically read the sysfs
+attributes to detect changes.
+
+Example:
+
+ charger: battery-charger {
+ compatible = "lltc,ltc3651-charger";
+ lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>;
+ lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>;
+ lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>;
+ };
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 86f40bf37c34..30598aa05e21 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -408,6 +408,13 @@ config CHARGER_MANAGER
runtime and in suspend-to-RAM by waking up the system periodically
with help of suspend_again support.
+config CHARGER_LTC3651
+ tristate "LTC3651 charger"
+ depends on GPIOLIB
+ help
+ Say Y to include support for the LTC3651 battery charger which reports
+ its status via GPIO lines.
+
config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index a39126d7a6ce..c5e576f0f0ee 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
+obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index 2397c482656e..44f70dcea61e 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -339,7 +339,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
"VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID", NULL };
static const char * const axp22x_irq_names[] = {
"VBUS_PLUGIN", "VBUS_REMOVAL", NULL };
- static const char * const *irq_names;
+ const char * const *irq_names;
const struct power_supply_desc *usb_power_desc;
int i, irq, ret;
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
index 26a2dc7ac9a2..a798af4471d7 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -38,20 +38,27 @@
#include <linux/iio/consumer.h>
#include <linux/mfd/motorola-cpcap.h>
-/* CPCAP_REG_CRM register bits */
+/*
+ * CPCAP_REG_CRM register bits. For documentation of somewhat similar hardware,
+ * see NXP "MC13783 Power Management and Audio Circuit Users's Guide"
+ * MC13783UG.pdf chapter "8.5 Battery Interface Register Summary". The registers
+ * and values for CPCAP are different, but some of the internal components seem
+ * similar. Also see the Motorola Linux kernel cpcap-regbits.h. CPCAP_REG_CHRGR_1
+ * bits that seem to describe the CRM register.
+ */
#define CPCAP_REG_CRM_UNUSED_641_15 BIT(15) /* 641 = register number */
#define CPCAP_REG_CRM_UNUSED_641_14 BIT(14) /* 641 = register number */
-#define CPCAP_REG_CRM_CHRG_LED_EN BIT(13)
-#define CPCAP_REG_CRM_RVRSMODE BIT(12)
-#define CPCAP_REG_CRM_ICHRG_TR1 BIT(11)
+#define CPCAP_REG_CRM_CHRG_LED_EN BIT(13) /* Charger LED */
+#define CPCAP_REG_CRM_RVRSMODE BIT(12) /* USB VBUS output enable */
+#define CPCAP_REG_CRM_ICHRG_TR1 BIT(11) /* Trickle charge current */
#define CPCAP_REG_CRM_ICHRG_TR0 BIT(10)
-#define CPCAP_REG_CRM_FET_OVRD BIT(9)
-#define CPCAP_REG_CRM_FET_CTRL BIT(8)
-#define CPCAP_REG_CRM_VCHRG3 BIT(7)
+#define CPCAP_REG_CRM_FET_OVRD BIT(9) /* 0 = hardware, 1 = FET_CTRL */
+#define CPCAP_REG_CRM_FET_CTRL BIT(8) /* BPFET 1 if FET_OVRD set */
+#define CPCAP_REG_CRM_VCHRG3 BIT(7) /* Charge voltage bits */
#define CPCAP_REG_CRM_VCHRG2 BIT(6)
#define CPCAP_REG_CRM_VCHRG1 BIT(5)
#define CPCAP_REG_CRM_VCHRG0 BIT(4)
-#define CPCAP_REG_CRM_ICHRG3 BIT(3)
+#define CPCAP_REG_CRM_ICHRG3 BIT(3) /* Charge current bits */
#define CPCAP_REG_CRM_ICHRG2 BIT(2)
#define CPCAP_REG_CRM_ICHRG1 BIT(1)
#define CPCAP_REG_CRM_ICHRG0 BIT(0)
@@ -63,42 +70,50 @@
#define CPCAP_REG_CRM_TR_0A48 CPCAP_REG_CRM_TR(0x2)
#define CPCAP_REG_CRM_TR_0A72 CPCAP_REG_CRM_TR(0x4)
-/* CPCAP_REG_CRM charge voltages */
+/*
+ * CPCAP_REG_CRM charge voltages based on the ADC channel 1 values.
+ * Note that these register bits don't match MC13783UG.pdf VCHRG
+ * register bits.
+ */
#define CPCAP_REG_CRM_VCHRG(val) (((val) & 0xf) << 4)
#define CPCAP_REG_CRM_VCHRG_3V80 CPCAP_REG_CRM_VCHRG(0x0)
#define CPCAP_REG_CRM_VCHRG_4V10 CPCAP_REG_CRM_VCHRG(0x1)
-#define CPCAP_REG_CRM_VCHRG_4V15 CPCAP_REG_CRM_VCHRG(0x2)
-#define CPCAP_REG_CRM_VCHRG_4V20 CPCAP_REG_CRM_VCHRG(0x3)
-#define CPCAP_REG_CRM_VCHRG_4V22 CPCAP_REG_CRM_VCHRG(0x4)
-#define CPCAP_REG_CRM_VCHRG_4V24 CPCAP_REG_CRM_VCHRG(0x5)
-#define CPCAP_REG_CRM_VCHRG_4V26 CPCAP_REG_CRM_VCHRG(0x6)
-#define CPCAP_REG_CRM_VCHRG_4V28 CPCAP_REG_CRM_VCHRG(0x7)
-#define CPCAP_REG_CRM_VCHRG_4V30 CPCAP_REG_CRM_VCHRG(0x8)
-#define CPCAP_REG_CRM_VCHRG_4V32 CPCAP_REG_CRM_VCHRG(0x9)
-#define CPCAP_REG_CRM_VCHRG_4V34 CPCAP_REG_CRM_VCHRG(0xa)
+#define CPCAP_REG_CRM_VCHRG_4V12 CPCAP_REG_CRM_VCHRG(0x2)
+#define CPCAP_REG_CRM_VCHRG_4V15 CPCAP_REG_CRM_VCHRG(0x3)
+#define CPCAP_REG_CRM_VCHRG_4V17 CPCAP_REG_CRM_VCHRG(0x4)
+#define CPCAP_REG_CRM_VCHRG_4V20 CPCAP_REG_CRM_VCHRG(0x5)
+#define CPCAP_REG_CRM_VCHRG_4V23 CPCAP_REG_CRM_VCHRG(0x6)
+#define CPCAP_REG_CRM_VCHRG_4V25 CPCAP_REG_CRM_VCHRG(0x7)
+#define CPCAP_REG_CRM_VCHRG_4V27 CPCAP_REG_CRM_VCHRG(0x8)
+#define CPCAP_REG_CRM_VCHRG_4V30 CPCAP_REG_CRM_VCHRG(0x9)
+#define CPCAP_REG_CRM_VCHRG_4V33 CPCAP_REG_CRM_VCHRG(0xa)
#define CPCAP_REG_CRM_VCHRG_4V35 CPCAP_REG_CRM_VCHRG(0xb)
#define CPCAP_REG_CRM_VCHRG_4V38 CPCAP_REG_CRM_VCHRG(0xc)
#define CPCAP_REG_CRM_VCHRG_4V40 CPCAP_REG_CRM_VCHRG(0xd)
#define CPCAP_REG_CRM_VCHRG_4V42 CPCAP_REG_CRM_VCHRG(0xe)
#define CPCAP_REG_CRM_VCHRG_4V44 CPCAP_REG_CRM_VCHRG(0xf)
-/* CPCAP_REG_CRM charge currents */
+/*
+ * CPCAP_REG_CRM charge currents. These seem to match MC13783UG.pdf
+ * values in "Table 8-3. Charge Path Regulator Current Limit
+ * Characteristics" for the nominal values.
+ */
#define CPCAP_REG_CRM_ICHRG(val) (((val) & 0xf) << 0)
#define CPCAP_REG_CRM_ICHRG_0A000 CPCAP_REG_CRM_ICHRG(0x0)
#define CPCAP_REG_CRM_ICHRG_0A070 CPCAP_REG_CRM_ICHRG(0x1)
-#define CPCAP_REG_CRM_ICHRG_0A176 CPCAP_REG_CRM_ICHRG(0x2)
-#define CPCAP_REG_CRM_ICHRG_0A264 CPCAP_REG_CRM_ICHRG(0x3)
-#define CPCAP_REG_CRM_ICHRG_0A352 CPCAP_REG_CRM_ICHRG(0x4)
-#define CPCAP_REG_CRM_ICHRG_0A440 CPCAP_REG_CRM_ICHRG(0x5)
-#define CPCAP_REG_CRM_ICHRG_0A528 CPCAP_REG_CRM_ICHRG(0x6)
-#define CPCAP_REG_CRM_ICHRG_0A616 CPCAP_REG_CRM_ICHRG(0x7)
-#define CPCAP_REG_CRM_ICHRG_0A704 CPCAP_REG_CRM_ICHRG(0x8)
-#define CPCAP_REG_CRM_ICHRG_0A792 CPCAP_REG_CRM_ICHRG(0x9)
-#define CPCAP_REG_CRM_ICHRG_0A880 CPCAP_REG_CRM_ICHRG(0xa)
-#define CPCAP_REG_CRM_ICHRG_0A968 CPCAP_REG_CRM_ICHRG(0xb)
-#define CPCAP_REG_CRM_ICHRG_1A056 CPCAP_REG_CRM_ICHRG(0xc)
-#define CPCAP_REG_CRM_ICHRG_1A144 CPCAP_REG_CRM_ICHRG(0xd)
-#define CPCAP_REG_CRM_ICHRG_1A584 CPCAP_REG_CRM_ICHRG(0xe)
+#define CPCAP_REG_CRM_ICHRG_0A177 CPCAP_REG_CRM_ICHRG(0x2)
+#define CPCAP_REG_CRM_ICHRG_0A266 CPCAP_REG_CRM_ICHRG(0x3)
+#define CPCAP_REG_CRM_ICHRG_0A355 CPCAP_REG_CRM_ICHRG(0x4)
+#define CPCAP_REG_CRM_ICHRG_0A443 CPCAP_REG_CRM_ICHRG(0x5)
+#define CPCAP_REG_CRM_ICHRG_0A532 CPCAP_REG_CRM_ICHRG(0x6)
+#define CPCAP_REG_CRM_ICHRG_0A621 CPCAP_REG_CRM_ICHRG(0x7)
+#define CPCAP_REG_CRM_ICHRG_0A709 CPCAP_REG_CRM_ICHRG(0x8)
+#define CPCAP_REG_CRM_ICHRG_0A798 CPCAP_REG_CRM_ICHRG(0x9)
+#define CPCAP_REG_CRM_ICHRG_0A886 CPCAP_REG_CRM_ICHRG(0xa)
+#define CPCAP_REG_CRM_ICHRG_0A975 CPCAP_REG_CRM_ICHRG(0xb)
+#define CPCAP_REG_CRM_ICHRG_1A064 CPCAP_REG_CRM_ICHRG(0xc)
+#define CPCAP_REG_CRM_ICHRG_1A152 CPCAP_REG_CRM_ICHRG(0xd)
+#define CPCAP_REG_CRM_ICHRG_1A596 CPCAP_REG_CRM_ICHRG(0xe)
#define CPCAP_REG_CRM_ICHRG_NO_LIMIT CPCAP_REG_CRM_ICHRG(0xf)
enum {
@@ -428,9 +443,9 @@ static void cpcap_usb_detect(struct work_struct *work)
int max_current;
if (cpcap_charger_battery_found(ddata))
- max_current = CPCAP_REG_CRM_ICHRG_1A584;
+ max_current = CPCAP_REG_CRM_ICHRG_1A596;
else
- max_current = CPCAP_REG_CRM_ICHRG_0A528;
+ max_current = CPCAP_REG_CRM_ICHRG_0A532;
error = cpcap_charger_set_state(ddata,
CPCAP_REG_CRM_VCHRG_4V35,
diff --git a/drivers/power/supply/ltc3651-charger.c b/drivers/power/supply/ltc3651-charger.c
new file mode 100644
index 000000000000..5f8d5c0b5721
--- /dev/null
+++ b/drivers/power/supply/ltc3651-charger.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017, Topic Embedded Products
+ * Driver for LTC3651 charger IC.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+struct ltc3651_charger {
+ struct power_supply *charger;
+ struct power_supply_desc charger_desc;
+ struct gpio_desc *acpr_gpio;
+ struct gpio_desc *fault_gpio;
+ struct gpio_desc *chrg_gpio;
+};
+
+static irqreturn_t ltc3651_charger_irq(int irq, void *devid)
+{
+ struct power_supply *charger = devid;
+
+ power_supply_changed(charger);
+
+ return IRQ_HANDLED;
+}
+
+static inline struct ltc3651_charger *psy_to_ltc3651_charger(
+ struct power_supply *psy)
+{
+ return power_supply_get_drvdata(psy);
+}
+
+static int ltc3651_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct ltc3651_charger *ltc3651_charger = psy_to_ltc3651_charger(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (!ltc3651_charger->chrg_gpio) {
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
+ if (gpiod_get_value(ltc3651_charger->chrg_gpio))
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = gpiod_get_value(ltc3651_charger->acpr_gpio);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ if (!ltc3651_charger->fault_gpio) {
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+ if (!gpiod_get_value(ltc3651_charger->fault_gpio)) {
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ }
+ /*
+ * If the fault pin is active, the chrg pin explains the type
+ * of failure.
+ */
+ if (!ltc3651_charger->chrg_gpio) {
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ }
+ val->intval = gpiod_get_value(ltc3651_charger->chrg_gpio) ?
+ POWER_SUPPLY_HEALTH_OVERHEAT :
+ POWER_SUPPLY_HEALTH_DEAD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property ltc3651_charger_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
+static int ltc3651_charger_probe(struct platform_device *pdev)
+{
+ struct power_supply_config psy_cfg = {};
+ struct ltc3651_charger *ltc3651_charger;
+ struct power_supply_desc *charger_desc;
+ int ret;
+
+ ltc3651_charger = devm_kzalloc(&pdev->dev, sizeof(*ltc3651_charger),
+ GFP_KERNEL);
+ if (!ltc3651_charger)
+ return -ENOMEM;
+
+ ltc3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev,
+ "lltc,acpr", GPIOD_IN);
+ if (IS_ERR(ltc3651_charger->acpr_gpio)) {
+ ret = PTR_ERR(ltc3651_charger->charger);
+ dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret);
+ return ret;
+ }
+ ltc3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev,
+ "lltc,fault", GPIOD_IN);
+ if (IS_ERR(ltc3651_charger->fault_gpio)) {
+ ret = PTR_ERR(ltc3651_charger->charger);
+ dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret);
+ return ret;
+ }
+ ltc3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev,
+ "lltc,chrg", GPIOD_IN);
+ if (IS_ERR(ltc3651_charger->chrg_gpio)) {
+ ret = PTR_ERR(ltc3651_charger->charger);
+ dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret);
+ return ret;
+ }
+
+ charger_desc = &ltc3651_charger->charger_desc;
+ charger_desc->name = pdev->dev.of_node->name;
+ charger_desc->type = POWER_SUPPLY_TYPE_MAINS;
+ charger_desc->properties = ltc3651_charger_properties;
+ charger_desc->num_properties = ARRAY_SIZE(ltc3651_charger_properties);
+ charger_desc->get_property = ltc3651_charger_get_property;
+ psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.drv_data = ltc3651_charger;
+
+ ltc3651_charger->charger = devm_power_supply_register(&pdev->dev,
+ charger_desc, &psy_cfg);
+ if (IS_ERR(ltc3651_charger->charger)) {
+ ret = PTR_ERR(ltc3651_charger->charger);
+ dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+ ret);
+ return ret;
+ }
+
+ /*
+ * Acquire IRQs for the GPIO pins if possible. If the system does not
+ * support IRQs on these pins, userspace will have to poll the sysfs
+ * files manually.
+ */
+ if (ltc3651_charger->acpr_gpio) {
+ ret = gpiod_to_irq(ltc3651_charger->acpr_gpio);
+ if (ret >= 0)
+ ret = devm_request_any_context_irq(&pdev->dev, ret,
+ ltc3651_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), ltc3651_charger->charger);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Failed to request acpr irq\n");
+ }
+ if (ltc3651_charger->fault_gpio) {
+ ret = gpiod_to_irq(ltc3651_charger->fault_gpio);
+ if (ret >= 0)
+ ret = devm_request_any_context_irq(&pdev->dev, ret,
+ ltc3651_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), ltc3651_charger->charger);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Failed to request fault irq\n");
+ }
+ if (ltc3651_charger->chrg_gpio) {
+ ret = gpiod_to_irq(ltc3651_charger->chrg_gpio);
+ if (ret >= 0)
+ ret = devm_request_any_context_irq(&pdev->dev, ret,
+ ltc3651_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), ltc3651_charger->charger);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Failed to request chrg irq\n");
+ }
+
+ platform_set_drvdata(pdev, ltc3651_charger);
+
+ return 0;
+}
+
+static const struct of_device_id ltc3651_charger_match[] = {
+ { .compatible = "lltc,ltc3651-charger" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc3651_charger_match);
+
+static struct platform_driver ltc3651_charger_driver = {
+ .probe = ltc3651_charger_probe,
+ .driver = {
+ .name = "ltc3651-charger",
+ .of_match_table = ltc3651_charger_match,
+ },
+};
+
+module_platform_driver(ltc3651_charger_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Driver for LTC3651 charger");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ltc3651-charger");
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 7ec7c7c202bd..0c09144193a6 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -274,8 +274,30 @@ static int power_supply_check_supplies(struct power_supply *psy)
return power_supply_populate_supplied_from(psy);
}
#else
-static inline int power_supply_check_supplies(struct power_supply *psy)
+static int power_supply_check_supplies(struct power_supply *psy)
{
+ int nval, ret;
+
+ if (!psy->dev.parent)
+ return 0;
+
+ nval = device_property_read_string_array(psy->dev.parent,
+ "supplied-from", NULL, 0);
+ if (nval <= 0)
+ return 0;
+
+ psy->supplied_from = devm_kmalloc_array(&psy->dev, nval,
+ sizeof(char *), GFP_KERNEL);
+ if (!psy->supplied_from)
+ return -ENOMEM;
+
+ ret = device_property_read_string_array(psy->dev.parent,
+ "supplied-from", (const char **)psy->supplied_from, nval);
+ if (ret < 0)
+ return ret;
+
+ psy->num_supplies = nval;
+
return 0;
}
#endif
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index bcde8d13476a..07b484f995c1 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -46,7 +46,7 @@ static ssize_t power_supply_show_property(struct device *dev,
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
"USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
- "USB_PD", "USB_PD_DRP"
+ "USB_PD", "USB_PD_DRP", "BrickID"
};
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 3965503315ef..4bd34051995e 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -159,13 +159,14 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_BATTERY,
POWER_SUPPLY_TYPE_UPS,
POWER_SUPPLY_TYPE_MAINS,
- POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
- POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
- POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
- POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
- POWER_SUPPLY_TYPE_USB_TYPE_C, /* Type C Port */
- POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery Port */
- POWER_SUPPLY_TYPE_USB_PD_DRP, /* PD Dual Role Port */
+ POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
+ POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
+ POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
+ POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
+ POWER_SUPPLY_TYPE_USB_TYPE_C, /* Type C Port */
+ POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery Port */
+ POWER_SUPPLY_TYPE_USB_PD_DRP, /* PD Dual Role Port */
+ POWER_SUPPLY_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */
};
enum power_supply_notifier_events {