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; 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 { 117 struct i2c_adapter *adapter = client->adapter; 118 struct power_supply_config psy_cfg = {}; 119 struct rt5033_battery *battery; 120 u32 ret; 121 122 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 123 return -EIO; 124 125 battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); 126 if (!battery) 127 return -ENOMEM; 128 129 battery->client = client; 130 battery->regmap = devm_regmap_init_i2c(client, 131 &rt5033_battery_regmap_config); 132 if (IS_ERR(battery->regmap)) { 133 dev_err(&client->dev, "Failed to initialize regmap\n"); 134 return -EINVAL; 135 } 136 137 i2c_set_clientdata(client, battery); 138 psy_cfg.drv_data = battery; 139 140 battery->psy = power_supply_register(&client->dev, 141 &rt5033_battery_desc, &psy_cfg); 142 if (IS_ERR(battery->psy)) { 143 dev_err(&client->dev, "Failed to register power supply\n"); 144 ret = PTR_ERR(battery->psy); 145 return ret; 146 } 147 148 return 0; 149 } 150 151 static void rt5033_battery_remove(struct i2c_client *client) 152 { 153 struct rt5033_battery *battery = i2c_get_clientdata(client); 154 155 power_supply_unregister(battery->psy); 156 } 157 158 static const struct i2c_device_id rt5033_battery_id[] = { 159 { "rt5033-battery", }, 160 { } 161 }; 162 MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); 163 164 static const struct of_device_id rt5033_battery_of_match[] = { 165 { .compatible = "richtek,rt5033-battery", }, 166 { } 167 }; 168 MODULE_DEVICE_TABLE(of, rt5033_battery_of_match); 169 170 static struct i2c_driver rt5033_battery_driver = { 171 .driver = { 172 .name = "rt5033-battery", 173 .of_match_table = rt5033_battery_of_match, 174 }, 175 .probe_new = rt5033_battery_probe, 176 .remove = rt5033_battery_remove, 177 .id_table = rt5033_battery_id, 178 }; 179 module_i2c_driver(rt5033_battery_driver); 180 181 MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver"); 182 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 183 MODULE_LICENSE("GPL"); 184