2 * Nokia RX-51 battery driver
4 * Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <linux/module.h>
22 #include <linux/param.h>
23 #include <linux/platform_device.h>
24 #include <linux/power_supply.h>
25 #include <linux/slab.h>
26 #include <linux/i2c/twl4030-madc.h>
28 /* RX51 specific channels */
29 #define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
30 #define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
32 struct rx51_device_info {
34 struct power_supply bat;
38 * Read ADCIN channel value, code copied from maemo kernel
40 static int rx51_battery_read_adc(int channel)
42 struct twl4030_madc_request req;
44 req.channels = channel;
46 req.method = TWL4030_MADC_SW1;
48 req.type = TWL4030_MADC_WAIT;
51 if (twl4030_madc_conversion(&req) <= 0)
54 return req.rbuf[ffs(channel) - 1];
58 * Read ADCIN channel 12 (voltage) and convert RAW value to micro voltage
59 * This conversion formula was extracted from maemo program bsi-read
61 static int rx51_battery_read_voltage(struct rx51_device_info *di)
63 int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
68 return 1000 * (10000 * voltage / 1705);
72 * Temperature look-up tables
73 * TEMP = (1/(t1 + 1/298) - 273.15)
74 * Where t1 = (1/B) * ln((RAW_ADC_U * 2.5)/(R * I * 255))
75 * Formula is based on experimental data, RX-51 CAL data, maemo program bme
76 * and formula from da9052 driver with values R = 100, B = 3380, I = 0.00671
80 * Table1 (temperature for first 25 RAW values)
81 * Usage: TEMP = rx51_temp_table1[RAW]
82 * RAW is between 1 and 24
83 * TEMP is between 201 C and 55 C
85 static u8 rx51_temp_table1[] = {
86 255, 201, 159, 138, 124, 114, 106, 99, 94, 89, 85, 82, 78, 75,
87 73, 70, 68, 66, 64, 62, 61, 59, 57, 56, 55
91 * Table2 (lowest RAW value for temperature)
92 * Usage: RAW = rx51_temp_table2[TEMP-rx51_temp_table2_first]
93 * TEMP is between 53 C and -32 C
94 * RAW is between 25 and 993
96 #define rx51_temp_table2_first 53
97 static u16 rx51_temp_table2[] = {
98 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39,
99 40, 41, 43, 44, 46, 48, 49, 51, 53, 55, 57, 59, 61, 64,
100 66, 69, 71, 74, 77, 80, 83, 86, 90, 94, 97, 101, 106, 110,
101 115, 119, 125, 130, 136, 141, 148, 154, 161, 168, 176, 184, 202, 211,
102 221, 231, 242, 254, 266, 279, 293, 308, 323, 340, 357, 375, 395, 415,
103 437, 460, 485, 511, 539, 568, 600, 633, 669, 706, 747, 790, 836, 885,
108 * Read ADCIN channel 0 (battery temp) and convert value to tenths of Celsius
109 * Use Temperature look-up tables for conversation
111 static int rx51_battery_read_temperature(struct rx51_device_info *di)
114 int max = ARRAY_SIZE(rx51_temp_table2) - 1;
115 int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
117 /* Zero and negative values are undefined */
121 /* ADC channels are 10 bit, higher value are undefined */
122 if (raw >= (1 << 10))
125 /* First check for temperature in first direct table */
126 if (raw < ARRAY_SIZE(rx51_temp_table1))
127 return rx51_temp_table1[raw] * 10;
129 /* Binary search RAW value in second inverse table */
130 while (max - min > 1) {
131 int mid = (max + min) / 2;
132 if (rx51_temp_table2[mid] <= raw)
134 else if (rx51_temp_table2[mid] > raw)
136 if (rx51_temp_table2[mid] == raw)
140 return (rx51_temp_table2_first - min) * 10;
144 * Read ADCIN channel 4 (BSI) and convert RAW value to micro Ah
145 * This conversion formula was extracted from maemo program bsi-read
147 static int rx51_battery_read_capacity(struct rx51_device_info *di)
149 int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
154 return 1280 * (1200 * capacity)/(1024 - capacity);
158 * Return power_supply property
160 static int rx51_battery_get_property(struct power_supply *psy,
161 enum power_supply_property psp,
162 union power_supply_propval *val)
164 struct rx51_device_info *di = container_of((psy),
165 struct rx51_device_info, bat);
168 case POWER_SUPPLY_PROP_TECHNOLOGY:
169 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
171 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
172 val->intval = 4200000;
174 case POWER_SUPPLY_PROP_PRESENT:
175 val->intval = rx51_battery_read_voltage(di) ? 1 : 0;
177 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
178 val->intval = rx51_battery_read_voltage(di);
180 case POWER_SUPPLY_PROP_TEMP:
181 val->intval = rx51_battery_read_temperature(di);
183 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
184 val->intval = rx51_battery_read_capacity(di);
190 if (val->intval == INT_MAX || val->intval == INT_MIN)
196 static enum power_supply_property rx51_battery_props[] = {
197 POWER_SUPPLY_PROP_TECHNOLOGY,
198 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
199 POWER_SUPPLY_PROP_PRESENT,
200 POWER_SUPPLY_PROP_VOLTAGE_NOW,
201 POWER_SUPPLY_PROP_TEMP,
202 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
205 static int rx51_battery_probe(struct platform_device *pdev)
207 struct rx51_device_info *di;
210 di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
214 platform_set_drvdata(pdev, di);
216 di->bat.name = dev_name(&pdev->dev);
217 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
218 di->bat.properties = rx51_battery_props;
219 di->bat.num_properties = ARRAY_SIZE(rx51_battery_props);
220 di->bat.get_property = rx51_battery_get_property;
222 ret = power_supply_register(di->dev, &di->bat);
229 static int rx51_battery_remove(struct platform_device *pdev)
231 struct rx51_device_info *di = platform_get_drvdata(pdev);
233 power_supply_unregister(&di->bat);
238 static struct platform_driver rx51_battery_driver = {
239 .probe = rx51_battery_probe,
240 .remove = rx51_battery_remove,
242 .name = "rx51-battery",
243 .owner = THIS_MODULE,
246 module_platform_driver(rx51_battery_driver);
248 MODULE_ALIAS("platform:rx51-battery");
249 MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
250 MODULE_DESCRIPTION("Nokia RX-51 battery driver");
251 MODULE_LICENSE("GPL");