diff options
author | Enric Balletbo i Serra <enric.balletbo@collabora.com> | 2017-01-27 12:43:46 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-02-01 06:44:23 -0500 |
commit | 4c466872d8ae8e3cdc3e5e1a47e28a15e3020d8b (patch) | |
tree | 12e1940455bb76c712476e5ef2e66244c09b68f0 /drivers/rtc | |
parent | 5dff3a3113173a0c835abbda0eef3c0a2a56cc3a (diff) |
rtc: bq32000: add support to enable disable the trickle charge FET bypass
The bq32000 includes a trickle charge circuit to maintain the charge of the
backup supply when a super capacitor is used.
You can enable the charging circuit by setting 'trickle-resistor-ohms',
additionally you can set TCFE to 1 to bypass the internal diode and boost
the charge voltage of the backup supply. You might want to enable/disable
the TCFE switch from userspace (e.g when device is only connected to a
battery)
This patch introduces a new sysfs entry to enable and disable this FET
form userspace.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-bq32k.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 397742446007..2b223935001f 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #define BQ32K_CALIBRATION 0x07 /* CAL_CFG1, calibration and control */ | 34 | #define BQ32K_CALIBRATION 0x07 /* CAL_CFG1, calibration and control */ |
35 | #define BQ32K_TCH2 0x08 /* Trickle charge enable */ | 35 | #define BQ32K_TCH2 0x08 /* Trickle charge enable */ |
36 | #define BQ32K_CFG2 0x09 /* Trickle charger control */ | 36 | #define BQ32K_CFG2 0x09 /* Trickle charger control */ |
37 | #define BQ32K_TCFE BIT(6) /* Trickle charge FET bypass */ | ||
37 | 38 | ||
38 | struct bq32k_regs { | 39 | struct bq32k_regs { |
39 | uint8_t seconds; | 40 | uint8_t seconds; |
@@ -188,6 +189,65 @@ static int trickle_charger_of_init(struct device *dev, struct device_node *node) | |||
188 | return 0; | 189 | return 0; |
189 | } | 190 | } |
190 | 191 | ||
192 | static ssize_t bq32k_sysfs_show_tricklecharge_bypass(struct device *dev, | ||
193 | struct device_attribute *attr, | ||
194 | char *buf) | ||
195 | { | ||
196 | int reg, error; | ||
197 | |||
198 | error = bq32k_read(dev, ®, BQ32K_CFG2, 1); | ||
199 | if (error) | ||
200 | return error; | ||
201 | |||
202 | return sprintf(buf, "%d\n", (reg & BQ32K_TCFE) ? 1 : 0); | ||
203 | } | ||
204 | |||
205 | static ssize_t bq32k_sysfs_store_tricklecharge_bypass(struct device *dev, | ||
206 | struct device_attribute *attr, | ||
207 | const char *buf, size_t count) | ||
208 | { | ||
209 | int reg, enable, error; | ||
210 | |||
211 | if (kstrtoint(buf, 0, &enable)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | error = bq32k_read(dev, ®, BQ32K_CFG2, 1); | ||
215 | if (error) | ||
216 | return error; | ||
217 | |||
218 | if (enable) { | ||
219 | reg |= BQ32K_TCFE; | ||
220 | error = bq32k_write(dev, ®, BQ32K_CFG2, 1); | ||
221 | if (error) | ||
222 | return error; | ||
223 | |||
224 | dev_info(dev, "Enabled trickle charge FET bypass.\n"); | ||
225 | } else { | ||
226 | reg &= ~BQ32K_TCFE; | ||
227 | error = bq32k_write(dev, ®, BQ32K_CFG2, 1); | ||
228 | if (error) | ||
229 | return error; | ||
230 | |||
231 | dev_info(dev, "Disabled trickle charge FET bypass.\n"); | ||
232 | } | ||
233 | |||
234 | return count; | ||
235 | } | ||
236 | |||
237 | static DEVICE_ATTR(trickle_charge_bypass, 0644, | ||
238 | bq32k_sysfs_show_tricklecharge_bypass, | ||
239 | bq32k_sysfs_store_tricklecharge_bypass); | ||
240 | |||
241 | static int bq32k_sysfs_register(struct device *dev) | ||
242 | { | ||
243 | return device_create_file(dev, &dev_attr_trickle_charge_bypass); | ||
244 | } | ||
245 | |||
246 | static void bq32k_sysfs_unregister(struct device *dev) | ||
247 | { | ||
248 | device_remove_file(dev, &dev_attr_trickle_charge_bypass); | ||
249 | } | ||
250 | |||
191 | static int bq32k_probe(struct i2c_client *client, | 251 | static int bq32k_probe(struct i2c_client *client, |
192 | const struct i2c_device_id *id) | 252 | const struct i2c_device_id *id) |
193 | { | 253 | { |
@@ -224,11 +284,26 @@ static int bq32k_probe(struct i2c_client *client, | |||
224 | if (IS_ERR(rtc)) | 284 | if (IS_ERR(rtc)) |
225 | return PTR_ERR(rtc); | 285 | return PTR_ERR(rtc); |
226 | 286 | ||
287 | error = bq32k_sysfs_register(&client->dev); | ||
288 | if (error) { | ||
289 | dev_err(&client->dev, | ||
290 | "Unable to create sysfs entries for rtc bq32000\n"); | ||
291 | return error; | ||
292 | } | ||
293 | |||
294 | |||
227 | i2c_set_clientdata(client, rtc); | 295 | i2c_set_clientdata(client, rtc); |
228 | 296 | ||
229 | return 0; | 297 | return 0; |
230 | } | 298 | } |
231 | 299 | ||
300 | static int bq32k_remove(struct i2c_client *client) | ||
301 | { | ||
302 | bq32k_sysfs_unregister(&client->dev); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
232 | static const struct i2c_device_id bq32k_id[] = { | 307 | static const struct i2c_device_id bq32k_id[] = { |
233 | { "bq32000", 0 }, | 308 | { "bq32000", 0 }, |
234 | { } | 309 | { } |
@@ -240,6 +315,7 @@ static struct i2c_driver bq32k_driver = { | |||
240 | .name = "bq32k", | 315 | .name = "bq32k", |
241 | }, | 316 | }, |
242 | .probe = bq32k_probe, | 317 | .probe = bq32k_probe, |
318 | .remove = bq32k_remove, | ||
243 | .id_table = bq32k_id, | 319 | .id_table = bq32k_id, |
244 | }; | 320 | }; |
245 | 321 | ||