Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Nokia RX-51 battery driver
0004  *
0005  * Copyright (C) 2012  Pali Rohár <pali@kernel.org>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/param.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/power_supply.h>
0012 #include <linux/slab.h>
0013 #include <linux/iio/consumer.h>
0014 #include <linux/of.h>
0015 
0016 struct rx51_device_info {
0017     struct device *dev;
0018     struct power_supply *bat;
0019     struct power_supply_desc bat_desc;
0020     struct iio_channel *channel_temp;
0021     struct iio_channel *channel_bsi;
0022     struct iio_channel *channel_vbat;
0023 };
0024 
0025 /*
0026  * Read ADCIN channel value, code copied from maemo kernel
0027  */
0028 static int rx51_battery_read_adc(struct iio_channel *channel)
0029 {
0030     int val, err;
0031     err = iio_read_channel_average_raw(channel, &val);
0032     if (err < 0)
0033         return err;
0034     return val;
0035 }
0036 
0037 /*
0038  * Read ADCIN channel 12 (voltage) and convert RAW value to micro voltage
0039  * This conversion formula was extracted from maemo program bsi-read
0040  */
0041 static int rx51_battery_read_voltage(struct rx51_device_info *di)
0042 {
0043     int voltage = rx51_battery_read_adc(di->channel_vbat);
0044 
0045     if (voltage < 0) {
0046         dev_err(di->dev, "Could not read ADC: %d\n", voltage);
0047         return voltage;
0048     }
0049 
0050     return 1000 * (10000 * voltage / 1705);
0051 }
0052 
0053 /*
0054  * Temperature look-up tables
0055  * TEMP = (1/(t1 + 1/298) - 273.15)
0056  * Where t1 = (1/B) * ln((RAW_ADC_U * 2.5)/(R * I * 255))
0057  * Formula is based on experimental data, RX-51 CAL data, maemo program bme
0058  * and formula from da9052 driver with values R = 100, B = 3380, I = 0.00671
0059  */
0060 
0061 /*
0062  * Table1 (temperature for first 25 RAW values)
0063  * Usage: TEMP = rx51_temp_table1[RAW]
0064  *   RAW is between 1 and 24
0065  *   TEMP is between 201 C and 55 C
0066  */
0067 static u8 rx51_temp_table1[] = {
0068     255, 201, 159, 138, 124, 114, 106,  99,  94,  89,  85,  82,  78,  75,
0069      73,  70,  68,  66,  64,  62,  61,  59,  57,  56,  55
0070 };
0071 
0072 /*
0073  * Table2 (lowest RAW value for temperature)
0074  * Usage: RAW = rx51_temp_table2[TEMP-rx51_temp_table2_first]
0075  *   TEMP is between 53 C and -32 C
0076  *   RAW is between 25 and 993
0077  */
0078 #define rx51_temp_table2_first 53
0079 static u16 rx51_temp_table2[] = {
0080      25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  39,
0081      40,  41,  43,  44,  46,  48,  49,  51,  53,  55,  57,  59,  61,  64,
0082      66,  69,  71,  74,  77,  80,  83,  86,  90,  94,  97, 101, 106, 110,
0083     115, 119, 125, 130, 136, 141, 148, 154, 161, 168, 176, 184, 202, 211,
0084     221, 231, 242, 254, 266, 279, 293, 308, 323, 340, 357, 375, 395, 415,
0085     437, 460, 485, 511, 539, 568, 600, 633, 669, 706, 747, 790, 836, 885,
0086     937, 993, 1024
0087 };
0088 
0089 /*
0090  * Read ADCIN channel 0 (battery temp) and convert value to tenths of Celsius
0091  * Use Temperature look-up tables for conversation
0092  */
0093 static int rx51_battery_read_temperature(struct rx51_device_info *di)
0094 {
0095     int min = 0;
0096     int max = ARRAY_SIZE(rx51_temp_table2) - 1;
0097     int raw = rx51_battery_read_adc(di->channel_temp);
0098 
0099     if (raw < 0)
0100         dev_err(di->dev, "Could not read ADC: %d\n", raw);
0101 
0102     /* Zero and negative values are undefined */
0103     if (raw <= 0)
0104         return INT_MAX;
0105 
0106     /* ADC channels are 10 bit, higher value are undefined */
0107     if (raw >= (1 << 10))
0108         return INT_MIN;
0109 
0110     /* First check for temperature in first direct table */
0111     if (raw < ARRAY_SIZE(rx51_temp_table1))
0112         return rx51_temp_table1[raw] * 10;
0113 
0114     /* Binary search RAW value in second inverse table */
0115     while (max - min > 1) {
0116         int mid = (max + min) / 2;
0117         if (rx51_temp_table2[mid] <= raw)
0118             min = mid;
0119         else if (rx51_temp_table2[mid] > raw)
0120             max = mid;
0121         if (rx51_temp_table2[mid] == raw)
0122             break;
0123     }
0124 
0125     return (rx51_temp_table2_first - min) * 10;
0126 }
0127 
0128 /*
0129  * Read ADCIN channel 4 (BSI) and convert RAW value to micro Ah
0130  * This conversion formula was extracted from maemo program bsi-read
0131  */
0132 static int rx51_battery_read_capacity(struct rx51_device_info *di)
0133 {
0134     int capacity = rx51_battery_read_adc(di->channel_bsi);
0135 
0136     if (capacity < 0) {
0137         dev_err(di->dev, "Could not read ADC: %d\n", capacity);
0138         return capacity;
0139     }
0140 
0141     return 1280 * (1200 * capacity)/(1024 - capacity);
0142 }
0143 
0144 /*
0145  * Return power_supply property
0146  */
0147 static int rx51_battery_get_property(struct power_supply *psy,
0148                     enum power_supply_property psp,
0149                     union power_supply_propval *val)
0150 {
0151     struct rx51_device_info *di = power_supply_get_drvdata(psy);
0152 
0153     switch (psp) {
0154     case POWER_SUPPLY_PROP_TECHNOLOGY:
0155         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0156         break;
0157     case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
0158         val->intval = 4200000;
0159         break;
0160     case POWER_SUPPLY_PROP_PRESENT:
0161         val->intval = rx51_battery_read_voltage(di) ? 1 : 0;
0162         break;
0163     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0164         val->intval = rx51_battery_read_voltage(di);
0165         break;
0166     case POWER_SUPPLY_PROP_TEMP:
0167         val->intval = rx51_battery_read_temperature(di);
0168         break;
0169     case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
0170         val->intval = rx51_battery_read_capacity(di);
0171         break;
0172     default:
0173         return -EINVAL;
0174     }
0175 
0176     if (val->intval == INT_MAX || val->intval == INT_MIN)
0177         return -EINVAL;
0178 
0179     return 0;
0180 }
0181 
0182 static enum power_supply_property rx51_battery_props[] = {
0183     POWER_SUPPLY_PROP_TECHNOLOGY,
0184     POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
0185     POWER_SUPPLY_PROP_PRESENT,
0186     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0187     POWER_SUPPLY_PROP_TEMP,
0188     POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
0189 };
0190 
0191 static int rx51_battery_probe(struct platform_device *pdev)
0192 {
0193     struct power_supply_config psy_cfg = {};
0194     struct rx51_device_info *di;
0195     int ret;
0196 
0197     di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
0198     if (!di)
0199         return -ENOMEM;
0200 
0201     platform_set_drvdata(pdev, di);
0202 
0203     di->dev = &pdev->dev;
0204     di->bat_desc.name = "rx51-battery";
0205     di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
0206     di->bat_desc.properties = rx51_battery_props;
0207     di->bat_desc.num_properties = ARRAY_SIZE(rx51_battery_props);
0208     di->bat_desc.get_property = rx51_battery_get_property;
0209 
0210     psy_cfg.drv_data = di;
0211 
0212     di->channel_temp = iio_channel_get(di->dev, "temp");
0213     if (IS_ERR(di->channel_temp)) {
0214         ret = PTR_ERR(di->channel_temp);
0215         goto error;
0216     }
0217 
0218     di->channel_bsi  = iio_channel_get(di->dev, "bsi");
0219     if (IS_ERR(di->channel_bsi)) {
0220         ret = PTR_ERR(di->channel_bsi);
0221         goto error_channel_temp;
0222     }
0223 
0224     di->channel_vbat = iio_channel_get(di->dev, "vbat");
0225     if (IS_ERR(di->channel_vbat)) {
0226         ret = PTR_ERR(di->channel_vbat);
0227         goto error_channel_bsi;
0228     }
0229 
0230     di->bat = power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
0231     if (IS_ERR(di->bat)) {
0232         ret = PTR_ERR(di->bat);
0233         goto error_channel_vbat;
0234     }
0235 
0236     return 0;
0237 
0238 error_channel_vbat:
0239     iio_channel_release(di->channel_vbat);
0240 error_channel_bsi:
0241     iio_channel_release(di->channel_bsi);
0242 error_channel_temp:
0243     iio_channel_release(di->channel_temp);
0244 error:
0245 
0246     return ret;
0247 }
0248 
0249 static int rx51_battery_remove(struct platform_device *pdev)
0250 {
0251     struct rx51_device_info *di = platform_get_drvdata(pdev);
0252 
0253     power_supply_unregister(di->bat);
0254 
0255     iio_channel_release(di->channel_vbat);
0256     iio_channel_release(di->channel_bsi);
0257     iio_channel_release(di->channel_temp);
0258 
0259     return 0;
0260 }
0261 
0262 #ifdef CONFIG_OF
0263 static const struct of_device_id n900_battery_of_match[] = {
0264     {.compatible = "nokia,n900-battery", },
0265     { },
0266 };
0267 MODULE_DEVICE_TABLE(of, n900_battery_of_match);
0268 #endif
0269 
0270 static struct platform_driver rx51_battery_driver = {
0271     .probe = rx51_battery_probe,
0272     .remove = rx51_battery_remove,
0273     .driver = {
0274         .name = "rx51-battery",
0275         .of_match_table = of_match_ptr(n900_battery_of_match),
0276     },
0277 };
0278 module_platform_driver(rx51_battery_driver);
0279 
0280 MODULE_ALIAS("platform:rx51-battery");
0281 MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
0282 MODULE_DESCRIPTION("Nokia RX-51 battery driver");
0283 MODULE_LICENSE("GPL");