1 // SPDX-License-Identifier: GPL-2.0+
3 * Battery driver for Acer Iconia Tab A500.
5 * Copyright 2020 GRATE-driver project.
7 * Based on downstream driver from Acer Inc.
8 * Based on NVIDIA Gas Gauge driver for SBS Compliant Batteries.
10 * Copyright (c) 2010, NVIDIA Corporation.
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/power_supply.h>
16 #include <linux/regmap.h>
17 #include <linux/sched.h>
18 #include <linux/slab.h>
19 #include <linux/workqueue.h>
29 #define EC_DATA(_reg, _psp) { \
30 .psp = POWER_SUPPLY_PROP_ ## _psp, \
34 static const struct battery_register
{
35 enum power_supply_property psp
;
38 [REG_CAPACITY
] = EC_DATA(0x00, CAPACITY
),
39 [REG_VOLTAGE
] = EC_DATA(0x01, VOLTAGE_NOW
),
40 [REG_CURRENT
] = EC_DATA(0x03, CURRENT_NOW
),
41 [REG_DESIGN_CAPACITY
] = EC_DATA(0x08, CHARGE_FULL_DESIGN
),
42 [REG_TEMPERATURE
] = EC_DATA(0x0a, TEMP
),
45 static const enum power_supply_property a500_battery_properties
[] = {
46 POWER_SUPPLY_PROP_CAPACITY
,
47 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
48 POWER_SUPPLY_PROP_CURRENT_NOW
,
49 POWER_SUPPLY_PROP_PRESENT
,
50 POWER_SUPPLY_PROP_STATUS
,
51 POWER_SUPPLY_PROP_TECHNOLOGY
,
52 POWER_SUPPLY_PROP_TEMP
,
53 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
57 struct delayed_work poll_work
;
58 struct power_supply
*psy
;
59 struct regmap
*regmap
;
60 unsigned int capacity
;
63 static bool a500_battery_update_capacity(struct a500_battery
*bat
)
65 unsigned int capacity
;
68 err
= regmap_read(bat
->regmap
, ec_data
[REG_CAPACITY
].reg
, &capacity
);
72 /* capacity can be >100% even if max value is 100% */
73 capacity
= min(capacity
, 100u);
75 if (bat
->capacity
!= capacity
) {
76 bat
->capacity
= capacity
;
83 static int a500_battery_get_status(struct a500_battery
*bat
)
85 if (bat
->capacity
< 100) {
86 if (power_supply_am_i_supplied(bat
->psy
))
87 return POWER_SUPPLY_STATUS_CHARGING
;
89 return POWER_SUPPLY_STATUS_DISCHARGING
;
92 return POWER_SUPPLY_STATUS_FULL
;
95 static void a500_battery_unit_adjustment(struct device
*dev
,
96 enum power_supply_property psp
,
97 union power_supply_propval
*val
)
99 const unsigned int base_unit_conversion
= 1000;
100 const unsigned int temp_kelvin_to_celsius
= 2731;
103 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
104 case POWER_SUPPLY_PROP_CURRENT_NOW
:
105 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
106 val
->intval
*= base_unit_conversion
;
109 case POWER_SUPPLY_PROP_TEMP
:
110 val
->intval
-= temp_kelvin_to_celsius
;
113 case POWER_SUPPLY_PROP_PRESENT
:
114 val
->intval
= !!val
->intval
;
119 "%s: no need for unit conversion %d\n", __func__
, psp
);
123 static int a500_battery_get_ec_data_index(struct device
*dev
,
124 enum power_supply_property psp
)
129 * DESIGN_CAPACITY register always returns a non-zero value if
130 * battery is connected and zero if disconnected, hence we'll use
131 * it for judging the battery presence.
133 if (psp
== POWER_SUPPLY_PROP_PRESENT
)
134 psp
= POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
;
136 for (i
= 0; i
< ARRAY_SIZE(ec_data
); i
++)
137 if (psp
== ec_data
[i
].psp
)
140 dev_dbg(dev
, "%s: invalid property %u\n", __func__
, psp
);
145 static int a500_battery_get_property(struct power_supply
*psy
,
146 enum power_supply_property psp
,
147 union power_supply_propval
*val
)
149 struct a500_battery
*bat
= power_supply_get_drvdata(psy
);
150 struct device
*dev
= psy
->dev
.parent
;
154 case POWER_SUPPLY_PROP_STATUS
:
155 val
->intval
= a500_battery_get_status(bat
);
158 case POWER_SUPPLY_PROP_TECHNOLOGY
:
159 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LION
;
162 case POWER_SUPPLY_PROP_CAPACITY
:
163 a500_battery_update_capacity(bat
);
164 val
->intval
= bat
->capacity
;
167 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
168 case POWER_SUPPLY_PROP_CURRENT_NOW
:
169 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
170 case POWER_SUPPLY_PROP_PRESENT
:
171 case POWER_SUPPLY_PROP_TEMP
:
172 ret
= a500_battery_get_ec_data_index(dev
, psp
);
176 ret
= regmap_read(bat
->regmap
, ec_data
[ret
].reg
, &val
->intval
);
180 dev_err(dev
, "%s: invalid property %u\n", __func__
, psp
);
185 /* convert units to match requirements of power supply class */
186 a500_battery_unit_adjustment(dev
, psp
, val
);
189 dev_dbg(dev
, "%s: property = %d, value = %x\n",
190 __func__
, psp
, val
->intval
);
192 /* return NODATA for properties if battery not presents */
199 static void a500_battery_poll_work(struct work_struct
*work
)
201 struct a500_battery
*bat
;
202 bool capacity_changed
;
204 bat
= container_of(work
, struct a500_battery
, poll_work
.work
);
205 capacity_changed
= a500_battery_update_capacity(bat
);
207 if (capacity_changed
)
208 power_supply_changed(bat
->psy
);
210 /* continuously send uevent notification */
211 schedule_delayed_work(&bat
->poll_work
, 30 * HZ
);
214 static const struct power_supply_desc a500_battery_desc
= {
215 .name
= "ec-battery",
216 .type
= POWER_SUPPLY_TYPE_BATTERY
,
217 .properties
= a500_battery_properties
,
218 .get_property
= a500_battery_get_property
,
219 .num_properties
= ARRAY_SIZE(a500_battery_properties
),
220 .external_power_changed
= power_supply_changed
,
223 static int a500_battery_probe(struct platform_device
*pdev
)
225 struct power_supply_config psy_cfg
= {};
226 struct a500_battery
*bat
;
228 bat
= devm_kzalloc(&pdev
->dev
, sizeof(*bat
), GFP_KERNEL
);
232 platform_set_drvdata(pdev
, bat
);
234 psy_cfg
.of_node
= pdev
->dev
.parent
->of_node
;
235 psy_cfg
.drv_data
= bat
;
236 psy_cfg
.no_wakeup_source
= true;
238 bat
->regmap
= dev_get_regmap(pdev
->dev
.parent
, "KB930");
242 bat
->psy
= devm_power_supply_register(&pdev
->dev
,
245 if (IS_ERR(bat
->psy
))
246 return dev_err_probe(&pdev
->dev
, PTR_ERR(bat
->psy
),
247 "failed to register battery\n");
249 INIT_DELAYED_WORK(&bat
->poll_work
, a500_battery_poll_work
);
250 schedule_delayed_work(&bat
->poll_work
, HZ
);
255 static void a500_battery_remove(struct platform_device
*pdev
)
257 struct a500_battery
*bat
= dev_get_drvdata(&pdev
->dev
);
259 cancel_delayed_work_sync(&bat
->poll_work
);
262 static int __maybe_unused
a500_battery_suspend(struct device
*dev
)
264 struct a500_battery
*bat
= dev_get_drvdata(dev
);
266 cancel_delayed_work_sync(&bat
->poll_work
);
271 static int __maybe_unused
a500_battery_resume(struct device
*dev
)
273 struct a500_battery
*bat
= dev_get_drvdata(dev
);
275 schedule_delayed_work(&bat
->poll_work
, HZ
);
280 static SIMPLE_DEV_PM_OPS(a500_battery_pm_ops
,
281 a500_battery_suspend
, a500_battery_resume
);
283 static struct platform_driver a500_battery_driver
= {
285 .name
= "acer-a500-iconia-battery",
286 .pm
= &a500_battery_pm_ops
,
288 .probe
= a500_battery_probe
,
289 .remove
= a500_battery_remove
,
291 module_platform_driver(a500_battery_driver
);
293 MODULE_DESCRIPTION("Battery gauge driver for Acer Iconia Tab A500");
294 MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
295 MODULE_ALIAS("platform:acer-a500-iconia-battery");
296 MODULE_LICENSE("GPL");