Merge tag 'pinctrl-v4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6-block.git] / drivers / power / supply / bq27xxx_battery_hdq.c
CommitLineData
cfbc6190 1/*
67bd22c0 2 * BQ27xxx battery monitor HDQ/1-wire driver
cfbc6190 3 *
67bd22c0 4 * Copyright (C) 2007-2017 Texas Instruments Incorporated - http://www.ti.com/
cfbc6190 5 *
67bd22c0
AD
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
cfbc6190
MC
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/types.h>
20#include <linux/platform_device.h>
21#include <linux/mutex.h>
081bab21 22#include <linux/power/bq27xxx_battery.h>
cfbc6190 23
de0d6dbd
AD
24#include <linux/w1.h>
25
26#define W1_FAMILY_BQ27000 0x01
cfbc6190 27
67bd22c0
AD
28#define HDQ_CMD_READ (0 << 7)
29#define HDQ_CMD_WRITE (1 << 7)
cfbc6190
MC
30
31static int F_ID;
50fa2951 32module_param(F_ID, int, S_IRUSR);
67bd22c0 33MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ27xxx device");
cfbc6190 34
67bd22c0 35static int w1_bq27000_read(struct w1_slave *sl, unsigned int reg)
cfbc6190
MC
36{
37 u8 val;
cfbc6190 38
b02f8bed 39 mutex_lock(&sl->master->bus_mutex);
cfbc6190
MC
40 w1_write_8(sl->master, HDQ_CMD_READ | reg);
41 val = w1_read_8(sl->master);
b02f8bed 42 mutex_unlock(&sl->master->bus_mutex);
cfbc6190
MC
43
44 return val;
45}
9f3519d2 46
67bd22c0
AD
47static int bq27xxx_battery_hdq_read(struct bq27xxx_device_info *di, u8 reg,
48 bool single)
cfbc6190 49{
67bd22c0
AD
50 struct w1_slave *sl = dev_to_w1_slave(di->dev);
51 unsigned int timeout = 3;
52 int upper, lower;
53 int temp;
54
55 if (!single) {
56 /*
57 * Make sure the value has not changed in between reading the
58 * lower and the upper part
59 */
60 upper = w1_bq27000_read(sl, reg + 1);
61 do {
62 temp = upper;
63 if (upper < 0)
64 return upper;
65
66 lower = w1_bq27000_read(sl, reg);
67 if (lower < 0)
68 return lower;
69
70 upper = w1_bq27000_read(sl, reg + 1);
71 } while (temp != upper && --timeout);
72
73 if (timeout == 0)
74 return -EIO;
75
76 return (upper << 8) | lower;
cfbc6190 77 }
cfbc6190 78
67bd22c0
AD
79 return w1_bq27000_read(sl, reg);
80}
cfbc6190 81
67bd22c0
AD
82static int bq27xxx_battery_hdq_add_slave(struct w1_slave *sl)
83{
84 struct bq27xxx_device_info *di;
85
86 di = devm_kzalloc(&sl->dev, sizeof(*di), GFP_KERNEL);
87 if (!di)
88 return -ENOMEM;
cfbc6190 89
67bd22c0 90 dev_set_drvdata(&sl->dev, di);
cfbc6190 91
67bd22c0
AD
92 di->dev = &sl->dev;
93 di->chip = BQ27000;
94 di->name = "bq27000-battery";
95 di->bus.read = bq27xxx_battery_hdq_read;
96
97 return bq27xxx_battery_setup(di);
cfbc6190
MC
98}
99
67bd22c0 100static void bq27xxx_battery_hdq_remove_slave(struct w1_slave *sl)
cfbc6190 101{
67bd22c0 102 struct bq27xxx_device_info *di = dev_get_drvdata(&sl->dev);
cfbc6190 103
67bd22c0 104 bq27xxx_battery_teardown(di);
cfbc6190
MC
105}
106
67bd22c0
AD
107static struct w1_family_ops bq27xxx_battery_hdq_fops = {
108 .add_slave = bq27xxx_battery_hdq_add_slave,
109 .remove_slave = bq27xxx_battery_hdq_remove_slave,
cfbc6190
MC
110};
111
67bd22c0 112static struct w1_family bq27xxx_battery_hdq_family = {
4b7e4f82 113 .fid = W1_FAMILY_BQ27000,
67bd22c0 114 .fops = &bq27xxx_battery_hdq_fops,
cfbc6190
MC
115};
116
67bd22c0 117static int __init bq27xxx_battery_hdq_init(void)
cfbc6190
MC
118{
119 if (F_ID)
67bd22c0 120 bq27xxx_battery_hdq_family.fid = F_ID;
cfbc6190 121
67bd22c0 122 return w1_register_family(&bq27xxx_battery_hdq_family);
cfbc6190 123}
67bd22c0 124module_init(bq27xxx_battery_hdq_init);
cfbc6190 125
67bd22c0 126static void __exit bq27xxx_battery_hdq_exit(void)
cfbc6190 127{
67bd22c0 128 w1_unregister_family(&bq27xxx_battery_hdq_family);
cfbc6190 129}
67bd22c0 130module_exit(bq27xxx_battery_hdq_exit);
cfbc6190 131
cfbc6190 132MODULE_AUTHOR("Texas Instruments Ltd");
67bd22c0 133MODULE_DESCRIPTION("BQ27xxx battery monitor HDQ/1-wire driver");
50fa2951
AD
134MODULE_LICENSE("GPL");
135MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000));