Skip to content

Commit 19a15b1

Browse files
kumajayaniclimcy
authored andcommitted
drivers: power: Import BQ2022A battery controller driver
Change-Id: I58ee1f6c2f2ddb0b4acef03d2134a1477a3e083e
1 parent 1e7541e commit 19a15b1

File tree

4 files changed

+334
-0
lines changed

4 files changed

+334
-0
lines changed

drivers/power/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,12 @@ config SMB135X_CHARGER
393393
The driver reports the charger status via the power supply framework.
394394
A charger status change triggers an IRQ via the device STAT pin.
395395

396+
config BQ2022A_SUPPORT
397+
bool "BQ2022A_SUPPORT"
398+
depends on OF
399+
help
400+
ba2022a use to get battery ID.
401+
396402
config SMB1360_CHARGER_FG
397403
tristate "SMB1360 Charger and Fuel Guage"
398404
depends on I2C

drivers/power/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ obj-$(CONFIG_SMB349_USB_CHARGER) += smb349-charger.o
5555
obj-$(CONFIG_SMB350_CHARGER) += smb350_charger.o
5656
obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o
5757
obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o
58+
obj-$(CONFIG_BQ2022A_SUPPORT) += bq2022a-batid.o
5859
obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg.o
5960
obj-$(CONFIG_SMB358_CHARGER) += smb358-charger.o
6061
obj-$(CONFIG_BATTERY_BQ28400) += bq28400_battery.o

