brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · eaab750 Raw
224 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Battery class driver for Apple PMU4 *5 *	Copyright © 2006  David Woodhouse <dwmw2@infradead.org>6 */7 8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/err.h>11#include <linux/power_supply.h>12#include <linux/adb.h>13#include <linux/pmu.h>14#include <linux/slab.h>15 16static struct pmu_battery_dev {17	struct power_supply *bat;18	struct power_supply_desc bat_desc;19	struct pmu_battery_info *pbi;20	char name[16];21	int propval;22} *pbats[PMU_MAX_BATTERIES];23 24#define to_pmu_battery_dev(x) power_supply_get_drvdata(x)25 26/*********************************************************************27 *		Power28 *********************************************************************/29 30static int pmu_get_ac_prop(struct power_supply *psy,31			   enum power_supply_property psp,32			   union power_supply_propval *val)33{34	switch (psp) {35	case POWER_SUPPLY_PROP_ONLINE:36		val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||37			      (pmu_battery_count == 0);38		break;39	default:40		return -EINVAL;41	}42 43	return 0;44}45 46static enum power_supply_property pmu_ac_props[] = {47	POWER_SUPPLY_PROP_ONLINE,48};49 50static const struct power_supply_desc pmu_ac_desc = {51	.name = "pmu-ac",52	.type = POWER_SUPPLY_TYPE_MAINS,53	.properties = pmu_ac_props,54	.num_properties = ARRAY_SIZE(pmu_ac_props),55	.get_property = pmu_get_ac_prop,56};57 58static struct power_supply *pmu_ac;59 60/*********************************************************************61 *		Battery properties62 *********************************************************************/63 64static char *pmu_batt_types[] = {65	"Smart", "Comet", "Hooper", "Unknown"66};67 68static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)69{70	switch (pbi->flags & PMU_BATT_TYPE_MASK) {71	case PMU_BATT_TYPE_SMART:72		return pmu_batt_types[0];73	case PMU_BATT_TYPE_COMET:74		return pmu_batt_types[1];75	case PMU_BATT_TYPE_HOOPER:76		return pmu_batt_types[2];77	default: break;78	}79	return pmu_batt_types[3];80}81 82static int pmu_bat_get_property(struct power_supply *psy,83				enum power_supply_property psp,84				union power_supply_propval *val)85{86	struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);87	struct pmu_battery_info *pbi = pbat->pbi;88 89	switch (psp) {90	case POWER_SUPPLY_PROP_STATUS:91		if (pbi->flags & PMU_BATT_CHARGING)92			val->intval = POWER_SUPPLY_STATUS_CHARGING;93		else if (pmu_power_flags & PMU_PWR_AC_PRESENT)94			val->intval = POWER_SUPPLY_STATUS_FULL;95		else96			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;97		break;98	case POWER_SUPPLY_PROP_PRESENT:99		val->intval = !!(pbi->flags & PMU_BATT_PRESENT);100		break;101	case POWER_SUPPLY_PROP_MODEL_NAME:102		val->strval = pmu_bat_get_model_name(pbi);103		break;104	case POWER_SUPPLY_PROP_ENERGY_AVG:105		val->intval = pbi->charge     * 1000; /* mWh -> µWh */106		break;107	case POWER_SUPPLY_PROP_ENERGY_FULL:108		val->intval = pbi->max_charge * 1000; /* mWh -> µWh */109		break;110	case POWER_SUPPLY_PROP_CURRENT_AVG:111		val->intval = pbi->amperage   * 1000; /* mA -> µA */112		break;113	case POWER_SUPPLY_PROP_VOLTAGE_AVG:114		val->intval = pbi->voltage    * 1000; /* mV -> µV */115		break;116	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:117		val->intval = pbi->time_remaining;118		break;119	default:120		return -EINVAL;121	}122 123	return 0;124}125 126static enum power_supply_property pmu_bat_props[] = {127	POWER_SUPPLY_PROP_STATUS,128	POWER_SUPPLY_PROP_PRESENT,129	POWER_SUPPLY_PROP_MODEL_NAME,130	POWER_SUPPLY_PROP_ENERGY_AVG,131	POWER_SUPPLY_PROP_ENERGY_FULL,132	POWER_SUPPLY_PROP_CURRENT_AVG,133	POWER_SUPPLY_PROP_VOLTAGE_AVG,134	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,135};136 137/*********************************************************************138 *		Initialisation139 *********************************************************************/140 141static struct platform_device *bat_pdev;142 143static int __init pmu_bat_init(void)144{145	int ret = 0;146	int i;147 148	bat_pdev = platform_device_register_simple("pmu-battery",149						   0, NULL, 0);150	if (IS_ERR(bat_pdev)) {151		ret = PTR_ERR(bat_pdev);152		goto pdev_register_failed;153	}154 155	pmu_ac = power_supply_register(&bat_pdev->dev, &pmu_ac_desc, NULL);156	if (IS_ERR(pmu_ac)) {157		ret = PTR_ERR(pmu_ac);158		goto ac_register_failed;159	}160 161	for (i = 0; i < pmu_battery_count; i++) {162		struct power_supply_config psy_cfg = {};163		struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),164						       GFP_KERNEL);165		if (!pbat)166			break;167 168		sprintf(pbat->name, "PMU_battery_%d", i);169		pbat->bat_desc.name = pbat->name;170		pbat->bat_desc.properties = pmu_bat_props;171		pbat->bat_desc.num_properties = ARRAY_SIZE(pmu_bat_props);172		pbat->bat_desc.get_property = pmu_bat_get_property;173		pbat->pbi = &pmu_batteries[i];174		psy_cfg.drv_data = pbat;175 176		pbat->bat = power_supply_register(&bat_pdev->dev,177						  &pbat->bat_desc,178						  &psy_cfg);179		if (IS_ERR(pbat->bat)) {180			ret = PTR_ERR(pbat->bat);181			kfree(pbat);182			goto battery_register_failed;183		}184		pbats[i] = pbat;185	}186 187	goto success;188 189battery_register_failed:190	while (i--) {191		if (!pbats[i])192			continue;193		power_supply_unregister(pbats[i]->bat);194		kfree(pbats[i]);195	}196	power_supply_unregister(pmu_ac);197ac_register_failed:198	platform_device_unregister(bat_pdev);199pdev_register_failed:200success:201	return ret;202}203 204static void __exit pmu_bat_exit(void)205{206	int i;207 208	for (i = 0; i < PMU_MAX_BATTERIES; i++) {209		if (!pbats[i])210			continue;211		power_supply_unregister(pbats[i]->bat);212		kfree(pbats[i]);213	}214	power_supply_unregister(pmu_ac);215	platform_device_unregister(bat_pdev);216}217 218module_init(pmu_bat_init);219module_exit(pmu_bat_exit);220 221MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");222MODULE_LICENSE("GPL");223MODULE_DESCRIPTION("PMU battery driver");224