linux/drivers/power/supply/rt5033_battery.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Fuel gauge driver for Richtek RT5033
   4 *
   5 * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
   6 * Author: Beomho Seo <beomho.seo@samsung.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/platform_device.h>
  11#include <linux/power_supply.h>
  12#include <linux/mfd/rt5033-private.h>
  13#include <linux/mfd/rt5033.h>
  14
  15static int rt5033_battery_get_capacity(struct i2c_client *client)
  16{
  17        struct rt5033_battery *battery = i2c_get_clientdata(client);
  18        u32 msb;
  19
  20        regmap_read(battery->regmap, RT5033_FUEL_REG_SOC_H, &msb);
  21
  22        return msb;
  23}
  24
  25static int rt5033_battery_get_present(struct i2c_client *client)
  26{
  27        struct rt5033_battery *battery = i2c_get_clientdata(client);
  28        u32 val;
  29
  30        regmap_read(battery->regmap, RT5033_FUEL_REG_CONFIG_L, &val);
  31
  32        return (val & RT5033_FUEL_BAT_PRESENT) ? true : false;
  33}
  34
  35static int rt5033_battery_get_watt_prop(struct i2c_client *client,
  36                enum power_supply_property psp)
  37{
  38        struct rt5033_battery *battery = i2c_get_clientdata(client);
  39        unsigned int regh, regl;
  40        int ret;
  41        u32 msb, lsb;
  42
  43        switch (psp) {
  44        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  45                regh = RT5033_FUEL_REG_VBAT_H;
  46                regl = RT5033_FUEL_REG_VBAT_L;
  47                break;
  48        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
  49                regh = RT5033_FUEL_REG_AVG_VOLT_H;
  50                regl = RT5033_FUEL_REG_AVG_VOLT_L;
  51                break;
  52        case POWER_SUPPLY_PROP_VOLTAGE_OCV:
  53                regh = RT5033_FUEL_REG_OCV_H;
  54                regl = RT5033_FUEL_REG_OCV_L;
  55                break;
  56        default:
  57                return -EINVAL;
  58        }
  59
  60        regmap_read(battery->regmap, regh, &msb);
  61        regmap_read(battery->regmap, regl, &lsb);
  62
  63        ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000;
  64
  65        return ret;
  66}
  67
  68static int rt5033_battery_get_property(struct power_supply *psy,
  69                enum power_supply_property psp,
  70                union power_supply_propval *val)
  71{
  72        struct rt5033_battery *battery = power_supply_get_drvdata(psy);
  73
  74        switch (psp) {
  75        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  76        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
  77        case POWER_SUPPLY_PROP_VOLTAGE_OCV:
  78                val->intval = rt5033_battery_get_watt_prop(battery->client,
  79                                                                        psp);
  80                break;
  81        case POWER_SUPPLY_PROP_PRESENT:
  82                val->intval = rt5033_battery_get_present(battery->client);
  83                break;
  84        case POWER_SUPPLY_PROP_CAPACITY:
  85                val->intval = rt5033_battery_get_capacity(battery->client);
  86                break;
  87        default:
  88                return -EINVAL;
  89        }
  90        return 0;
  91}
  92
  93static enum power_supply_property rt5033_battery_props[] = {
  94        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  95        POWER_SUPPLY_PROP_VOLTAGE_AVG,
  96        POWER_SUPPLY_PROP_VOLTAGE_OCV,
  97        POWER_SUPPLY_PROP_PRESENT,
  98        POWER_SUPPLY_PROP_CAPACITY,
  99};
 100
 101static const struct regmap_config rt5033_battery_regmap_config = {
 102        .reg_bits       = 8,
 103        .val_bits       = 8,
 104        .max_register   = RT5033_FUEL_REG_END,
 105};
 106
 107static const struct power_supply_desc rt5033_battery_desc = {
 108        .name           = "rt5033-battery",
 109        .type           = POWER_SUPPLY_TYPE_BATTERY,
 110        .get_property   = rt5033_battery_get_property,
 111        .properties     = rt5033_battery_props,
 112        .num_properties = ARRAY_SIZE(rt5033_battery_props),
 113};
 114
 115static int rt5033_battery_probe(struct i2c_client *client,
 116                const struct i2c_device_id *id)
 117{
 118        struct i2c_adapter *adapter = client->adapter;
 119        struct power_supply_config psy_cfg = {};
 120        struct rt5033_battery *battery;
 121        u32 ret;
 122
 123        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
 124                return -EIO;
 125
 126        battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL);
 127        if (!battery)
 128                return -ENOMEM;
 129
 130        battery->client = client;
 131        battery->regmap = devm_regmap_init_i2c(client,
 132                        &rt5033_battery_regmap_config);
 133        if (IS_ERR(battery->regmap)) {
 134                dev_err(&client->dev, "Failed to initialize regmap\n");
 135                return -EINVAL;
 136        }
 137
 138        i2c_set_clientdata(client, battery);
 139        psy_cfg.drv_data = battery;
 140
 141        battery->psy = power_supply_register(&client->dev,
 142                                             &rt5033_battery_desc, &psy_cfg);
 143        if (IS_ERR(battery->psy)) {
 144                dev_err(&client->dev, "Failed to register power supply\n");
 145                ret = PTR_ERR(battery->psy);
 146                return ret;
 147        }
 148
 149        return 0;
 150}
 151
 152static int rt5033_battery_remove(struct i2c_client *client)
 153{
 154        struct rt5033_battery *battery = i2c_get_clientdata(client);
 155
 156        power_supply_unregister(battery->psy);
 157
 158        return 0;
 159}
 160
 161static const struct i2c_device_id rt5033_battery_id[] = {
 162        { "rt5033-battery", },
 163        { }
 164};
 165MODULE_DEVICE_TABLE(i2c, rt5033_battery_id);
 166
 167static struct i2c_driver rt5033_battery_driver = {
 168        .driver = {
 169                .name = "rt5033-battery",
 170        },
 171        .probe = rt5033_battery_probe,
 172        .remove = rt5033_battery_remove,
 173        .id_table = rt5033_battery_id,
 174};
 175module_i2c_driver(rt5033_battery_driver);
 176
 177MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver");
 178MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
 179MODULE_LICENSE("GPL");
 180