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

goldfish_battery.c (7745B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Power supply driver for the goldfish emulator
      4 *
      5 * Copyright (C) 2008 Google, Inc.
      6 * Copyright (C) 2012 Intel, Inc.
      7 * Copyright (C) 2013 Intel, Inc.
      8 * Author: Mike Lockwood <lockwood@android.com>
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/err.h>
     13#include <linux/platform_device.h>
     14#include <linux/power_supply.h>
     15#include <linux/types.h>
     16#include <linux/pci.h>
     17#include <linux/interrupt.h>
     18#include <linux/io.h>
     19#include <linux/acpi.h>
     20
     21struct goldfish_battery_data {
     22	void __iomem *reg_base;
     23	int irq;
     24	spinlock_t lock;
     25
     26	struct power_supply *battery;
     27	struct power_supply *ac;
     28};
     29
     30#define GOLDFISH_BATTERY_READ(data, addr) \
     31	(readl(data->reg_base + addr))
     32#define GOLDFISH_BATTERY_WRITE(data, addr, x) \
     33	(writel(x, data->reg_base + addr))
     34
     35enum {
     36	/* status register */
     37	BATTERY_INT_STATUS	= 0x00,
     38	/* set this to enable IRQ */
     39	BATTERY_INT_ENABLE	= 0x04,
     40
     41	BATTERY_AC_ONLINE	= 0x08,
     42	BATTERY_STATUS		= 0x0C,
     43	BATTERY_HEALTH		= 0x10,
     44	BATTERY_PRESENT		= 0x14,
     45	BATTERY_CAPACITY	= 0x18,
     46	BATTERY_VOLTAGE		= 0x1C,
     47	BATTERY_TEMP		= 0x20,
     48	BATTERY_CHARGE_COUNTER	= 0x24,
     49	BATTERY_VOLTAGE_MAX	= 0x28,
     50	BATTERY_CURRENT_MAX	= 0x2C,
     51	BATTERY_CURRENT_NOW	= 0x30,
     52	BATTERY_CURRENT_AVG	= 0x34,
     53	BATTERY_CHARGE_FULL_UAH	= 0x38,
     54	BATTERY_CYCLE_COUNT	= 0x40,
     55
     56	BATTERY_STATUS_CHANGED	= 1U << 0,
     57	AC_STATUS_CHANGED	= 1U << 1,
     58	BATTERY_INT_MASK	= BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
     59};
     60
     61
     62static int goldfish_ac_get_property(struct power_supply *psy,
     63			enum power_supply_property psp,
     64			union power_supply_propval *val)
     65{
     66	struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
     67	int ret = 0;
     68
     69	switch (psp) {
     70	case POWER_SUPPLY_PROP_ONLINE:
     71		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
     72		break;
     73	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
     74		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE_MAX);
     75		break;
     76	case POWER_SUPPLY_PROP_CURRENT_MAX:
     77		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_MAX);
     78		break;
     79	default:
     80		ret = -EINVAL;
     81		break;
     82	}
     83	return ret;
     84}
     85
     86static int goldfish_battery_get_property(struct power_supply *psy,
     87				 enum power_supply_property psp,
     88				 union power_supply_propval *val)
     89{
     90	struct goldfish_battery_data *data = power_supply_get_drvdata(psy);
     91	int ret = 0;
     92
     93	switch (psp) {
     94	case POWER_SUPPLY_PROP_STATUS:
     95		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);
     96		break;
     97	case POWER_SUPPLY_PROP_HEALTH:
     98		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);
     99		break;
    100	case POWER_SUPPLY_PROP_PRESENT:
    101		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);
    102		break;
    103	case POWER_SUPPLY_PROP_TECHNOLOGY:
    104		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
    105		break;
    106	case POWER_SUPPLY_PROP_CAPACITY:
    107		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
    108		break;
    109	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
    110		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE);
    111		break;
    112	case POWER_SUPPLY_PROP_TEMP:
    113		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_TEMP);
    114		break;
    115	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
    116		val->intval = GOLDFISH_BATTERY_READ(data,
    117						    BATTERY_CHARGE_COUNTER);
    118		break;
    119	case POWER_SUPPLY_PROP_CURRENT_NOW:
    120		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_NOW);
    121		break;
    122	case POWER_SUPPLY_PROP_CURRENT_AVG:
    123		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_AVG);
    124		break;
    125	case POWER_SUPPLY_PROP_CHARGE_FULL:
    126		val->intval = GOLDFISH_BATTERY_READ(data,
    127						    BATTERY_CHARGE_FULL_UAH);
    128		break;
    129	case POWER_SUPPLY_PROP_CYCLE_COUNT:
    130		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CYCLE_COUNT);
    131		break;
    132	default:
    133		ret = -EINVAL;
    134		break;
    135	}
    136
    137	return ret;
    138}
    139
    140static enum power_supply_property goldfish_battery_props[] = {
    141	POWER_SUPPLY_PROP_STATUS,
    142	POWER_SUPPLY_PROP_HEALTH,
    143	POWER_SUPPLY_PROP_PRESENT,
    144	POWER_SUPPLY_PROP_TECHNOLOGY,
    145	POWER_SUPPLY_PROP_CAPACITY,
    146	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    147	POWER_SUPPLY_PROP_TEMP,
    148	POWER_SUPPLY_PROP_CHARGE_COUNTER,
    149	POWER_SUPPLY_PROP_CURRENT_NOW,
    150	POWER_SUPPLY_PROP_CURRENT_AVG,
    151	POWER_SUPPLY_PROP_CHARGE_FULL,
    152	POWER_SUPPLY_PROP_CYCLE_COUNT,
    153};
    154
    155static enum power_supply_property goldfish_ac_props[] = {
    156	POWER_SUPPLY_PROP_ONLINE,
    157	POWER_SUPPLY_PROP_VOLTAGE_MAX,
    158	POWER_SUPPLY_PROP_CURRENT_MAX,
    159};
    160
    161static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
    162{
    163	unsigned long irq_flags;
    164	struct goldfish_battery_data *data = dev_id;
    165	uint32_t status;
    166
    167	spin_lock_irqsave(&data->lock, irq_flags);
    168
    169	/* read status flags, which will clear the interrupt */
    170	status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
    171	status &= BATTERY_INT_MASK;
    172
    173	if (status & BATTERY_STATUS_CHANGED)
    174		power_supply_changed(data->battery);
    175	if (status & AC_STATUS_CHANGED)
    176		power_supply_changed(data->ac);
    177
    178	spin_unlock_irqrestore(&data->lock, irq_flags);
    179	return status ? IRQ_HANDLED : IRQ_NONE;
    180}
    181
    182static const struct power_supply_desc battery_desc = {
    183	.properties	= goldfish_battery_props,
    184	.num_properties	= ARRAY_SIZE(goldfish_battery_props),
    185	.get_property	= goldfish_battery_get_property,
    186	.name		= "battery",
    187	.type		= POWER_SUPPLY_TYPE_BATTERY,
    188};
    189
    190static const struct power_supply_desc ac_desc = {
    191	.properties	= goldfish_ac_props,
    192	.num_properties	= ARRAY_SIZE(goldfish_ac_props),
    193	.get_property	= goldfish_ac_get_property,
    194	.name		= "ac",
    195	.type		= POWER_SUPPLY_TYPE_MAINS,
    196};
    197
    198static int goldfish_battery_probe(struct platform_device *pdev)
    199{
    200	int ret;
    201	struct resource *r;
    202	struct goldfish_battery_data *data;
    203	struct power_supply_config psy_cfg = {};
    204
    205	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    206	if (data == NULL)
    207		return -ENOMEM;
    208
    209	spin_lock_init(&data->lock);
    210
    211	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    212	if (r == NULL) {
    213		dev_err(&pdev->dev, "platform_get_resource failed\n");
    214		return -ENODEV;
    215	}
    216
    217	data->reg_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
    218	if (data->reg_base == NULL) {
    219		dev_err(&pdev->dev, "unable to remap MMIO\n");
    220		return -ENOMEM;
    221	}
    222
    223	data->irq = platform_get_irq(pdev, 0);
    224	if (data->irq < 0) {
    225		dev_err(&pdev->dev, "platform_get_irq failed\n");
    226		return -ENODEV;
    227	}
    228
    229	ret = devm_request_irq(&pdev->dev, data->irq,
    230			       goldfish_battery_interrupt,
    231			       IRQF_SHARED, pdev->name, data);
    232	if (ret)
    233		return ret;
    234
    235	psy_cfg.drv_data = data;
    236
    237	data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);
    238	if (IS_ERR(data->ac))
    239		return PTR_ERR(data->ac);
    240
    241	data->battery = power_supply_register(&pdev->dev, &battery_desc,
    242						&psy_cfg);
    243	if (IS_ERR(data->battery)) {
    244		power_supply_unregister(data->ac);
    245		return PTR_ERR(data->battery);
    246	}
    247
    248	platform_set_drvdata(pdev, data);
    249
    250	GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
    251	return 0;
    252}
    253
    254static int goldfish_battery_remove(struct platform_device *pdev)
    255{
    256	struct goldfish_battery_data *data = platform_get_drvdata(pdev);
    257
    258	power_supply_unregister(data->battery);
    259	power_supply_unregister(data->ac);
    260	return 0;
    261}
    262
    263static const struct of_device_id goldfish_battery_of_match[] = {
    264	{ .compatible = "google,goldfish-battery", },
    265	{},
    266};
    267MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);
    268
    269#ifdef CONFIG_ACPI
    270static const struct acpi_device_id goldfish_battery_acpi_match[] = {
    271	{ "GFSH0001", 0 },
    272	{ },
    273};
    274MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
    275#endif
    276
    277static struct platform_driver goldfish_battery_device = {
    278	.probe		= goldfish_battery_probe,
    279	.remove		= goldfish_battery_remove,
    280	.driver = {
    281		.name = "goldfish-battery",
    282		.of_match_table = goldfish_battery_of_match,
    283		.acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),
    284	}
    285};
    286module_platform_driver(goldfish_battery_device);
    287
    288MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
    289MODULE_LICENSE("GPL");
    290MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");