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 15 static 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 25 static 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 35 static 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 68 static 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 93 static 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 101 static 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 107 static 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 115 static 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 152 static 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 161 static const struct i2c_device_id rt5033_battery_id[] = { 162 { "rt5033-battery", }, 163 { } 164 }; 165 MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); 166 167 static const struct of_device_id rt5033_battery_of_match[] = { 168 { .compatible = "richtek,rt5033-battery", }, 169 { } 170 }; 171 MODULE_DEVICE_TABLE(of, rt5033_battery_of_match); 172 173 static struct i2c_driver rt5033_battery_driver = { 174 .driver = { 175 .name = "rt5033-battery", 176 .of_match_table = rt5033_battery_of_match, 177 }, 178 .probe = rt5033_battery_probe, 179 .remove = rt5033_battery_remove, 180 .id_table = rt5033_battery_id, 181 }; 182 module_i2c_driver(rt5033_battery_driver); 183 184 MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver"); 185 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 186 MODULE_LICENSE("GPL"); 187