brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 479195e Raw
278 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Power supply driver for the goldfish emulator4 *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		return -ENODEV;226 227	ret = devm_request_irq(&pdev->dev, data->irq,228			       goldfish_battery_interrupt,229			       IRQF_SHARED, pdev->name, data);230	if (ret)231		return ret;232 233	psy_cfg.drv_data = data;234 235	data->ac = devm_power_supply_register(&pdev->dev,236					      &ac_desc,237					      &psy_cfg);238	if (IS_ERR(data->ac))239		return PTR_ERR(data->ac);240 241	data->battery = devm_power_supply_register(&pdev->dev,242						   &battery_desc,243						   &psy_cfg);244	if (IS_ERR(data->battery))245		return PTR_ERR(data->battery);246 247	GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);248	return 0;249}250 251static const struct of_device_id goldfish_battery_of_match[] = {252	{ .compatible = "google,goldfish-battery", },253	{},254};255MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);256 257#ifdef CONFIG_ACPI258static const struct acpi_device_id goldfish_battery_acpi_match[] = {259	{ "GFSH0001", 0 },260	{ },261};262MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);263#endif264 265static struct platform_driver goldfish_battery_device = {266	.probe		= goldfish_battery_probe,267	.driver = {268		.name = "goldfish-battery",269		.of_match_table = goldfish_battery_of_match,270		.acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),271	}272};273module_platform_driver(goldfish_battery_device);274 275MODULE_AUTHOR("Mike Lockwood lockwood@android.com");276MODULE_LICENSE("GPL");277MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");278