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