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