cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pmu_battery.c (5573B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Battery class driver for Apple PMU
      4 *
      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 *		Power
     28 *********************************************************************/
     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 properties
     62 *********************************************************************/
     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		else
     96			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 *		Initialisation
    139 *********************************************************************/
    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");