Commit | Line | Data |
---|---|---|
b847dd96 BS |
1 | /* |
2 | * Fuel gauge driver for Richtek RT5033 | |
3 | * | |
4 | * Copyright (C) 2014 Samsung Electronics, Co., Ltd. | |
5 | * Author: Beomho Seo <beomho.seo@samsung.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published bythe Free Software Foundation. | |
10 | */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/platform_device.h> | |
14 | #include <linux/power_supply.h> | |
15 | #include <linux/mfd/rt5033-private.h> | |
16 | #include <linux/mfd/rt5033.h> | |
17 | ||
18 | static int rt5033_battery_get_capacity(struct i2c_client *client) | |
19 | { | |
20 | struct rt5033_battery *battery = i2c_get_clientdata(client); | |
21 | u32 msb; | |
22 | ||
23 | regmap_read(battery->regmap, RT5033_FUEL_REG_SOC_H, &msb); | |
24 | ||
25 | return msb; | |
26 | } | |
27 | ||
28 | static int rt5033_battery_get_present(struct i2c_client *client) | |
29 | { | |
30 | struct rt5033_battery *battery = i2c_get_clientdata(client); | |
31 | u32 val; | |
32 | ||
33 | regmap_read(battery->regmap, RT5033_FUEL_REG_CONFIG_L, &val); | |
34 | ||
35 | return (val & RT5033_FUEL_BAT_PRESENT) ? true : false; | |
36 | } | |
37 | ||
38 | static int rt5033_battery_get_watt_prop(struct i2c_client *client, | |
39 | enum power_supply_property psp) | |
40 | { | |
41 | struct rt5033_battery *battery = i2c_get_clientdata(client); | |
42 | unsigned int regh, regl; | |
43 | int ret; | |
44 | u32 msb, lsb; | |
45 | ||
46 | switch (psp) { | |
47 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
48 | regh = RT5033_FUEL_REG_VBAT_H; | |
49 | regl = RT5033_FUEL_REG_VBAT_L; | |
50 | break; | |
51 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
52 | regh = RT5033_FUEL_REG_AVG_VOLT_H; | |
53 | regl = RT5033_FUEL_REG_AVG_VOLT_L; | |
54 | break; | |
55 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: | |
56 | regh = RT5033_FUEL_REG_OCV_H; | |
57 | regl = RT5033_FUEL_REG_OCV_L; | |
58 | break; | |
59 | default: | |
60 | return -EINVAL; | |
61 | } | |
62 | ||
63 | regmap_read(battery->regmap, regh, &msb); | |
64 | regmap_read(battery->regmap, regl, &lsb); | |
65 | ||
66 | ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000; | |
67 | ||
68 | return ret; | |
69 | } | |
70 | ||
71 | static int rt5033_battery_get_property(struct power_supply *psy, | |
72 | enum power_supply_property psp, | |
73 | union power_supply_propval *val) | |
74 | { | |
75 | struct rt5033_battery *battery = container_of(psy, | |
76 | struct rt5033_battery, psy); | |
77 | ||
78 | switch (psp) { | |
79 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
80 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
81 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: | |
82 | val->intval = rt5033_battery_get_watt_prop(battery->client, | |
83 | psp); | |
84 | break; | |
85 | case POWER_SUPPLY_PROP_PRESENT: | |
86 | val->intval = rt5033_battery_get_present(battery->client); | |
87 | break; | |
88 | case POWER_SUPPLY_PROP_CAPACITY: | |
89 | val->intval = rt5033_battery_get_capacity(battery->client); | |
90 | break; | |
91 | default: | |
92 | return -EINVAL; | |
93 | } | |
94 | return 0; | |
95 | } | |
96 | ||
97 | static enum power_supply_property rt5033_battery_props[] = { | |
98 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | |
99 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | |
100 | POWER_SUPPLY_PROP_VOLTAGE_OCV, | |
101 | POWER_SUPPLY_PROP_PRESENT, | |
102 | POWER_SUPPLY_PROP_CAPACITY, | |
103 | }; | |
104 | ||
105 | static struct regmap_config rt5033_battery_regmap_config = { | |
106 | .reg_bits = 8, | |
107 | .val_bits = 8, | |
108 | .max_register = RT5033_FUEL_REG_END, | |
109 | }; | |
110 | ||
111 | static int rt5033_battery_probe(struct i2c_client *client, | |
112 | const struct i2c_device_id *id) | |
113 | { | |
114 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | |
115 | struct rt5033_battery *battery; | |
116 | u32 ret; | |
117 | ||
118 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | |
119 | return -EIO; | |
120 | ||
121 | battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); | |
122 | if (!battery) | |
123 | return -EINVAL; | |
124 | ||
125 | battery->client = client; | |
126 | battery->regmap = devm_regmap_init_i2c(client, | |
127 | &rt5033_battery_regmap_config); | |
128 | if (IS_ERR(battery->regmap)) { | |
129 | dev_err(&client->dev, "Failed to initialize regmap\n"); | |
130 | return -EINVAL; | |
131 | } | |
132 | ||
133 | i2c_set_clientdata(client, battery); | |
134 | ||
135 | battery->psy.name = "rt5033-battery"; | |
136 | battery->psy.type = POWER_SUPPLY_TYPE_BATTERY; | |
137 | battery->psy.get_property = rt5033_battery_get_property; | |
138 | battery->psy.properties = rt5033_battery_props; | |
139 | battery->psy.num_properties = ARRAY_SIZE(rt5033_battery_props); | |
140 | ||
141 | ret = power_supply_register(&client->dev, &battery->psy); | |
142 | if (ret) { | |
143 | dev_err(&client->dev, "Failed to register power supply\n"); | |
144 | return ret; | |
145 | } | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | static int rt5033_battery_remove(struct i2c_client *client) | |
151 | { | |
152 | struct rt5033_battery *battery = i2c_get_clientdata(client); | |
153 | ||
154 | power_supply_unregister(&battery->psy); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | static const struct i2c_device_id rt5033_battery_id[] = { | |
160 | { "rt5033-battery", }, | |
161 | { } | |
162 | }; | |
163 | MODULE_DEVICE_TABLE(platform, rt5033_battery_id); | |
164 | ||
165 | static struct i2c_driver rt5033_battery_driver = { | |
166 | .driver = { | |
167 | .name = "rt5033-battery", | |
168 | }, | |
169 | .probe = rt5033_battery_probe, | |
170 | .remove = rt5033_battery_remove, | |
171 | .id_table = rt5033_battery_id, | |
172 | }; | |
173 | module_i2c_driver(rt5033_battery_driver); | |
174 | ||
175 | MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver"); | |
176 | MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); | |
177 | MODULE_LICENSE("GPL"); |