blob: 03f57615be56efd6c0f5a008efca861bb7b81a75 [file] [log] [blame]
Pali Rohár04930ba2012-10-31 10:48:40 +01001/*
2 * Nokia RX-51 battery driver
3 *
4 * Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
5 *
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.
10 *
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.
15 *
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.
19 */
20
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>
27
Marek Belisko8e2747f2013-08-22 00:45:10 +020028/* RX51 specific channels */
29#define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
30#define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
31
Pali Rohár04930ba2012-10-31 10:48:40 +010032struct rx51_device_info {
33 struct device *dev;
34 struct power_supply bat;
35};
36
37/*
38 * Read ADCIN channel value, code copied from maemo kernel
39 */
40static int rx51_battery_read_adc(int channel)
41{
42 struct twl4030_madc_request req;
43
Marek Belisko8e2747f2013-08-22 00:45:10 +020044 req.channels = channel;
Pali Rohár04930ba2012-10-31 10:48:40 +010045 req.do_avg = 1;
46 req.method = TWL4030_MADC_SW1;
47 req.func_cb = NULL;
48 req.type = TWL4030_MADC_WAIT;
Pali Rohár8059c1c2013-02-15 23:56:50 +010049 req.raw = true;
Pali Rohár04930ba2012-10-31 10:48:40 +010050
51 if (twl4030_madc_conversion(&req) <= 0)
52 return -ENODATA;
53
54 return req.rbuf[channel];
55}
56
57/*
58 * Read ADCIN channel 12 (voltage) and convert RAW value to micro voltage
59 * This conversion formula was extracted from maemo program bsi-read
60 */
61static int rx51_battery_read_voltage(struct rx51_device_info *di)
62{
Marek Belisko8e2747f2013-08-22 00:45:10 +020063 int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
Pali Rohár04930ba2012-10-31 10:48:40 +010064
65 if (voltage < 0)
66 return voltage;
67
68 return 1000 * (10000 * voltage / 1705);
69}
70
71/*
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
77 */
78
79/*
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
84 */
85static 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
88};
89
90/*
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
95 */
96#define rx51_temp_table2_first 53
97static 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,
104 937, 993, 1024
105};
106
107/*
108 * Read ADCIN channel 0 (battery temp) and convert value to tenths of Celsius
109 * Use Temperature look-up tables for conversation
110 */
111static int rx51_battery_read_temperature(struct rx51_device_info *di)
112{
113 int min = 0;
114 int max = ARRAY_SIZE(rx51_temp_table2) - 1;
Marek Belisko8e2747f2013-08-22 00:45:10 +0200115 int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
Pali Rohár04930ba2012-10-31 10:48:40 +0100116
117 /* Zero and negative values are undefined */
118 if (raw <= 0)
119 return INT_MAX;
120
121 /* ADC channels are 10 bit, higher value are undefined */
122 if (raw >= (1 << 10))
123 return INT_MIN;
124
125 /* First check for temperature in first direct table */
126 if (raw < ARRAY_SIZE(rx51_temp_table1))
Pali Rohár59584852013-03-28 17:42:23 +0100127 return rx51_temp_table1[raw] * 10;
Pali Rohár04930ba2012-10-31 10:48:40 +0100128
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)
133 min = mid;
134 else if (rx51_temp_table2[mid] > raw)
135 max = mid;
136 if (rx51_temp_table2[mid] == raw)
137 break;
138 }
139
Pali Rohár59584852013-03-28 17:42:23 +0100140 return (rx51_temp_table2_first - min) * 10;
Pali Rohár04930ba2012-10-31 10:48:40 +0100141}
142
143/*
144 * Read ADCIN channel 4 (BSI) and convert RAW value to micro Ah
145 * This conversion formula was extracted from maemo program bsi-read
146 */
147static int rx51_battery_read_capacity(struct rx51_device_info *di)
148{
Marek Belisko8e2747f2013-08-22 00:45:10 +0200149 int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
Pali Rohár04930ba2012-10-31 10:48:40 +0100150
151 if (capacity < 0)
152 return capacity;
153
154 return 1280 * (1200 * capacity)/(1024 - capacity);
155}
156
157/*
158 * Return power_supply property
159 */
160static int rx51_battery_get_property(struct power_supply *psy,
161 enum power_supply_property psp,
162 union power_supply_propval *val)
163{
164 struct rx51_device_info *di = container_of((psy),
165 struct rx51_device_info, bat);
166
167 switch (psp) {
168 case POWER_SUPPLY_PROP_TECHNOLOGY:
169 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
170 break;
171 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
172 val->intval = 4200000;
173 break;
174 case POWER_SUPPLY_PROP_PRESENT:
175 val->intval = rx51_battery_read_voltage(di) ? 1 : 0;
176 break;
177 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
178 val->intval = rx51_battery_read_voltage(di);
179 break;
180 case POWER_SUPPLY_PROP_TEMP:
181 val->intval = rx51_battery_read_temperature(di);
182 break;
183 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
184 val->intval = rx51_battery_read_capacity(di);
185 break;
186 default:
187 return -EINVAL;
188 }
189
190 if (val->intval == INT_MAX || val->intval == INT_MIN)
191 return -EINVAL;
192
193 return 0;
194}
195
196static 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,
203};
204
Greg Kroah-Hartman6d2cea42012-12-21 15:04:54 -0800205static int rx51_battery_probe(struct platform_device *pdev)
Pali Rohár04930ba2012-10-31 10:48:40 +0100206{
207 struct rx51_device_info *di;
208 int ret;
209
Jingoo Hanb852ac52013-03-11 15:35:58 +0900210 di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
Pali Rohár04930ba2012-10-31 10:48:40 +0100211 if (!di)
212 return -ENOMEM;
213
214 platform_set_drvdata(pdev, di);
215
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;
221
222 ret = power_supply_register(di->dev, &di->bat);
Jingoo Hanf70d7392013-05-06 13:23:45 +0900223 if (ret)
Pali Rohár04930ba2012-10-31 10:48:40 +0100224 return ret;
Pali Rohár04930ba2012-10-31 10:48:40 +0100225
226 return 0;
227}
228
Greg Kroah-Hartman6d2cea42012-12-21 15:04:54 -0800229static int rx51_battery_remove(struct platform_device *pdev)
Pali Rohár04930ba2012-10-31 10:48:40 +0100230{
231 struct rx51_device_info *di = platform_get_drvdata(pdev);
232
233 power_supply_unregister(&di->bat);
Pali Rohár04930ba2012-10-31 10:48:40 +0100234
235 return 0;
236}
237
238static struct platform_driver rx51_battery_driver = {
239 .probe = rx51_battery_probe,
Greg Kroah-Hartman6d2cea42012-12-21 15:04:54 -0800240 .remove = rx51_battery_remove,
Pali Rohár04930ba2012-10-31 10:48:40 +0100241 .driver = {
242 .name = "rx51-battery",
243 .owner = THIS_MODULE,
244 },
245};
246module_platform_driver(rx51_battery_driver);
247
248MODULE_ALIAS("platform:rx51-battery");
249MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
250MODULE_DESCRIPTION("Nokia RX-51 battery driver");
251MODULE_LICENSE("GPL");