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 | { | |
297d716f | 75 | struct rt5033_battery *battery = power_supply_get_drvdata(psy); |
b847dd96 BS |
76 | |
77 | switch (psp) { | |
78 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
79 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | |
80 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: | |
81 | val->intval = rt5033_battery_get_watt_prop(battery->client, | |
82 | psp); | |
83 | break; | |
84 | case POWER_SUPPLY_PROP_PRESENT: | |
85 | val->intval = rt5033_battery_get_present(battery->client); | |
86 | break; | |
87 | case POWER_SUPPLY_PROP_CAPACITY: | |
88 | val->intval = rt5033_battery_get_capacity(battery->client); | |
89 | break; | |
90 | default: | |
91 | return -EINVAL; | |
92 | } | |
93 | return 0; | |
94 | } | |
95 | ||
96 | static enum power_supply_property rt5033_battery_props[] = { | |
97 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | |
98 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | |
99 | POWER_SUPPLY_PROP_VOLTAGE_OCV, | |
100 | POWER_SUPPLY_PROP_PRESENT, | |
101 | POWER_SUPPLY_PROP_CAPACITY, | |
102 | }; | |
103 | ||
65ce1c95 | 104 | static const struct regmap_config rt5033_battery_regmap_config = { |
b847dd96 BS |
105 | .reg_bits = 8, |
106 | .val_bits = 8, | |
107 | .max_register = RT5033_FUEL_REG_END, | |
108 | }; | |
109 | ||
297d716f KK |
110 | static const struct power_supply_desc rt5033_battery_desc = { |
111 | .name = "rt5033-battery", | |
112 | .type = POWER_SUPPLY_TYPE_BATTERY, | |
113 | .get_property = rt5033_battery_get_property, | |
114 | .properties = rt5033_battery_props, | |
115 | .num_properties = ARRAY_SIZE(rt5033_battery_props), | |
116 | }; | |
117 | ||
b847dd96 BS |
118 | static int rt5033_battery_probe(struct i2c_client *client, |
119 | const struct i2c_device_id *id) | |
120 | { | |
121 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | |
297d716f | 122 | struct power_supply_config psy_cfg = {}; |
b847dd96 BS |
123 | struct rt5033_battery *battery; |
124 | u32 ret; | |
125 | ||
126 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | |
127 | return -EIO; | |
128 | ||
129 | battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); | |
130 | if (!battery) | |
131 | return -EINVAL; | |
132 | ||
133 | battery->client = client; | |
134 | battery->regmap = devm_regmap_init_i2c(client, | |
135 | &rt5033_battery_regmap_config); | |
136 | if (IS_ERR(battery->regmap)) { | |
137 | dev_err(&client->dev, "Failed to initialize regmap\n"); | |
138 | return -EINVAL; | |
139 | } | |
140 | ||
141 | i2c_set_clientdata(client, battery); | |
297d716f | 142 | psy_cfg.drv_data = battery; |
b847dd96 | 143 | |
297d716f KK |
144 | battery->psy = power_supply_register(&client->dev, |
145 | &rt5033_battery_desc, &psy_cfg); | |
146 | if (IS_ERR(battery->psy)) { | |
b847dd96 | 147 | dev_err(&client->dev, "Failed to register power supply\n"); |
297d716f | 148 | ret = PTR_ERR(battery->psy); |
b847dd96 BS |
149 | return ret; |
150 | } | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | static int rt5033_battery_remove(struct i2c_client *client) | |
156 | { | |
157 | struct rt5033_battery *battery = i2c_get_clientdata(client); | |
158 | ||
297d716f | 159 | power_supply_unregister(battery->psy); |
b847dd96 BS |
160 | |
161 | return 0; | |
162 | } | |
163 | ||
164 | static const struct i2c_device_id rt5033_battery_id[] = { | |
165 | { "rt5033-battery", }, | |
166 | { } | |
167 | }; | |
168 | MODULE_DEVICE_TABLE(platform, rt5033_battery_id); | |
169 | ||
170 | static struct i2c_driver rt5033_battery_driver = { | |
171 | .driver = { | |
172 | .name = "rt5033-battery", | |
173 | }, | |
174 | .probe = rt5033_battery_probe, | |
175 | .remove = rt5033_battery_remove, | |
176 | .id_table = rt5033_battery_id, | |
177 | }; | |
178 | module_i2c_driver(rt5033_battery_driver); | |
179 | ||
180 | MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver"); | |
181 | MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); | |
182 | MODULE_LICENSE("GPL"); |