aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/bq24022.c
blob: 366565aba865380672a3ed0e2e04e07b98d40238 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
 * 1-Cell Li-Ion Charger connected via GPIOs.
 *
 * Copyright (c) 2008 Philipp Zabel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/regulator/bq24022.h>
#include <linux/regulator/driver.h>


static int bq24022_set_current_limit(struct regulator_dev *rdev,
					int min_uA, int max_uA)
{
	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);

	dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
		max_uA >= 500000 ? "500" : "100");

	/* REVISIT: maybe return error if min_uA != 0 ? */
	gpio_set_value(pdata->gpio_iset2, max_uA >= 500000);
	return 0;
}

static int bq24022_get_current_limit(struct regulator_dev *rdev)
{
	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);

	return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
}

static int bq24022_enable(struct regulator_dev *rdev)
{
	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);

	dev_dbg(rdev_get_dev(rdev), "enabling charger\n");

	gpio_set_value(pdata->gpio_nce, 0);
	return 0;
}

static int bq24022_disable(struct regulator_dev *rdev)
{
	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);

	dev_dbg(rdev_get_dev(rdev), "disabling charger\n");

	gpio_set_value(pdata->gpio_nce, 1);
	return 0;
}

static int bq24022_is_enabled(struct regulator_dev *rdev)
{
	struct platform_device *pdev = rdev_get_drvdata(rdev);
	struct bq24022_mach_info *pdata = pdev->dev.platform_data;

	return !gpio_get_value(pdata->gpio_nce);
}

static struct regulator_ops bq24022_ops = {
	.set_current_limit = bq24022_set_current_limit,
	.get_current_limit = bq24022_get_current_limit,
	.enable            = bq24022_enable,
	.disable           = bq24022_disable,
	.is_enabled        = bq24022_is_enabled,
};

static struct regulator_desc bq24022_desc = {
	.name  = "bq24022",
	.ops   = &bq24022_ops,
	.type  = REGULATOR_CURRENT,
};

static int __init bq24022_probe(struct platform_device *pdev)
{
	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
	struct regulator_dev *bq24022;
	int ret;

	if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2)
		return -EINVAL;

	ret = gpio_request(pdata->gpio_nce, "ncharge_en");
	if (ret) {
		dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n",
			pdata->gpio_nce);
		goto err_ce;
	}
	ret = gpio_request(pdata->gpio_iset2, "charge_mode");
	if (ret) {
		dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n",
			pdata->gpio_iset2);
		goto err_iset2;
	}
	ret = gpio_direction_output(pdata->gpio_iset2, 0);
	ret = gpio_direction_output(pdata->gpio_nce, 1);

	bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
	if (IS_ERR(bq24022)) {
		dev_dbg(&pdev->dev, "couldn't register regulator\n");
		ret = PTR_ERR(bq24022);
		goto err_reg;
	}
	platform_set_drvdata(pdev, bq24022);
	dev_dbg(&pdev->dev, "registered regulator\n");

	return 0;
err_reg:
	gpio_free(pdata->gpio_iset2);
err_iset2:
	gpio_free(pdata->gpio_nce);
err_ce:
	return ret;
}

static int __devexit bq24022_remove(struct platform_device *pdev)
{
	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
	struct regulator_dev *bq24022 = platform_get_drvdata(pdev);

	regulator_unregister(bq24022);
	gpio_free(pdata->gpio_iset2);
	gpio_free(pdata->gpio_nce);

	return 0;
}

static struct platform_driver bq24022_driver = {
	.driver = {
		.name = "bq24022",
	},
	.remove = __devexit_p(bq24022_remove),
};

static int __init bq24022_init(void)
{
	return platform_driver_probe(&bq24022_driver, bq24022_probe);
}

static void __exit bq24022_exit(void)
{
	platform_driver_unregister(&bq24022_driver);
}

/*
 * make sure this is probed before gpio_vbus and pda_power,
 * but after asic3 or other GPIO expander drivers.
 */
subsys_initcall(bq24022_init);
module_exit(bq24022_exit);

MODULE_AUTHOR("Philipp Zabel");
MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver");
MODULE_LICENSE("GPL");