drivers/power/bq2022a-batid.c

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
#define pr_fmt(fmt) "BQ2022A:%s: " fmt, __func__
2+
3+
#include <linux/init.h>
4+
#include <linux/module.h>
5+
#include <linux/debugfs.h>
6+
#include <linux/gpio.h>
7+
#include <linux/errno.h>
8+
#include <linux/delay.h>
9+
#include <linux/slab.h>
10+
#include <linux/of.h>
11+
#include <linux/of_gpio.h>
12+
#include <linux/bitops.h>
13+
#include <linux/spinlock.h>
14+
#include <asm/io.h>
15+
#include <asm/system.h>
16+
#include <linux/types.h>
17+
#include <linux/slab.h>
18+
#include <linux/device.h>
19+
#include <linux/err.h>
20+
#include <linux/power_supply.h>
21+
#include <linux/of_batterydata.h>
22+
#include <linux/thermal.h>
23+
#include <linux/platform_device.h>
24+
#include "bq2022a-batid.h"
25+
26+
/* BQ2022A. */
27+
#define ROM_COMMAND (0xcc)
28+
#define CTL_COMMAND (0xc3)
29+
#define WADDR_LB (0x00)
30+
#define WADDR_HB (0x00)
31+
#define GPIO_HIGH 1
32+
#define GPIO_LOW 0
33+
#define GPIO_BATT_ID_PIN (902+2)
34+
35+
static struct bq2022a_platform_data *g_bq2022a;
36+
static int bq2022a_bat_id = GPIO_BATT_ID_PIN;
37+
38+
unsigned char bq2022a_sdq_detect(void)
39+
{
40+
unsigned int PresenceTimer = 50;
41+
static volatile unsigned char InputData;
42+
static volatile unsigned char GotPulse;
43+
44+
gpio_direction_output(bq2022a_bat_id, GPIO_LOW);
45+
46+
/* Reset time should be > 480 usec */
47+
udelay(800);
48+
gpio_direction_input(bq2022a_bat_id);
49+
udelay(60);
50+
51+
while ((PresenceTimer > 0) && (GotPulse == 0)) {
52+
InputData = gpio_get_value(bq2022a_bat_id);
53+
if (InputData == 0) {
54+
GotPulse = 1;
55+
} else {
56+
GotPulse = 0;
57+
--PresenceTimer;
58+
}
59+
}
60+
udelay(200);
61+
62+
return GotPulse;
63+
}
64+
unsigned char bq2022a_sdq_readbyte(int time)
65+
{
66+
unsigned char data = 0x00;
67+
unsigned char mask, i;
68+
unsigned long flags;
69+
70+
spin_lock_irqsave(&g_bq2022a->bqlock, flags);
71+
72+
for (i = 0; i < 8; i++) {
73+
gpio_direction_output(bq2022a_bat_id, GPIO_LOW);
74+
75+
udelay(7);
76+
gpio_direction_input(bq2022a_bat_id);
77+
udelay(time);
78+
mask = gpio_get_value(bq2022a_bat_id);
79+
udelay(65);
80+
mask <<= i;
81+
data = (data | mask);
82+
}
83+
84+
udelay(200);
85+
spin_unlock_irqrestore(&g_bq2022a->bqlock, flags);
86+
87+
return data;
88+
}
89+
90+
void bq2022a_sdq_writebyte(u8 value)
91+
{
92+
unsigned char mask = 1;
93+
int i;
94+
unsigned long flags;
95+
96+
spin_lock_irqsave(&g_bq2022a->bqlock, flags);
97+
98+
99+
gpio_direction_output(bq2022a_bat_id, GPIO_HIGH);
100+
101+
for (i = 0; i < 8; i++) {
102+
gpio_set_value(bq2022a_bat_id, GPIO_LOW);
103+
udelay(4);
104+
if (mask & value) {
105+
udelay(10);
106+
gpio_set_value(bq2022a_bat_id, GPIO_HIGH);
107+
udelay(100);
108+
} else {
109+
udelay(100);
110+
gpio_set_value(bq2022a_bat_id, GPIO_HIGH);
111+
udelay(10);
112+
}
113+
114+
udelay(7);
115+
mask <<= 1;
116+
}
117+
118+
spin_unlock_irqrestore(&g_bq2022a->bqlock, flags);
119+
120+
}
121+
122+
static int bat_module_id;
123+
bool is_battery_feedback = false;
124+
125+
static const unsigned char con_bat_id[] = {
126+
0xed, 0x21, 0x4c, 0xe5,
127+
0xed, 0xa9, 0x4b, 0x2e,
128+
};
129+
130+
static int bq2022a_read_bat_id(int delay_time, int pimc_pin)
131+
{
132+
unsigned char bat_id = 0xff;
133+
unsigned char reset_id = 0;
134+
int i = 0;
135+
136+
for (i = 0; i < 10; i++) {
137+
reset_id = bq2022a_sdq_detect();
138+
if (reset_id && pimc_pin) {
139+
is_battery_feedback = true;
140+
break;
141+
}
142+
}
143+
144+
bq2022a_sdq_writebyte(ROM_COMMAND);
145+
bq2022a_sdq_writebyte(CTL_COMMAND);
146+
bq2022a_sdq_writebyte(WADDR_LB);
147+
bq2022a_sdq_writebyte(WADDR_HB);
148+
bat_id = bq2022a_sdq_readbyte(delay_time);
149+
150+
for (i = 0; i < 34; i++) {
151+
bat_id = bq2022a_sdq_readbyte(delay_time);
152+
pr_debug("reset_id:%x is_battery_feedback:%d temp ID:%x!!\n", reset_id, is_battery_feedback, bat_id);
153+
if ((bat_id != con_bat_id[i]) && (i < 8)) {
154+
pr_err("read family code Error!!\n");
155+
break;
156+
}
157+
158+
if ((i == 8) && (bat_id != 0x62)) {
159+
bat_module_id = (bat_id & 0x0f);
160+
break;
161+
} else if (i == 33) {
162+
if (bat_id == 0xdb)
163+
bat_module_id = 17;
164+
else if (bat_id == 0x3c)
165+
bat_module_id = 0x02;
166+
break;
167+
}
168+
}
169+
bat_id = bq2022a_sdq_readbyte(delay_time);
170+
gpio_direction_output(bq2022a_bat_id, GPIO_HIGH);
171+
172+
if (((0 < bat_module_id) && (bat_module_id < 11)) || (bat_module_id == 17))
173+
pr_debug("get correct ID!!\n");
174+
else {
175+
if (is_battery_feedback) {
176+
bat_module_id = 0;
177+
pr_debug("use common ID!!\n");
178+
} else {
179+
bat_module_id = 0xff;
180+
pr_debug("get wrong ID!!\n");
181+
return -ENODEV;
182+
}
183+
}
184+
185+
pr_err("bat_module_id= %x\n", bat_module_id);
186+
return 0;
187+
}
188+
int bq2022a_get_bat_module_id(void)
189+
{
190+
if (((0 <= bat_module_id) && (bat_module_id < 11)) || (bat_module_id == 17))
191+
return bat_module_id;
192+
else
193+
return 0xff;
194+
}
195+
EXPORT_SYMBOL_GPL(bq2022a_get_bat_module_id);
196+
static const struct of_device_id of_bq2022as_match[] = {
197+
{ .compatible = "bq2022a", },
198+
{},
199+
};
200+
201+
static int bq2022a_probe(struct platform_device *pdev)
202+
{
203+
struct bq2022a_platform_data *data;
204+
int rc = 0;
205+
int delay_time = 0;
206+
char bat_id_buf[64] = {0};
207+
208+
pr_debug(" entry!\n");
209+
210+
bq2022a_bat_id = of_get_named_gpio(pdev->dev.of_node, "qcom,bq2022a-id-gpio", 0);
211+
if (bq2022a_bat_id <= 0) {
212+
pr_err("can't get battery id pin from dts nod, so use BB gpio2\n");
213+
bq2022a_bat_id = GPIO_BATT_ID_PIN;
214+
}
215+
216+
pr_debug("bat_id_pin_num:%d\n", bq2022a_bat_id);
217+
218+
if (gpio_request(bq2022a_bat_id, "Batt_ID")) {
219+
pr_err("GPIO request failed!\n");
220+
rc = -EPROBE_DEFER;
221+
return rc;
222+
}
223+
224+
data = (struct bq2022a_platform_data *) kzalloc(sizeof(struct bq2022a_platform_data), GFP_KERNEL);
225+
if (data == NULL) {
226+
pr_err("kzalloc Failed!\n");
227+
return -ENOMEM;
228+
}
229+
g_bq2022a = data;
230+
231+
spin_lock_init(&g_bq2022a->bqlock);
232+
233+
delay_time = 5;
234+
do {
235+
msleep(10);
236+
rc = bq2022a_read_bat_id(delay_time, 1);
237+
delay_time++;
238+
} while ((rc < 0) && (delay_time < 10));
239+
240+
if (rc) {
241+
pr_debug("check batt id Error!\n");
242+
if (bq2022a_bat_id != GPIO_BATT_ID_PIN) {
243+
pr_err("use gpio2 to detect battery id!\n");
244+
bq2022a_bat_id = GPIO_BATT_ID_PIN;
245+
delay_time = 5;
246+
bq2022a_read_bat_id(delay_time, 0);
247+
}
248+
}
249+
switch (bq2022a_get_bat_module_id()) {
250+
case 0:
251+
sprintf(bat_id_buf, "%s", "0 Common");
252+
break;
253+
case 1:
254+
sprintf(bat_id_buf, "%s", "1 Sunwoda + Samsung");
255+
break;
256+
case 2:
257+
sprintf(bat_id_buf, "%s", "2 Guangyu + Guangyu");
258+
break;
259+
case 3:
260+
sprintf(bat_id_buf, "%s", "3 Sunwoda + Sony");
261+
break;
262+
case 4:
263+
sprintf(bat_id_buf, "%s", "4 Sunwoda + Samsung(customdown)");
264+
break;
265+
case 5:
266+
sprintf(bat_id_buf, "%s", "5 Desay + LG");
267+
break;
268+
case 6:
269+
sprintf(bat_id_buf, "%s", "6 Feimaotui + Sony");
270+
break;
271+
case 7:
272+
sprintf(bat_id_buf, "%s", "7 AAC");
273+
break;
274+
case 8:
275+
sprintf(bat_id_buf, "%s", "8 Guangyu(2200)");
276+
break;
277+
case 9:
278+
sprintf(bat_id_buf, "%s", "9 Desai(2200)");
279+
break;
280+
case 10:
281+
sprintf(bat_id_buf, "%s", "10 Sunwoda(2200)");
282+
break;
283+
case 17:
284+
sprintf(bat_id_buf, "%s", "17 Feimaotui + Samsung(MI2A)");
285+
break;
286+
case 0xff:
287+
default:
288+
sprintf(bat_id_buf, "%s", "error");
289+
break;
290+
}
291+
pr_debug("battery module:%s", bat_id_buf);
292+
pr_err("success!!\n");
293+
294+
return rc;
295+
}
296+
297+
static int bq2022a_remove(struct platform_device *pdev)
298+
{
299+
gpio_free(bq2022a_bat_id);
300+
kfree(g_bq2022a);
301+
g_bq2022a = NULL;
302+
303+
return 0;
304+
}
305+
306+
static struct platform_driver bq2022a_driver = {
307+
.probe = bq2022a_probe,
308+
.remove = bq2022a_remove,
309+
.driver = {
310+
.name = "bq2022a",
311+
.owner = THIS_MODULE,
312+
.of_match_table = of_match_ptr(of_bq2022as_match),
313+
},
314+
};
315+
316+
module_platform_driver(bq2022a_driver);
317+
318+
MODULE_DESCRIPTION("bq2022a-batid driver");
319+
MODULE_LICENSE("GPL");

drivers/power/bq2022a-batid.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef __BQ2022A_H__
2+
#define __BQ2022A_H__
3+
4+
struct bq2022a_platform_data {
5+
spinlock_t bqlock;
6+
};
7+
8+
#endif

0 commit comments

Comments
 (0)