Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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
 32struct 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
 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 */
 61static 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 */
 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;
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 */
147static 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 */
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
205static 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
229static 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
238static 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};
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");