Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC
0004  *
0005  * Copyright (C) 2009 Bluewater Systems Ltd
0006  *
0007  * Author: Ryan Mallon
0008  *
0009  * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
0010  *
0011  * UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru>
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/types.h>
0017 #include <linux/errno.h>
0018 #include <linux/swab.h>
0019 #include <linux/i2c.h>
0020 #include <linux/delay.h>
0021 #include <linux/idr.h>
0022 #include <linux/power_supply.h>
0023 #include <linux/slab.h>
0024 #include <linux/ds2782_battery.h>
0025 
0026 #define DS2782_REG_RARC     0x06    /* Remaining active relative capacity */
0027 
0028 #define DS278x_REG_VOLT_MSB 0x0c
0029 #define DS278x_REG_TEMP_MSB 0x0a
0030 #define DS278x_REG_CURRENT_MSB  0x0e
0031 
0032 /* EEPROM Block */
0033 #define DS2782_REG_RSNSP    0x69    /* Sense resistor value */
0034 
0035 /* Current unit measurement in uA for a 1 milli-ohm sense resistor */
0036 #define DS2782_CURRENT_UNITS    1563
0037 
0038 #define DS2786_REG_RARC     0x02    /* Remaining active relative capacity */
0039 
0040 #define DS2786_CURRENT_UNITS    25
0041 
0042 #define DS278x_DELAY        1000
0043 
0044 struct ds278x_info;
0045 
0046 struct ds278x_battery_ops {
0047     int (*get_battery_current)(struct ds278x_info *info, int *current_uA);
0048     int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV);
0049     int (*get_battery_capacity)(struct ds278x_info *info, int *capacity);
0050 };
0051 
0052 #define to_ds278x_info(x) power_supply_get_drvdata(x)
0053 
0054 struct ds278x_info {
0055     struct i2c_client   *client;
0056     struct power_supply *battery;
0057     struct power_supply_desc    battery_desc;
0058     const struct ds278x_battery_ops *ops;
0059     struct delayed_work bat_work;
0060     int         id;
0061     int                     rsns;
0062     int         capacity;
0063     int         status;     /* State Of Charge */
0064 };
0065 
0066 static DEFINE_IDR(battery_id);
0067 static DEFINE_MUTEX(battery_lock);
0068 
0069 static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val)
0070 {
0071     int ret;
0072 
0073     ret = i2c_smbus_read_byte_data(info->client, reg);
0074     if (ret < 0) {
0075         dev_err(&info->client->dev, "register read failed\n");
0076         return ret;
0077     }
0078 
0079     *val = ret;
0080     return 0;
0081 }
0082 
0083 static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb,
0084                     s16 *val)
0085 {
0086     int ret;
0087 
0088     ret = i2c_smbus_read_word_data(info->client, reg_msb);
0089     if (ret < 0) {
0090         dev_err(&info->client->dev, "register read failed\n");
0091         return ret;
0092     }
0093 
0094     *val = swab16(ret);
0095     return 0;
0096 }
0097 
0098 static int ds278x_get_temp(struct ds278x_info *info, int *temp)
0099 {
0100     s16 raw;
0101     int err;
0102 
0103     /*
0104      * Temperature is measured in units of 0.125 degrees celcius, the
0105      * power_supply class measures temperature in tenths of degrees
0106      * celsius. The temperature value is stored as a 10 bit number, plus
0107      * sign in the upper bits of a 16 bit register.
0108      */
0109     err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw);
0110     if (err)
0111         return err;
0112     *temp = ((raw / 32) * 125) / 100;
0113     return 0;
0114 }
0115 
0116 static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
0117 {
0118     int sense_res;
0119     int err;
0120     u8 sense_res_raw;
0121     s16 raw;
0122 
0123     /*
0124      * The units of measurement for current are dependent on the value of
0125      * the sense resistor.
0126      */
0127     err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
0128     if (err)
0129         return err;
0130     if (sense_res_raw == 0) {
0131         dev_err(&info->client->dev, "sense resistor value is 0\n");
0132         return -ENXIO;
0133     }
0134     sense_res = 1000 / sense_res_raw;
0135 
0136     dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
0137         sense_res);
0138     err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
0139     if (err)
0140         return err;
0141     *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
0142     return 0;
0143 }
0144 
0145 static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV)
0146 {
0147     s16 raw;
0148     int err;
0149 
0150     /*
0151      * Voltage is measured in units of 4.88mV. The voltage is stored as
0152      * a 10-bit number plus sign, in the upper bits of a 16-bit register
0153      */
0154     err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
0155     if (err)
0156         return err;
0157     *voltage_uV = (raw / 32) * 4800;
0158     return 0;
0159 }
0160 
0161 static int ds2782_get_capacity(struct ds278x_info *info, int *capacity)
0162 {
0163     int err;
0164     u8 raw;
0165 
0166     err = ds278x_read_reg(info, DS2782_REG_RARC, &raw);
0167     if (err)
0168         return err;
0169     *capacity = raw;
0170     return 0;
0171 }
0172 
0173 static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
0174 {
0175     int err;
0176     s16 raw;
0177 
0178     err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
0179     if (err)
0180         return err;
0181     *current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns);
0182     return 0;
0183 }
0184 
0185 static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
0186 {
0187     s16 raw;
0188     int err;
0189 
0190     /*
0191      * Voltage is measured in units of 1.22mV. The voltage is stored as
0192      * a 12-bit number plus sign, in the upper bits of a 16-bit register
0193      */
0194     err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
0195     if (err)
0196         return err;
0197     *voltage_uV = (raw / 8) * 1220;
0198     return 0;
0199 }
0200 
0201 static int ds2786_get_capacity(struct ds278x_info *info, int *capacity)
0202 {
0203     int err;
0204     u8 raw;
0205 
0206     err = ds278x_read_reg(info, DS2786_REG_RARC, &raw);
0207     if (err)
0208         return err;
0209     /* Relative capacity is displayed with resolution 0.5 % */
0210     *capacity = raw/2 ;
0211     return 0;
0212 }
0213 
0214 static int ds278x_get_status(struct ds278x_info *info, int *status)
0215 {
0216     int err;
0217     int current_uA;
0218     int capacity;
0219 
0220     err = info->ops->get_battery_current(info, &current_uA);
0221     if (err)
0222         return err;
0223 
0224     err = info->ops->get_battery_capacity(info, &capacity);
0225     if (err)
0226         return err;
0227 
0228     info->capacity = capacity;
0229 
0230     if (capacity == 100)
0231         *status = POWER_SUPPLY_STATUS_FULL;
0232     else if (current_uA == 0)
0233         *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
0234     else if (current_uA < 0)
0235         *status = POWER_SUPPLY_STATUS_DISCHARGING;
0236     else
0237         *status = POWER_SUPPLY_STATUS_CHARGING;
0238 
0239     return 0;
0240 }
0241 
0242 static int ds278x_battery_get_property(struct power_supply *psy,
0243                        enum power_supply_property prop,
0244                        union power_supply_propval *val)
0245 {
0246     struct ds278x_info *info = to_ds278x_info(psy);
0247     int ret;
0248 
0249     switch (prop) {
0250     case POWER_SUPPLY_PROP_STATUS:
0251         ret = ds278x_get_status(info, &val->intval);
0252         break;
0253 
0254     case POWER_SUPPLY_PROP_CAPACITY:
0255         ret = info->ops->get_battery_capacity(info, &val->intval);
0256         break;
0257 
0258     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0259         ret = info->ops->get_battery_voltage(info, &val->intval);
0260         break;
0261 
0262     case POWER_SUPPLY_PROP_CURRENT_NOW:
0263         ret = info->ops->get_battery_current(info, &val->intval);
0264         break;
0265 
0266     case POWER_SUPPLY_PROP_TEMP:
0267         ret = ds278x_get_temp(info, &val->intval);
0268         break;
0269 
0270     default:
0271         ret = -EINVAL;
0272     }
0273 
0274     return ret;
0275 }
0276 
0277 static void ds278x_bat_update(struct ds278x_info *info)
0278 {
0279     int old_status = info->status;
0280     int old_capacity = info->capacity;
0281 
0282     ds278x_get_status(info, &info->status);
0283 
0284     if ((old_status != info->status) || (old_capacity != info->capacity))
0285         power_supply_changed(info->battery);
0286 }
0287 
0288 static void ds278x_bat_work(struct work_struct *work)
0289 {
0290     struct ds278x_info *info;
0291 
0292     info = container_of(work, struct ds278x_info, bat_work.work);
0293     ds278x_bat_update(info);
0294 
0295     schedule_delayed_work(&info->bat_work, DS278x_DELAY);
0296 }
0297 
0298 static enum power_supply_property ds278x_battery_props[] = {
0299     POWER_SUPPLY_PROP_STATUS,
0300     POWER_SUPPLY_PROP_CAPACITY,
0301     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0302     POWER_SUPPLY_PROP_CURRENT_NOW,
0303     POWER_SUPPLY_PROP_TEMP,
0304 };
0305 
0306 static void ds278x_power_supply_init(struct power_supply_desc *battery)
0307 {
0308     battery->type           = POWER_SUPPLY_TYPE_BATTERY;
0309     battery->properties     = ds278x_battery_props;
0310     battery->num_properties     = ARRAY_SIZE(ds278x_battery_props);
0311     battery->get_property       = ds278x_battery_get_property;
0312     battery->external_power_changed = NULL;
0313 }
0314 
0315 static int ds278x_battery_remove(struct i2c_client *client)
0316 {
0317     struct ds278x_info *info = i2c_get_clientdata(client);
0318     int id = info->id;
0319 
0320     power_supply_unregister(info->battery);
0321     cancel_delayed_work_sync(&info->bat_work);
0322     kfree(info->battery_desc.name);
0323     kfree(info);
0324 
0325     mutex_lock(&battery_lock);
0326     idr_remove(&battery_id, id);
0327     mutex_unlock(&battery_lock);
0328 
0329     return 0;
0330 }
0331 
0332 #ifdef CONFIG_PM_SLEEP
0333 
0334 static int ds278x_suspend(struct device *dev)
0335 {
0336     struct i2c_client *client = to_i2c_client(dev);
0337     struct ds278x_info *info = i2c_get_clientdata(client);
0338 
0339     cancel_delayed_work(&info->bat_work);
0340     return 0;
0341 }
0342 
0343 static int ds278x_resume(struct device *dev)
0344 {
0345     struct i2c_client *client = to_i2c_client(dev);
0346     struct ds278x_info *info = i2c_get_clientdata(client);
0347 
0348     schedule_delayed_work(&info->bat_work, DS278x_DELAY);
0349     return 0;
0350 }
0351 #endif /* CONFIG_PM_SLEEP */
0352 
0353 static SIMPLE_DEV_PM_OPS(ds278x_battery_pm_ops, ds278x_suspend, ds278x_resume);
0354 
0355 enum ds278x_num_id {
0356     DS2782 = 0,
0357     DS2786,
0358 };
0359 
0360 static const struct ds278x_battery_ops ds278x_ops[] = {
0361     [DS2782] = {
0362         .get_battery_current  = ds2782_get_current,
0363         .get_battery_voltage  = ds2782_get_voltage,
0364         .get_battery_capacity = ds2782_get_capacity,
0365     },
0366     [DS2786] = {
0367         .get_battery_current  = ds2786_get_current,
0368         .get_battery_voltage  = ds2786_get_voltage,
0369         .get_battery_capacity = ds2786_get_capacity,
0370     }
0371 };
0372 
0373 static int ds278x_battery_probe(struct i2c_client *client,
0374                 const struct i2c_device_id *id)
0375 {
0376     struct ds278x_platform_data *pdata = client->dev.platform_data;
0377     struct power_supply_config psy_cfg = {};
0378     struct ds278x_info *info;
0379     int ret;
0380     int num;
0381 
0382     /*
0383      * ds2786 should have the sense resistor value set
0384      * in the platform data
0385      */
0386     if (id->driver_data == DS2786 && !pdata) {
0387         dev_err(&client->dev, "missing platform data for ds2786\n");
0388         return -EINVAL;
0389     }
0390 
0391     /* Get an ID for this battery */
0392     mutex_lock(&battery_lock);
0393     ret = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
0394     mutex_unlock(&battery_lock);
0395     if (ret < 0)
0396         goto fail_id;
0397     num = ret;
0398 
0399     info = kzalloc(sizeof(*info), GFP_KERNEL);
0400     if (!info) {
0401         ret = -ENOMEM;
0402         goto fail_info;
0403     }
0404 
0405     info->battery_desc.name = kasprintf(GFP_KERNEL, "%s-%d",
0406                         client->name, num);
0407     if (!info->battery_desc.name) {
0408         ret = -ENOMEM;
0409         goto fail_name;
0410     }
0411 
0412     if (id->driver_data == DS2786)
0413         info->rsns = pdata->rsns;
0414 
0415     i2c_set_clientdata(client, info);
0416     info->client = client;
0417     info->id = num;
0418     info->ops  = &ds278x_ops[id->driver_data];
0419     ds278x_power_supply_init(&info->battery_desc);
0420     psy_cfg.drv_data = info;
0421 
0422     info->capacity = 100;
0423     info->status = POWER_SUPPLY_STATUS_FULL;
0424 
0425     INIT_DELAYED_WORK(&info->bat_work, ds278x_bat_work);
0426 
0427     info->battery = power_supply_register(&client->dev,
0428                           &info->battery_desc, &psy_cfg);
0429     if (IS_ERR(info->battery)) {
0430         dev_err(&client->dev, "failed to register battery\n");
0431         ret = PTR_ERR(info->battery);
0432         goto fail_register;
0433     } else {
0434         schedule_delayed_work(&info->bat_work, DS278x_DELAY);
0435     }
0436 
0437     return 0;
0438 
0439 fail_register:
0440     kfree(info->battery_desc.name);
0441 fail_name:
0442     kfree(info);
0443 fail_info:
0444     mutex_lock(&battery_lock);
0445     idr_remove(&battery_id, num);
0446     mutex_unlock(&battery_lock);
0447 fail_id:
0448     return ret;
0449 }
0450 
0451 static const struct i2c_device_id ds278x_id[] = {
0452     {"ds2782", DS2782},
0453     {"ds2786", DS2786},
0454     {},
0455 };
0456 MODULE_DEVICE_TABLE(i2c, ds278x_id);
0457 
0458 static struct i2c_driver ds278x_battery_driver = {
0459     .driver     = {
0460         .name   = "ds2782-battery",
0461         .pm = &ds278x_battery_pm_ops,
0462     },
0463     .probe      = ds278x_battery_probe,
0464     .remove     = ds278x_battery_remove,
0465     .id_table   = ds278x_id,
0466 };
0467 module_i2c_driver(ds278x_battery_driver);
0468 
0469 MODULE_AUTHOR("Ryan Mallon");
0470 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC driver");
0471 MODULE_LICENSE("GPL");