brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · 7a27b26 Raw
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