Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/power/rx51_battery.c

  1 /*
  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 
 28 /* RX51 specific channels */
 29 #define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
 30 #define TWL4030_MADC_BCI_RX51   TWL4030_MADC_ADCIN4
 31 
 32 struct 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  */
 40 static int rx51_battery_read_adc(int channel)
 41 {
 42         struct twl4030_madc_request req;
 43 
 44         req.channels = channel;
 45         req.do_avg = 1;
 46         req.method = TWL4030_MADC_SW1;
 47         req.func_cb = NULL;
 48         req.type = TWL4030_MADC_WAIT;
 49         req.raw = true;
 50 
 51         if (twl4030_madc_conversion(&req) <= 0)
 52                 return -ENODATA;
 53 
 54         return req.rbuf[ffs(channel) - 1];
 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  */
 61 static int rx51_battery_read_voltage(struct rx51_device_info *di)
 62 {
 63         int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
 64 
 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  */
 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
 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
 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,
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  */
111 static int rx51_battery_read_temperature(struct rx51_device_info *di)
112 {
113         int min = 0;
114         int max = ARRAY_SIZE(rx51_temp_table2) - 1;
115         int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
116 
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))
127                 return rx51_temp_table1[raw] * 10;
128 
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 
140         return (rx51_temp_table2_first - min) * 10;
141 }
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  */
147 static int rx51_battery_read_capacity(struct rx51_device_info *di)
148 {
149         int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
150 
151         if (capacity < 0)
152                 return capacity;
153 
154         return 1280 * (1200 * capacity)/(1024 - capacity);
155 }
156 
157 /*
158  * Return power_supply property
159  */
160 static 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 
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,
203 };
204 
205 static int rx51_battery_probe(struct platform_device *pdev)
206 {
207         struct rx51_device_info *di;
208         int ret;
209 
210         di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
211         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);
223         if (ret)
224                 return ret;
225 
226         return 0;
227 }
228 
229 static int rx51_battery_remove(struct platform_device *pdev)
230 {
231         struct rx51_device_info *di = platform_get_drvdata(pdev);
232 
233         power_supply_unregister(&di->bat);
234 
235         return 0;
236 }
237 
238 static struct platform_driver rx51_battery_driver = {
239         .probe = rx51_battery_probe,
240         .remove = rx51_battery_remove,
241         .driver = {
242                 .name = "rx51-battery",
243                 .owner = THIS_MODULE,
244         },
245 };
246 module_platform_driver(rx51_battery_driver);
247 
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");
252 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us