2 +++ kernel-power/drivers/power/rx51_battery.c
5 + rx51_battery.c - Nokia RX-51 battery driver
6 + Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
8 + This program is free software; you can redistribute it and/or modify
9 + it under the terms of the GNU General Public License as published by
10 + the Free Software Foundation; either version 2 of the License, or
11 + (at your option) any later version.
13 + This program is distributed in the hope that it will be useful,
14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 + GNU General Public License for more details.
18 + You should have received a copy of the GNU General Public License along
19 + with this program; if not, write to the Free Software Foundation, Inc.,
20 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 +#include <linux/module.h>
24 +#include <linux/param.h>
25 +#include <linux/platform_device.h>
26 +#include <linux/power_supply.h>
27 +#include <linux/slab.h>
28 +#include <linux/i2c/twl4030-madc.h>
30 +struct rx51_device_info {
32 + struct power_supply bat;
35 +/* Read ADCIN channel value, code copied from maemo kernel */
36 +static int rx51_battery_read_adc(int channel)
38 + struct twl4030_madc_request req;
40 + req.channels = (1 << channel);
42 + req.method = TWL4030_MADC_SW1;
44 + req.type = TWL4030_MADC_WAIT;
46 + if (twl4030_madc_conversion(&req) > 0)
47 + return (u16)req.rbuf[channel];
52 +/* Read ADCIN channel 12 (voltage) and convert RAW value to micro voltage */
53 +/* This conversion formula was extracted from maemo program bsi-read */
54 +static int rx51_battery_read_voltage(struct rx51_device_info *di)
56 + int voltage = rx51_battery_read_adc(12);
59 + return (((((2099203 - (1LL<<31)) * voltage * 6000) >> 32) -
60 + ((voltage * 6000LL << 1) >> 32) + (voltage * 6000)) >> 9)*1000;
63 +/* Conversation table based on experimental data */
64 +/* Usage: rx51_temp_table[rx51_temp_first - Celsius value] = lowest RAW value */
65 +static int rx51_temp_first = 48;
66 +static int rx51_temp_table[] = {
67 + 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 42, 43, 45, 47,
68 + 48, 50, 51, 53, 55, 57, 59, 61, 63, 66, 69, 72, 74, 76,
69 + 80, 83, 86, 90, 93, 96, 100, 105, 109, 114, 119, 124, 130, 136,
70 + 142, 148, 155, 161, 166, 177, 184, 193, 202, 213, 222, 230, 243, 255,
74 +/* Read ADCIN channel 0 (battery temp) and convert value to tenths of Celsius */
75 +/* Try to find lowest temperature value for raw value in table */
76 +static int rx51_battery_read_temperature(struct rx51_device_info *di)
79 + int max = ARRAY_SIZE(rx51_temp_table)-1;
80 + int temperature = rx51_battery_read_adc(0);
82 + if (temperature < 0)
84 + if (temperature < rx51_temp_table[min])
85 + return rx51_temp_first-min+1;
86 + if (temperature > rx51_temp_table[max])
87 + return rx51_temp_first-max-1;
89 + while (max-min > 1) {
90 + int mid = (max+min)/2;
91 + if (rx51_temp_table[mid] <= temperature)
93 + else if (rx51_temp_table[mid] > temperature)
95 + if (rx51_temp_table[mid] == temperature)
99 + return (rx51_temp_first - min) * 100;
102 +/* Read ADCIN channel 4 (BSI) and convert RAW value to micro Ah */
103 +/* This conversion formula was extracted from maemo program bsi-read */
104 +static int rx51_battery_read_capacity(struct rx51_device_info *di)
106 + int capacity = rx51_battery_read_adc(4);
109 + return 1280 * (1200 * capacity)/(1024 - capacity);
112 +/* Return power_supply property */
113 +static int rx51_battery_get_property(struct power_supply *psy,
114 + enum power_supply_property psp,
115 + union power_supply_propval *val)
117 + struct rx51_device_info *di = container_of((psy),
118 + struct rx51_device_info, bat);
121 + case POWER_SUPPLY_PROP_TECHNOLOGY:
122 + val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
124 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
125 + val->intval = 4200000;
127 + case POWER_SUPPLY_PROP_PRESENT:
128 + val->intval = rx51_battery_read_voltage(di) ? 1 : 0;
130 + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
131 + val->intval = rx51_battery_read_voltage(di);
133 + case POWER_SUPPLY_PROP_TEMP:
134 + val->intval = rx51_battery_read_temperature(di);
136 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
137 + val->intval = rx51_battery_read_capacity(di);
143 + if (val->intval < 0)
144 + return val->intval;
149 +static enum power_supply_property rx51_battery_props[] = {
150 + POWER_SUPPLY_PROP_TECHNOLOGY,
151 + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
152 + POWER_SUPPLY_PROP_PRESENT,
153 + POWER_SUPPLY_PROP_VOLTAGE_NOW,
154 + POWER_SUPPLY_PROP_TEMP,
155 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
158 +static int __devinit rx51_battery_probe(struct platform_device *pdev)
160 + struct rx51_device_info *di;
163 + di = kzalloc(sizeof(*di), GFP_KERNEL);
167 + platform_set_drvdata(pdev, di);
169 + di->bat.name = dev_name(&pdev->dev);
170 + di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
171 + di->bat.properties = rx51_battery_props;
172 + di->bat.num_properties = ARRAY_SIZE(rx51_battery_props);
173 + di->bat.get_property = rx51_battery_get_property;
175 + ret = power_supply_register(di->dev, &di->bat);
177 + platform_set_drvdata(pdev, NULL);
185 +static int __devexit rx51_battery_remove(struct platform_device *pdev)
187 + struct rx51_device_info *di = platform_get_drvdata(pdev);
189 + power_supply_unregister(&di->bat);
190 + platform_set_drvdata(pdev, NULL);
196 +static struct platform_driver rx51_battery_driver = {
197 + .probe = rx51_battery_probe,
198 + .remove = __devexit_p(rx51_battery_remove),
200 + .name = "rx51-battery",
201 + .owner = THIS_MODULE,
205 +static int __init rx51_battery_init(void)
207 + return platform_driver_register(&rx51_battery_driver);
209 +module_init(rx51_battery_init);
211 +static void __exit rx51_battery_exit(void)
213 + platform_driver_unregister(&rx51_battery_driver);
215 +module_exit(rx51_battery_exit);
217 +MODULE_ALIAS("platform:rx51-battery");
218 +MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
219 +MODULE_DESCRIPTION("Nokia RX-51 battery driver");
220 +MODULE_LICENSE("GPL");