18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Battery driver for wm8350 PMIC
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2007, 2008 Wolfson Microelectronics PLC.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on OLPC Battery Driver
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright 2006  David Woodhouse <dwmw2@infradead.org>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/power_supply.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/wm8350/supply.h>
178c2ecf20Sopenharmony_ci#include <linux/mfd/wm8350/core.h>
188c2ecf20Sopenharmony_ci#include <linux/mfd/wm8350/comparator.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int wm8350_read_battery_uvolts(struct wm8350 *wm8350)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0)
238c2ecf20Sopenharmony_ci		* WM8350_AUX_COEFF;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int wm8350_read_line_uvolts(struct wm8350 *wm8350)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0)
298c2ecf20Sopenharmony_ci		* WM8350_AUX_COEFF;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic int wm8350_read_usb_uvolts(struct wm8350 *wm8350)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0)
358c2ecf20Sopenharmony_ci		* WM8350_AUX_COEFF;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define WM8350_BATT_SUPPLY	1
398c2ecf20Sopenharmony_ci#define WM8350_USB_SUPPLY	2
408c2ecf20Sopenharmony_ci#define WM8350_LINE_SUPPLY	4
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	if (!wm8350->power.rev_g_coeff)
458c2ecf20Sopenharmony_ci		return (((min - 30) / 15) & 0xf) << 8;
468c2ecf20Sopenharmony_ci	else
478c2ecf20Sopenharmony_ci		return (((min - 30) / 30) & 0xf) << 8;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int wm8350_get_supplies(struct wm8350 *wm8350)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	u16 sm, ov, co, chrg;
538c2ecf20Sopenharmony_ci	int supplies = 0;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS);
568c2ecf20Sopenharmony_ci	ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES);
578c2ecf20Sopenharmony_ci	co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES);
588c2ecf20Sopenharmony_ci	chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* USB_SM */
618c2ecf20Sopenharmony_ci	sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* CHG_ISEL */
648c2ecf20Sopenharmony_ci	chrg &= WM8350_CHG_ISEL_MASK;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* If the USB state machine is active then we're using that with or
678c2ecf20Sopenharmony_ci	 * without battery, otherwise check for wall supply */
688c2ecf20Sopenharmony_ci	if (((sm == WM8350_USB_SM_100_SLV) ||
698c2ecf20Sopenharmony_ci	     (sm == WM8350_USB_SM_500_SLV) ||
708c2ecf20Sopenharmony_ci	     (sm == WM8350_USB_SM_STDBY_SLV))
718c2ecf20Sopenharmony_ci	    && !(ov & WM8350_USB_LIMIT_OVRDE))
728c2ecf20Sopenharmony_ci		supplies = WM8350_USB_SUPPLY;
738c2ecf20Sopenharmony_ci	else if (((sm == WM8350_USB_SM_100_SLV) ||
748c2ecf20Sopenharmony_ci		  (sm == WM8350_USB_SM_500_SLV) ||
758c2ecf20Sopenharmony_ci		  (sm == WM8350_USB_SM_STDBY_SLV))
768c2ecf20Sopenharmony_ci		 && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0))
778c2ecf20Sopenharmony_ci		supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY;
788c2ecf20Sopenharmony_ci	else if (co & WM8350_WALL_FB_OVRDE)
798c2ecf20Sopenharmony_ci		supplies = WM8350_LINE_SUPPLY;
808c2ecf20Sopenharmony_ci	else
818c2ecf20Sopenharmony_ci		supplies = WM8350_BATT_SUPPLY;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return supplies;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int wm8350_charger_config(struct wm8350 *wm8350,
878c2ecf20Sopenharmony_ci				 struct wm8350_charger_policy *policy)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	u16 reg, eoc_mA, fast_limit_mA;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (!policy) {
928c2ecf20Sopenharmony_ci		dev_warn(wm8350->dev,
938c2ecf20Sopenharmony_ci			 "No charger policy, charger not configured.\n");
948c2ecf20Sopenharmony_ci		return -EINVAL;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* make sure USB fast charge current is not > 500mA */
988c2ecf20Sopenharmony_ci	if (policy->fast_limit_USB_mA > 500) {
998c2ecf20Sopenharmony_ci		dev_err(wm8350->dev, "USB fast charge > 500mA\n");
1008c2ecf20Sopenharmony_ci		return -EINVAL;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	wm8350_reg_unlock(wm8350);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
1088c2ecf20Sopenharmony_ci		& WM8350_CHG_ENA_R168;
1098c2ecf20Sopenharmony_ci	wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
1108c2ecf20Sopenharmony_ci			 reg | eoc_mA | policy->trickle_start_mV |
1118c2ecf20Sopenharmony_ci			 WM8350_CHG_TRICKLE_TEMP_CHOKE |
1128c2ecf20Sopenharmony_ci			 WM8350_CHG_TRICKLE_USB_CHOKE |
1138c2ecf20Sopenharmony_ci			 WM8350_CHG_FAST_USB_THROTTLE);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
1168c2ecf20Sopenharmony_ci		fast_limit_mA =
1178c2ecf20Sopenharmony_ci			WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
1188c2ecf20Sopenharmony_ci		wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
1198c2ecf20Sopenharmony_ci			    policy->charge_mV | policy->trickle_charge_USB_mA |
1208c2ecf20Sopenharmony_ci			    fast_limit_mA | wm8350_charge_time_min(wm8350,
1218c2ecf20Sopenharmony_ci						policy->charge_timeout));
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	} else {
1248c2ecf20Sopenharmony_ci		fast_limit_mA =
1258c2ecf20Sopenharmony_ci			WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
1268c2ecf20Sopenharmony_ci		wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
1278c2ecf20Sopenharmony_ci			    policy->charge_mV | policy->trickle_charge_mA |
1288c2ecf20Sopenharmony_ci			    fast_limit_mA | wm8350_charge_time_min(wm8350,
1298c2ecf20Sopenharmony_ci						policy->charge_timeout));
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	wm8350_reg_lock(wm8350);
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int wm8350_batt_status(struct wm8350 *wm8350)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	u16 state;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
1418c2ecf20Sopenharmony_ci	state &= WM8350_CHG_STS_MASK;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	switch (state) {
1448c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_OFF:
1458c2ecf20Sopenharmony_ci		return POWER_SUPPLY_STATUS_DISCHARGING;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_TRICKLE:
1488c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_FAST:
1498c2ecf20Sopenharmony_ci		return POWER_SUPPLY_STATUS_CHARGING;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	default:
1528c2ecf20Sopenharmony_ci		return POWER_SUPPLY_STATUS_UNKNOWN;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic ssize_t charger_state_show(struct device *dev,
1578c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = dev_get_drvdata(dev);
1608c2ecf20Sopenharmony_ci	char *charge;
1618c2ecf20Sopenharmony_ci	int state;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
1648c2ecf20Sopenharmony_ci	    WM8350_CHG_STS_MASK;
1658c2ecf20Sopenharmony_ci	switch (state) {
1668c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_OFF:
1678c2ecf20Sopenharmony_ci		charge = "Charger Off";
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_TRICKLE:
1708c2ecf20Sopenharmony_ci		charge = "Trickle Charging";
1718c2ecf20Sopenharmony_ci		break;
1728c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_FAST:
1738c2ecf20Sopenharmony_ci		charge = "Fast Charging";
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	default:
1768c2ecf20Sopenharmony_ci		return 0;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", charge);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(charger_state);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic irqreturn_t wm8350_charger_handler(int irq, void *data)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = data;
1878c2ecf20Sopenharmony_ci	struct wm8350_power *power = &wm8350->power;
1888c2ecf20Sopenharmony_ci	struct wm8350_charger_policy *policy = power->policy;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	switch (irq - wm8350->irq_base) {
1918c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_BAT_FAIL:
1928c2ecf20Sopenharmony_ci		dev_err(wm8350->dev, "battery failed\n");
1938c2ecf20Sopenharmony_ci		break;
1948c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_TO:
1958c2ecf20Sopenharmony_ci		dev_err(wm8350->dev, "charger timeout\n");
1968c2ecf20Sopenharmony_ci		power_supply_changed(power->battery);
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_BAT_HOT:
2008c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_BAT_COLD:
2018c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_START:
2028c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_END:
2038c2ecf20Sopenharmony_ci		power_supply_changed(power->battery);
2048c2ecf20Sopenharmony_ci		break;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_FAST_RDY:
2078c2ecf20Sopenharmony_ci		dev_dbg(wm8350->dev, "fast charger ready\n");
2088c2ecf20Sopenharmony_ci		wm8350_charger_config(wm8350, policy);
2098c2ecf20Sopenharmony_ci		wm8350_reg_unlock(wm8350);
2108c2ecf20Sopenharmony_ci		wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
2118c2ecf20Sopenharmony_ci				WM8350_CHG_FAST);
2128c2ecf20Sopenharmony_ci		wm8350_reg_lock(wm8350);
2138c2ecf20Sopenharmony_ci		break;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_VBATT_LT_3P9:
2168c2ecf20Sopenharmony_ci		dev_warn(wm8350->dev, "battery < 3.9V\n");
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_VBATT_LT_3P1:
2198c2ecf20Sopenharmony_ci		dev_warn(wm8350->dev, "battery < 3.1V\n");
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	case WM8350_IRQ_CHG_VBATT_LT_2P85:
2228c2ecf20Sopenharmony_ci		dev_warn(wm8350->dev, "battery < 2.85V\n");
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		/* Supply change.  We will overnotify but it should do
2268c2ecf20Sopenharmony_ci		 * no harm. */
2278c2ecf20Sopenharmony_ci	case WM8350_IRQ_EXT_USB_FB:
2288c2ecf20Sopenharmony_ci	case WM8350_IRQ_EXT_WALL_FB:
2298c2ecf20Sopenharmony_ci		wm8350_charger_config(wm8350, policy);
2308c2ecf20Sopenharmony_ci		fallthrough;
2318c2ecf20Sopenharmony_ci	case WM8350_IRQ_EXT_BAT_FB:
2328c2ecf20Sopenharmony_ci		power_supply_changed(power->battery);
2338c2ecf20Sopenharmony_ci		power_supply_changed(power->usb);
2348c2ecf20Sopenharmony_ci		power_supply_changed(power->ac);
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	default:
2388c2ecf20Sopenharmony_ci		dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/*********************************************************************
2458c2ecf20Sopenharmony_ci *		AC Power
2468c2ecf20Sopenharmony_ci *********************************************************************/
2478c2ecf20Sopenharmony_cistatic int wm8350_ac_get_prop(struct power_supply *psy,
2488c2ecf20Sopenharmony_ci			      enum power_supply_property psp,
2498c2ecf20Sopenharmony_ci			      union power_supply_propval *val)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
2528c2ecf20Sopenharmony_ci	int ret = 0;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	switch (psp) {
2558c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
2568c2ecf20Sopenharmony_ci		val->intval = !!(wm8350_get_supplies(wm8350) &
2578c2ecf20Sopenharmony_ci				 WM8350_LINE_SUPPLY);
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2608c2ecf20Sopenharmony_ci		val->intval = wm8350_read_line_uvolts(wm8350);
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	default:
2638c2ecf20Sopenharmony_ci		ret = -EINVAL;
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	return ret;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic enum power_supply_property wm8350_ac_props[] = {
2708c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
2718c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/*********************************************************************
2758c2ecf20Sopenharmony_ci *		USB Power
2768c2ecf20Sopenharmony_ci *********************************************************************/
2778c2ecf20Sopenharmony_cistatic int wm8350_usb_get_prop(struct power_supply *psy,
2788c2ecf20Sopenharmony_ci			       enum power_supply_property psp,
2798c2ecf20Sopenharmony_ci			       union power_supply_propval *val)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
2828c2ecf20Sopenharmony_ci	int ret = 0;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	switch (psp) {
2858c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
2868c2ecf20Sopenharmony_ci		val->intval = !!(wm8350_get_supplies(wm8350) &
2878c2ecf20Sopenharmony_ci				 WM8350_USB_SUPPLY);
2888c2ecf20Sopenharmony_ci		break;
2898c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2908c2ecf20Sopenharmony_ci		val->intval = wm8350_read_usb_uvolts(wm8350);
2918c2ecf20Sopenharmony_ci		break;
2928c2ecf20Sopenharmony_ci	default:
2938c2ecf20Sopenharmony_ci		ret = -EINVAL;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci	return ret;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic enum power_supply_property wm8350_usb_props[] = {
3008c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
3018c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3028c2ecf20Sopenharmony_ci};
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci/*********************************************************************
3058c2ecf20Sopenharmony_ci *		Battery properties
3068c2ecf20Sopenharmony_ci *********************************************************************/
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int wm8350_bat_check_health(struct wm8350 *wm8350)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	u16 reg;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (wm8350_read_battery_uvolts(wm8350) < 2850000)
3138c2ecf20Sopenharmony_ci		return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES);
3168c2ecf20Sopenharmony_ci	if (reg & WM8350_CHG_BATT_HOT_OVRDE)
3178c2ecf20Sopenharmony_ci		return POWER_SUPPLY_HEALTH_OVERHEAT;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (reg & WM8350_CHG_BATT_COLD_OVRDE)
3208c2ecf20Sopenharmony_ci		return POWER_SUPPLY_HEALTH_COLD;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return POWER_SUPPLY_HEALTH_GOOD;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int wm8350_bat_get_charge_type(struct wm8350 *wm8350)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	int state;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
3308c2ecf20Sopenharmony_ci	    WM8350_CHG_STS_MASK;
3318c2ecf20Sopenharmony_ci	switch (state) {
3328c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_OFF:
3338c2ecf20Sopenharmony_ci		return POWER_SUPPLY_CHARGE_TYPE_NONE;
3348c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_TRICKLE:
3358c2ecf20Sopenharmony_ci		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
3368c2ecf20Sopenharmony_ci	case WM8350_CHG_STS_FAST:
3378c2ecf20Sopenharmony_ci		return POWER_SUPPLY_CHARGE_TYPE_FAST;
3388c2ecf20Sopenharmony_ci	default:
3398c2ecf20Sopenharmony_ci		return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int wm8350_bat_get_property(struct power_supply *psy,
3448c2ecf20Sopenharmony_ci				   enum power_supply_property psp,
3458c2ecf20Sopenharmony_ci				   union power_supply_propval *val)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
3488c2ecf20Sopenharmony_ci	int ret = 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	switch (psp) {
3518c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_STATUS:
3528c2ecf20Sopenharmony_ci		val->intval = wm8350_batt_status(wm8350);
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
3558c2ecf20Sopenharmony_ci		val->intval = !!(wm8350_get_supplies(wm8350) &
3568c2ecf20Sopenharmony_ci				 WM8350_BATT_SUPPLY);
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3598c2ecf20Sopenharmony_ci		val->intval = wm8350_read_battery_uvolts(wm8350);
3608c2ecf20Sopenharmony_ci		break;
3618c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
3628c2ecf20Sopenharmony_ci		val->intval = wm8350_bat_check_health(wm8350);
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_TYPE:
3658c2ecf20Sopenharmony_ci		val->intval = wm8350_bat_get_charge_type(wm8350);
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	default:
3688c2ecf20Sopenharmony_ci		ret = -EINVAL;
3698c2ecf20Sopenharmony_ci		break;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	return ret;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic enum power_supply_property wm8350_bat_props[] = {
3768c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
3778c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
3788c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3798c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
3808c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_TYPE,
3818c2ecf20Sopenharmony_ci};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic const struct power_supply_desc wm8350_ac_desc = {
3848c2ecf20Sopenharmony_ci	.name		= "wm8350-ac",
3858c2ecf20Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_MAINS,
3868c2ecf20Sopenharmony_ci	.properties	= wm8350_ac_props,
3878c2ecf20Sopenharmony_ci	.num_properties	= ARRAY_SIZE(wm8350_ac_props),
3888c2ecf20Sopenharmony_ci	.get_property	= wm8350_ac_get_prop,
3898c2ecf20Sopenharmony_ci};
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic const struct power_supply_desc wm8350_battery_desc = {
3928c2ecf20Sopenharmony_ci	.name		= "wm8350-battery",
3938c2ecf20Sopenharmony_ci	.properties	= wm8350_bat_props,
3948c2ecf20Sopenharmony_ci	.num_properties	= ARRAY_SIZE(wm8350_bat_props),
3958c2ecf20Sopenharmony_ci	.get_property	= wm8350_bat_get_property,
3968c2ecf20Sopenharmony_ci	.use_for_apm	= 1,
3978c2ecf20Sopenharmony_ci};
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic const struct power_supply_desc wm8350_usb_desc = {
4008c2ecf20Sopenharmony_ci	.name		= "wm8350-usb",
4018c2ecf20Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_USB,
4028c2ecf20Sopenharmony_ci	.properties	= wm8350_usb_props,
4038c2ecf20Sopenharmony_ci	.num_properties	= ARRAY_SIZE(wm8350_usb_props),
4048c2ecf20Sopenharmony_ci	.get_property	= wm8350_usb_get_prop,
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci/*********************************************************************
4088c2ecf20Sopenharmony_ci *		Initialisation
4098c2ecf20Sopenharmony_ci *********************************************************************/
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int wm8350_init_charger(struct wm8350 *wm8350)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	int ret;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* register our interest in charger events */
4168c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
4178c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "Battery hot", wm8350);
4188c2ecf20Sopenharmony_ci	if (ret)
4198c2ecf20Sopenharmony_ci		goto err;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
4228c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "Battery cold", wm8350);
4238c2ecf20Sopenharmony_ci	if (ret)
4248c2ecf20Sopenharmony_ci		goto free_chg_bat_hot;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
4278c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "Battery fail", wm8350);
4288c2ecf20Sopenharmony_ci	if (ret)
4298c2ecf20Sopenharmony_ci		goto free_chg_bat_cold;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
4328c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4338c2ecf20Sopenharmony_ci			    "Charger timeout", wm8350);
4348c2ecf20Sopenharmony_ci	if (ret)
4358c2ecf20Sopenharmony_ci		goto free_chg_bat_fail;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
4388c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4398c2ecf20Sopenharmony_ci			    "Charge end", wm8350);
4408c2ecf20Sopenharmony_ci	if (ret)
4418c2ecf20Sopenharmony_ci		goto free_chg_to;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
4448c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4458c2ecf20Sopenharmony_ci			    "Charge start", wm8350);
4468c2ecf20Sopenharmony_ci	if (ret)
4478c2ecf20Sopenharmony_ci		goto free_chg_end;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
4508c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4518c2ecf20Sopenharmony_ci			    "Fast charge ready", wm8350);
4528c2ecf20Sopenharmony_ci	if (ret)
4538c2ecf20Sopenharmony_ci		goto free_chg_start;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
4568c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4578c2ecf20Sopenharmony_ci			    "Battery <3.9V", wm8350);
4588c2ecf20Sopenharmony_ci	if (ret)
4598c2ecf20Sopenharmony_ci		goto free_chg_fast_rdy;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
4628c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4638c2ecf20Sopenharmony_ci			    "Battery <3.1V", wm8350);
4648c2ecf20Sopenharmony_ci	if (ret)
4658c2ecf20Sopenharmony_ci		goto free_chg_vbatt_lt_3p9;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
4688c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0,
4698c2ecf20Sopenharmony_ci			    "Battery <2.85V", wm8350);
4708c2ecf20Sopenharmony_ci	if (ret)
4718c2ecf20Sopenharmony_ci		goto free_chg_vbatt_lt_3p1;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* and supply change events */
4748c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
4758c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "USB", wm8350);
4768c2ecf20Sopenharmony_ci	if (ret)
4778c2ecf20Sopenharmony_ci		goto free_chg_vbatt_lt_2p85;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
4808c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "Wall", wm8350);
4818c2ecf20Sopenharmony_ci	if (ret)
4828c2ecf20Sopenharmony_ci		goto free_ext_usb_fb;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
4858c2ecf20Sopenharmony_ci			    wm8350_charger_handler, 0, "Battery", wm8350);
4868c2ecf20Sopenharmony_ci	if (ret)
4878c2ecf20Sopenharmony_ci		goto free_ext_wall_fb;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	return 0;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cifree_ext_wall_fb:
4928c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
4938c2ecf20Sopenharmony_cifree_ext_usb_fb:
4948c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
4958c2ecf20Sopenharmony_cifree_chg_vbatt_lt_2p85:
4968c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
4978c2ecf20Sopenharmony_cifree_chg_vbatt_lt_3p1:
4988c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
4998c2ecf20Sopenharmony_cifree_chg_vbatt_lt_3p9:
5008c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
5018c2ecf20Sopenharmony_cifree_chg_fast_rdy:
5028c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350);
5038c2ecf20Sopenharmony_cifree_chg_start:
5048c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
5058c2ecf20Sopenharmony_cifree_chg_end:
5068c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
5078c2ecf20Sopenharmony_cifree_chg_to:
5088c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
5098c2ecf20Sopenharmony_cifree_chg_bat_fail:
5108c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
5118c2ecf20Sopenharmony_cifree_chg_bat_cold:
5128c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
5138c2ecf20Sopenharmony_cifree_chg_bat_hot:
5148c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
5158c2ecf20Sopenharmony_cierr:
5168c2ecf20Sopenharmony_ci	return ret;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic void free_charger_irq(struct wm8350 *wm8350)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
5228c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
5238c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
5248c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
5258c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
5268c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
5278c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350);
5288c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
5298c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
5308c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
5318c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
5328c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
5338c2ecf20Sopenharmony_ci	wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic int wm8350_power_probe(struct platform_device *pdev)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
5398c2ecf20Sopenharmony_ci	struct wm8350_power *power = &wm8350->power;
5408c2ecf20Sopenharmony_ci	struct wm8350_charger_policy *policy = power->policy;
5418c2ecf20Sopenharmony_ci	int ret;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	power->ac = power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL);
5448c2ecf20Sopenharmony_ci	if (IS_ERR(power->ac))
5458c2ecf20Sopenharmony_ci		return PTR_ERR(power->ac);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	power->battery = power_supply_register(&pdev->dev, &wm8350_battery_desc,
5488c2ecf20Sopenharmony_ci					       NULL);
5498c2ecf20Sopenharmony_ci	if (IS_ERR(power->battery)) {
5508c2ecf20Sopenharmony_ci		ret = PTR_ERR(power->battery);
5518c2ecf20Sopenharmony_ci		goto battery_failed;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	power->usb = power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL);
5558c2ecf20Sopenharmony_ci	if (IS_ERR(power->usb)) {
5568c2ecf20Sopenharmony_ci		ret = PTR_ERR(power->usb);
5578c2ecf20Sopenharmony_ci		goto usb_failed;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
5618c2ecf20Sopenharmony_ci	if (ret < 0)
5628c2ecf20Sopenharmony_ci		dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
5638c2ecf20Sopenharmony_ci	ret = 0;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	wm8350_init_charger(wm8350);
5668c2ecf20Sopenharmony_ci	if (wm8350_charger_config(wm8350, policy) == 0) {
5678c2ecf20Sopenharmony_ci		wm8350_reg_unlock(wm8350);
5688c2ecf20Sopenharmony_ci		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
5698c2ecf20Sopenharmony_ci		wm8350_reg_lock(wm8350);
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return ret;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ciusb_failed:
5758c2ecf20Sopenharmony_ci	power_supply_unregister(power->battery);
5768c2ecf20Sopenharmony_cibattery_failed:
5778c2ecf20Sopenharmony_ci	power_supply_unregister(power->ac);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return ret;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic int wm8350_power_remove(struct platform_device *pdev)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
5858c2ecf20Sopenharmony_ci	struct wm8350_power *power = &wm8350->power;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	free_charger_irq(wm8350);
5888c2ecf20Sopenharmony_ci	device_remove_file(&pdev->dev, &dev_attr_charger_state);
5898c2ecf20Sopenharmony_ci	power_supply_unregister(power->battery);
5908c2ecf20Sopenharmony_ci	power_supply_unregister(power->ac);
5918c2ecf20Sopenharmony_ci	power_supply_unregister(power->usb);
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic struct platform_driver wm8350_power_driver = {
5968c2ecf20Sopenharmony_ci	.probe = wm8350_power_probe,
5978c2ecf20Sopenharmony_ci	.remove = wm8350_power_remove,
5988c2ecf20Sopenharmony_ci	.driver = {
5998c2ecf20Sopenharmony_ci		.name = "wm8350-power",
6008c2ecf20Sopenharmony_ci	},
6018c2ecf20Sopenharmony_ci};
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cimodule_platform_driver(wm8350_power_driver);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6068c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Power supply driver for WM8350");
6078c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:wm8350-power");
608