brintos

brintos / linux-shallow public Read only

0
0
Text · 17.6 KiB · 72b170b Raw
730 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI LP8788 MFD - battery charger driver4 *5 * Copyright 2012 Texas Instruments6 *7 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>8 */9 10#include <linux/err.h>11#include <linux/iio/consumer.h>12#include <linux/interrupt.h>13#include <linux/irqdomain.h>14#include <linux/mfd/lp8788.h>15#include <linux/module.h>16#include <linux/platform_device.h>17#include <linux/power_supply.h>18#include <linux/slab.h>19#include <linux/workqueue.h>20 21/* register address */22#define LP8788_CHG_STATUS		0x0723#define LP8788_CHG_IDCIN		0x1324#define LP8788_CHG_IBATT		0x1425#define LP8788_CHG_VTERM		0x1526#define LP8788_CHG_EOC			0x1627 28/* mask/shift bits */29#define LP8788_CHG_INPUT_STATE_M	0x03	/* Addr 07h */30#define LP8788_CHG_STATE_M		0x3C31#define LP8788_CHG_STATE_S		232#define LP8788_NO_BATT_M		BIT(6)33#define LP8788_BAD_BATT_M		BIT(7)34#define LP8788_CHG_IBATT_M		0x1F	/* Addr 14h */35#define LP8788_CHG_VTERM_M		0x0F	/* Addr 15h */36#define LP8788_CHG_EOC_LEVEL_M		0x30	/* Addr 16h */37#define LP8788_CHG_EOC_LEVEL_S		438#define LP8788_CHG_EOC_TIME_M		0x0E39#define LP8788_CHG_EOC_TIME_S		140#define LP8788_CHG_EOC_MODE_M		BIT(0)41 42#define LP8788_CHARGER_NAME		"charger"43#define LP8788_BATTERY_NAME		"main_batt"44 45#define LP8788_CHG_START		0x1146#define LP8788_CHG_END			0x1C47 48#define LP8788_ISEL_MAX			2349#define LP8788_ISEL_STEP		5050#define LP8788_VTERM_MIN		410051#define LP8788_VTERM_STEP		2552#define LP8788_MAX_BATT_CAPACITY	10053#define LP8788_MAX_CHG_IRQS		1154 55enum lp8788_charging_state {56	LP8788_OFF,57	LP8788_WARM_UP,58	LP8788_LOW_INPUT = 0x3,59	LP8788_PRECHARGE,60	LP8788_CC,61	LP8788_CV,62	LP8788_MAINTENANCE,63	LP8788_BATTERY_FAULT,64	LP8788_SYSTEM_SUPPORT = 0xC,65	LP8788_HIGH_CURRENT = 0xF,66	LP8788_MAX_CHG_STATE,67};68 69enum lp8788_charger_adc_sel {70	LP8788_VBATT,71	LP8788_BATT_TEMP,72	LP8788_NUM_CHG_ADC,73};74 75enum lp8788_charger_input_state {76	LP8788_SYSTEM_SUPPLY = 1,77	LP8788_FULL_FUNCTION,78};79 80/*81 * struct lp8788_chg_irq82 * @which        : lp8788 interrupt id83 * @virq         : Linux IRQ number from irq_domain84 */85struct lp8788_chg_irq {86	enum lp8788_int_id which;87	int virq;88};89 90/*91 * struct lp8788_charger92 * @lp           : used for accessing the registers of mfd lp8788 device93 * @charger      : power supply driver for the battery charger94 * @battery      : power supply driver for the battery95 * @charger_work : work queue for charger input interrupts96 * @chan         : iio channels for getting adc values97 *                 eg) battery voltage, capacity and temperature98 * @irqs         : charger dedicated interrupts99 * @num_irqs     : total numbers of charger interrupts100 * @pdata        : charger platform specific data101 */102struct lp8788_charger {103	struct lp8788 *lp;104	struct power_supply *charger;105	struct power_supply *battery;106	struct work_struct charger_work;107	struct iio_channel *chan[LP8788_NUM_CHG_ADC];108	struct lp8788_chg_irq irqs[LP8788_MAX_CHG_IRQS];109	int num_irqs;110	struct lp8788_charger_platform_data *pdata;111};112 113static char *battery_supplied_to[] = {114	LP8788_BATTERY_NAME,115};116 117static enum power_supply_property lp8788_charger_prop[] = {118	POWER_SUPPLY_PROP_ONLINE,119	POWER_SUPPLY_PROP_CURRENT_MAX,120};121 122static enum power_supply_property lp8788_battery_prop[] = {123	POWER_SUPPLY_PROP_STATUS,124	POWER_SUPPLY_PROP_HEALTH,125	POWER_SUPPLY_PROP_PRESENT,126	POWER_SUPPLY_PROP_VOLTAGE_NOW,127	POWER_SUPPLY_PROP_CAPACITY,128	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,129	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,130	POWER_SUPPLY_PROP_TEMP,131};132 133static bool lp8788_is_charger_detected(struct lp8788_charger *pchg)134{135	u8 data;136 137	lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);138	data &= LP8788_CHG_INPUT_STATE_M;139 140	return data == LP8788_SYSTEM_SUPPLY || data == LP8788_FULL_FUNCTION;141}142 143static int lp8788_charger_get_property(struct power_supply *psy,144					enum power_supply_property psp,145					union power_supply_propval *val)146{147	struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);148	u8 read;149 150	switch (psp) {151	case POWER_SUPPLY_PROP_ONLINE:152		val->intval = lp8788_is_charger_detected(pchg);153		break;154	case POWER_SUPPLY_PROP_CURRENT_MAX:155		lp8788_read_byte(pchg->lp, LP8788_CHG_IDCIN, &read);156		val->intval = LP8788_ISEL_STEP *157				(min_t(int, read, LP8788_ISEL_MAX) + 1);158		break;159	default:160		return -EINVAL;161	}162 163	return 0;164}165 166static int lp8788_get_battery_status(struct lp8788_charger *pchg,167				union power_supply_propval *val)168{169	enum lp8788_charging_state state;170	u8 data;171	int ret;172 173	ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);174	if (ret)175		return ret;176 177	state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;178	switch (state) {179	case LP8788_OFF:180		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;181		break;182	case LP8788_PRECHARGE:183	case LP8788_CC:184	case LP8788_CV:185	case LP8788_HIGH_CURRENT:186		val->intval = POWER_SUPPLY_STATUS_CHARGING;187		break;188	case LP8788_MAINTENANCE:189		val->intval = POWER_SUPPLY_STATUS_FULL;190		break;191	default:192		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;193		break;194	}195 196	return 0;197}198 199static int lp8788_get_battery_health(struct lp8788_charger *pchg,200				union power_supply_propval *val)201{202	u8 data;203	int ret;204 205	ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);206	if (ret)207		return ret;208 209	if (data & LP8788_NO_BATT_M)210		val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;211	else if (data & LP8788_BAD_BATT_M)212		val->intval = POWER_SUPPLY_HEALTH_DEAD;213	else214		val->intval = POWER_SUPPLY_HEALTH_GOOD;215 216	return 0;217}218 219static int lp8788_get_battery_present(struct lp8788_charger *pchg,220				union power_supply_propval *val)221{222	u8 data;223	int ret;224 225	ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);226	if (ret)227		return ret;228 229	val->intval = !(data & LP8788_NO_BATT_M);230	return 0;231}232 233static int lp8788_get_vbatt_adc(struct lp8788_charger *pchg, int *result)234{235	struct iio_channel *channel = pchg->chan[LP8788_VBATT];236 237	if (!channel)238		return -EINVAL;239 240	return iio_read_channel_processed(channel, result);241}242 243static int lp8788_get_battery_voltage(struct lp8788_charger *pchg,244				union power_supply_propval *val)245{246	return lp8788_get_vbatt_adc(pchg, &val->intval);247}248 249static int lp8788_get_battery_capacity(struct lp8788_charger *pchg,250				union power_supply_propval *val)251{252	struct lp8788 *lp = pchg->lp;253	struct lp8788_charger_platform_data *pdata = pchg->pdata;254	unsigned int max_vbatt;255	int vbatt;256	enum lp8788_charging_state state;257	u8 data;258	int ret;259 260	if (!pdata)261		return -EINVAL;262 263	max_vbatt = pdata->max_vbatt_mv;264	if (max_vbatt == 0)265		return -EINVAL;266 267	ret = lp8788_read_byte(lp, LP8788_CHG_STATUS, &data);268	if (ret)269		return ret;270 271	state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;272 273	if (state == LP8788_MAINTENANCE) {274		val->intval = LP8788_MAX_BATT_CAPACITY;275	} else {276		ret = lp8788_get_vbatt_adc(pchg, &vbatt);277		if (ret)278			return ret;279 280		val->intval = (vbatt * LP8788_MAX_BATT_CAPACITY) / max_vbatt;281		val->intval = min(val->intval, LP8788_MAX_BATT_CAPACITY);282	}283 284	return 0;285}286 287static int lp8788_get_battery_temperature(struct lp8788_charger *pchg,288				union power_supply_propval *val)289{290	struct iio_channel *channel = pchg->chan[LP8788_BATT_TEMP];291	int result;292	int ret;293 294	if (!channel)295		return -EINVAL;296 297	ret = iio_read_channel_processed(channel, &result);298	if (ret < 0)299		return -EINVAL;300 301	/* unit: 0.1 'C */302	val->intval = result * 10;303 304	return 0;305}306 307static int lp8788_get_battery_charging_current(struct lp8788_charger *pchg,308				union power_supply_propval *val)309{310	u8 read;311 312	lp8788_read_byte(pchg->lp, LP8788_CHG_IBATT, &read);313	read &= LP8788_CHG_IBATT_M;314	val->intval = LP8788_ISEL_STEP *315			(min_t(int, read, LP8788_ISEL_MAX) + 1);316 317	return 0;318}319 320static int lp8788_get_charging_termination_voltage(struct lp8788_charger *pchg,321				union power_supply_propval *val)322{323	u8 read;324 325	lp8788_read_byte(pchg->lp, LP8788_CHG_VTERM, &read);326	read &= LP8788_CHG_VTERM_M;327	val->intval = LP8788_VTERM_MIN + LP8788_VTERM_STEP * read;328 329	return 0;330}331 332static int lp8788_battery_get_property(struct power_supply *psy,333					enum power_supply_property psp,334					union power_supply_propval *val)335{336	struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);337 338	switch (psp) {339	case POWER_SUPPLY_PROP_STATUS:340		return lp8788_get_battery_status(pchg, val);341	case POWER_SUPPLY_PROP_HEALTH:342		return lp8788_get_battery_health(pchg, val);343	case POWER_SUPPLY_PROP_PRESENT:344		return lp8788_get_battery_present(pchg, val);345	case POWER_SUPPLY_PROP_VOLTAGE_NOW:346		return lp8788_get_battery_voltage(pchg, val);347	case POWER_SUPPLY_PROP_CAPACITY:348		return lp8788_get_battery_capacity(pchg, val);349	case POWER_SUPPLY_PROP_TEMP:350		return lp8788_get_battery_temperature(pchg, val);351	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:352		return lp8788_get_battery_charging_current(pchg, val);353	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:354		return lp8788_get_charging_termination_voltage(pchg, val);355	default:356		return -EINVAL;357	}358}359 360static inline bool lp8788_is_valid_charger_register(u8 addr)361{362	return addr >= LP8788_CHG_START && addr <= LP8788_CHG_END;363}364 365static int lp8788_update_charger_params(struct platform_device *pdev,366					struct lp8788_charger *pchg)367{368	struct lp8788 *lp = pchg->lp;369	struct lp8788_charger_platform_data *pdata = pchg->pdata;370	struct lp8788_chg_param *param;371	int i;372	int ret;373 374	if (!pdata || !pdata->chg_params) {375		dev_info(&pdev->dev, "skip updating charger parameters\n");376		return 0;377	}378 379	/* setting charging parameters */380	for (i = 0; i < pdata->num_chg_params; i++) {381		param = pdata->chg_params + i;382 383		if (lp8788_is_valid_charger_register(param->addr)) {384			ret = lp8788_write_byte(lp, param->addr, param->val);385			if (ret)386				return ret;387		}388	}389 390	return 0;391}392 393static const struct power_supply_desc lp8788_psy_charger_desc = {394	.name		= LP8788_CHARGER_NAME,395	.type		= POWER_SUPPLY_TYPE_MAINS,396	.properties	= lp8788_charger_prop,397	.num_properties	= ARRAY_SIZE(lp8788_charger_prop),398	.get_property	= lp8788_charger_get_property,399};400 401static const struct power_supply_desc lp8788_psy_battery_desc = {402	.name		= LP8788_BATTERY_NAME,403	.type		= POWER_SUPPLY_TYPE_BATTERY,404	.properties	= lp8788_battery_prop,405	.num_properties	= ARRAY_SIZE(lp8788_battery_prop),406	.get_property	= lp8788_battery_get_property,407};408 409static void lp8788_charger_event(struct work_struct *work)410{411	struct lp8788_charger *pchg =412		container_of(work, struct lp8788_charger, charger_work);413	struct lp8788_charger_platform_data *pdata = pchg->pdata;414	enum lp8788_charger_event event = lp8788_is_charger_detected(pchg);415 416	pdata->charger_event(pchg->lp, event);417}418 419static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id)420{421	bool found = false;422	int i;423 424	for (i = 0; i < pchg->num_irqs; i++) {425		if (pchg->irqs[i].virq == virq) {426			*id = pchg->irqs[i].which;427			found = true;428			break;429		}430	}431 432	return found;433}434 435static irqreturn_t lp8788_charger_irq_thread(int virq, void *ptr)436{437	struct lp8788_charger *pchg = ptr;438	struct lp8788_charger_platform_data *pdata = pchg->pdata;439	int id = -1;440 441	if (!lp8788_find_irq_id(pchg, virq, &id))442		return IRQ_NONE;443 444	switch (id) {445	case LP8788_INT_CHG_INPUT_STATE:446	case LP8788_INT_CHG_STATE:447	case LP8788_INT_EOC:448	case LP8788_INT_BATT_LOW:449	case LP8788_INT_NO_BATT:450		power_supply_changed(pchg->charger);451		power_supply_changed(pchg->battery);452		break;453	default:454		break;455	}456 457	/* report charger dectection event if used */458	if (!pdata)459		goto irq_handled;460 461	if (pdata->charger_event && id == LP8788_INT_CHG_INPUT_STATE)462		schedule_work(&pchg->charger_work);463 464irq_handled:465	return IRQ_HANDLED;466}467 468static int lp8788_set_irqs(struct platform_device *pdev,469			struct lp8788_charger *pchg, const char *name)470{471	struct resource *r;472	struct irq_domain *irqdm = pchg->lp->irqdm;473	int irq_start;474	int irq_end;475	int virq;476	int nr_irq;477	int i;478	int ret;479 480	/* no error even if no irq resource */481	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, name);482	if (!r)483		return 0;484 485	irq_start = r->start;486	irq_end = r->end;487 488	for (i = irq_start; i <= irq_end; i++) {489		nr_irq = pchg->num_irqs;490 491		virq = irq_create_mapping(irqdm, i);492		pchg->irqs[nr_irq].virq = virq;493		pchg->irqs[nr_irq].which = i;494		pchg->num_irqs++;495 496		ret = request_threaded_irq(virq, NULL,497					lp8788_charger_irq_thread,498					IRQF_ONESHOT, name, pchg);499		if (ret)500			break;501	}502 503	if (i <= irq_end)504		goto err_free_irq;505 506	return 0;507 508err_free_irq:509	for (i = 0; i < pchg->num_irqs; i++)510		free_irq(pchg->irqs[i].virq, pchg);511	return ret;512}513 514static int lp8788_irq_register(struct platform_device *pdev,515				struct lp8788_charger *pchg)516{517	static const char * const name[] = {518		LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ519	};520	int i;521	int ret;522 523	INIT_WORK(&pchg->charger_work, lp8788_charger_event);524	pchg->num_irqs = 0;525 526	for (i = 0; i < ARRAY_SIZE(name); i++) {527		ret = lp8788_set_irqs(pdev, pchg, name[i]);528		if (ret) {529			dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]);530			return ret;531		}532	}533 534	if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) {535		dev_err(&pdev->dev, "invalid total number of irqs: %d\n",536			pchg->num_irqs);537		return -EINVAL;538	}539 540 541	return 0;542}543 544static void lp8788_irq_unregister(struct platform_device *pdev,545				  struct lp8788_charger *pchg)546{547	int i;548	int irq;549 550	for (i = 0; i < pchg->num_irqs; i++) {551		irq = pchg->irqs[i].virq;552		if (!irq)553			continue;554 555		free_irq(irq, pchg);556	}557}558 559static void lp8788_setup_adc_channel(struct device *dev,560				struct lp8788_charger *pchg)561{562	struct lp8788_charger_platform_data *pdata = pchg->pdata;563	struct iio_channel *chan;564 565	if (!pdata)566		return;567 568	/* ADC channel for battery voltage */569	chan = devm_iio_channel_get(dev, pdata->adc_vbatt);570	pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;571 572	/* ADC channel for battery temperature */573	chan = devm_iio_channel_get(dev, pdata->adc_batt_temp);574	pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;575}576 577static ssize_t lp8788_show_charger_status(struct device *dev,578				struct device_attribute *attr, char *buf)579{580	struct lp8788_charger *pchg = dev_get_drvdata(dev);581	enum lp8788_charging_state state;582	static const char * const desc[LP8788_MAX_CHG_STATE] = {583		[LP8788_OFF] = "CHARGER OFF",584		[LP8788_WARM_UP] = "WARM UP",585		[LP8788_LOW_INPUT] = "LOW INPUT STATE",586		[LP8788_PRECHARGE] = "CHARGING - PRECHARGE",587		[LP8788_CC] = "CHARGING - CC",588		[LP8788_CV] = "CHARGING - CV",589		[LP8788_MAINTENANCE] = "NO CHARGING - MAINTENANCE",590		[LP8788_BATTERY_FAULT] = "BATTERY FAULT",591		[LP8788_SYSTEM_SUPPORT] = "SYSTEM SUPPORT",592		[LP8788_HIGH_CURRENT] = "HIGH CURRENT",593	};594	u8 data;595 596	lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);597	state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;598 599	return sysfs_emit(buf, "%s\n", desc[state]);600}601 602static ssize_t lp8788_show_eoc_time(struct device *dev,603				struct device_attribute *attr, char *buf)604{605	struct lp8788_charger *pchg = dev_get_drvdata(dev);606	static const char * const stime[] = {607		"400ms", "5min", "10min", "15min",608		"20min", "25min", "30min", "No timeout"609	};610	u8 val;611 612	lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);613	val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;614 615	return sysfs_emit(buf, "End Of Charge Time: %s\n", stime[val]);616}617 618static ssize_t lp8788_show_eoc_level(struct device *dev,619				struct device_attribute *attr, char *buf)620{621	struct lp8788_charger *pchg = dev_get_drvdata(dev);622	static const char * const abs_level[] = {623			"25mA", "49mA", "75mA", "98mA"624	};625	static const char * const relative_level[] = {626			"5%", "10%", "15%", "20%"627	};628	const char *level;629	u8 val;630	u8 mode;631 632	lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);633 634	mode = val & LP8788_CHG_EOC_MODE_M;635	val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;636	level = mode ? abs_level[val] : relative_level[val];637 638	return sysfs_emit(buf, "End Of Charge Level: %s\n", level);639}640 641static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);642static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);643static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);644 645static struct attribute *lp8788_charger_sysfs_attrs[] = {646	&dev_attr_charger_status.attr,647	&dev_attr_eoc_time.attr,648	&dev_attr_eoc_level.attr,649	NULL,650};651 652ATTRIBUTE_GROUPS(lp8788_charger_sysfs);653 654static int lp8788_psy_register(struct platform_device *pdev,655				struct lp8788_charger *pchg)656{657	struct power_supply_config charger_cfg = {};658 659	charger_cfg.attr_grp = lp8788_charger_sysfs_groups;660	charger_cfg.supplied_to = battery_supplied_to;661	charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);662 663	pchg->charger = devm_power_supply_register(&pdev->dev,664						   &lp8788_psy_charger_desc,665						   &charger_cfg);666	if (IS_ERR(pchg->charger))667		return -EPERM;668 669	pchg->battery = devm_power_supply_register(&pdev->dev,670						   &lp8788_psy_battery_desc, NULL);671	if (IS_ERR(pchg->battery))672		return -EPERM;673 674	return 0;675}676 677static int lp8788_charger_probe(struct platform_device *pdev)678{679	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);680	struct lp8788_charger *pchg;681	struct device *dev = &pdev->dev;682	int ret;683 684	pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL);685	if (!pchg)686		return -ENOMEM;687 688	pchg->lp = lp;689	pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;690	platform_set_drvdata(pdev, pchg);691 692	ret = lp8788_update_charger_params(pdev, pchg);693	if (ret)694		return ret;695 696	lp8788_setup_adc_channel(&pdev->dev, pchg);697 698	ret = lp8788_psy_register(pdev, pchg);699	if (ret)700		return ret;701 702	ret = lp8788_irq_register(pdev, pchg);703	if (ret)704		dev_warn(dev, "failed to register charger irq: %d\n", ret);705 706	return 0;707}708 709static void lp8788_charger_remove(struct platform_device *pdev)710{711	struct lp8788_charger *pchg = platform_get_drvdata(pdev);712 713	flush_work(&pchg->charger_work);714	lp8788_irq_unregister(pdev, pchg);715}716 717static struct platform_driver lp8788_charger_driver = {718	.probe = lp8788_charger_probe,719	.remove_new = lp8788_charger_remove,720	.driver = {721		.name = LP8788_DEV_CHARGER,722	},723};724module_platform_driver(lp8788_charger_driver);725 726MODULE_DESCRIPTION("TI LP8788 Charger Driver");727MODULE_AUTHOR("Milo Kim");728MODULE_LICENSE("GPL");729MODULE_ALIAS("platform:lp8788-charger");730