aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorGraeme Gregory <gg@slimlogic.co.uk>2011-05-02 17:19:46 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2011-05-27 05:35:22 -0400
commit27c6750ec56fd3b22c670d9333d519a322996eb2 (patch)
treef3301c461a70dc651ab035b8ccfa04528625b352 /drivers/mfd
parent98ea5c218ed150bf7cabb879db4fc2c106b6fa5b (diff)
MFD: TPS65910: Add new mfd device for TPS65910
The TPS65910 chip is a power management IC for multimedia and handheld devices. It contains the following components: - Regulators - GPIO controller - RTC The tps65910 core driver is registered as a platform driver and provides communication through I2C with the host device for the different components. Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk> Signed-off-by: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> Acked-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/tps65910.c208
3 files changed, 217 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8344fc0ab858..d67511a67fdd 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -719,6 +719,14 @@ config MFD_PM8XXX_IRQ
719 This is required to use certain other PM 8xxx features, such as GPIO 719 This is required to use certain other PM 8xxx features, such as GPIO
720 and MPP. 720 and MPP.
721 721
722config MFD_TPS65910
723 tristate "TPS65910 Power Management chip"
724 depends on I2C && GPIOLIB
725 select MFD_CORE
726 help
727 if you say yes here you get support for the TPS65910 series of
728 Power Management chips.
729
722endif # MFD_SUPPORT 730endif # MFD_SUPPORT
723 731
724menu "Multimedia Capabilities Port drivers" 732menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1acb8f29a96c..f43ef5bba3ba 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -93,3 +93,4 @@ obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
93obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o 93obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
94obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o 94obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
95obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o 95obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
96obj-$(CONFIG_MFD_TPS65910) += tps65910.o
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
new file mode 100644
index 000000000000..dbcdfb55bb8d
--- /dev/null
+++ b/drivers/mfd/tps65910.c
@@ -0,0 +1,208 @@
1/*
2 * tps65910.c -- TI TPS6591x
3 *
4 * Copyright 2010 Texas Instruments Inc.
5 *
6 * Author: Graeme Gregory <gg@slimlogic.co.uk>
7 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/i2c.h>
21#include <linux/gpio.h>
22#include <linux/mfd/core.h>
23#include <linux/mfd/tps65910.h>
24
25static struct mfd_cell tps65910s[] = {
26 {
27 .name = "tps65910-pmic",
28 },
29 {
30 .name = "tps65910-rtc",
31 },
32 {
33 .name = "tps65910-power",
34 },
35};
36
37
38static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
39 int bytes, void *dest)
40{
41 struct i2c_client *i2c = tps65910->i2c_client;
42 struct i2c_msg xfer[2];
43 int ret;
44
45 /* Write register */
46 xfer[0].addr = i2c->addr;
47 xfer[0].flags = 0;
48 xfer[0].len = 1;
49 xfer[0].buf = &reg;
50
51 /* Read data */
52 xfer[1].addr = i2c->addr;
53 xfer[1].flags = I2C_M_RD;
54 xfer[1].len = bytes;
55 xfer[1].buf = dest;
56
57 ret = i2c_transfer(i2c->adapter, xfer, 2);
58 if (ret == 2)
59 ret = 0;
60 else if (ret >= 0)
61 ret = -EIO;
62
63 return ret;
64}
65
66static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
67 int bytes, void *src)
68{
69 struct i2c_client *i2c = tps65910->i2c_client;
70 /* we add 1 byte for device register */
71 u8 msg[TPS65910_MAX_REGISTER + 1];
72 int ret;
73
74 if (bytes > (TPS65910_MAX_REGISTER + 1))
75 return -EINVAL;
76
77 msg[0] = reg;
78 memcpy(&msg[1], src, bytes);
79
80 ret = i2c_master_send(i2c, msg, bytes + 1);
81 if (ret < 0)
82 return ret;
83 if (ret != bytes + 1)
84 return -EIO;
85 return 0;
86}
87
88int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
89{
90 u8 data;
91 int err;
92
93 mutex_lock(&tps65910->io_mutex);
94 err = tps65910_i2c_read(tps65910, reg, 1, &data);
95 if (err) {
96 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
97 goto out;
98 }
99
100 data |= mask;
101 err = tps65910_i2c_write(tps65910, reg, 1, &data);
102 if (err)
103 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
104
105out:
106 mutex_unlock(&tps65910->io_mutex);
107 return err;
108}
109EXPORT_SYMBOL_GPL(tps65910_set_bits);
110
111int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
112{
113 u8 data;
114 int err;
115
116 mutex_lock(&tps65910->io_mutex);
117 err = tps65910_i2c_read(tps65910, reg, 1, &data);
118 if (err) {
119 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
120 goto out;
121 }
122
123 data &= mask;
124 err = tps65910_i2c_write(tps65910, reg, 1, &data);
125 if (err)
126 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
127
128out:
129 mutex_unlock(&tps65910->io_mutex);
130 return err;
131}
132EXPORT_SYMBOL_GPL(tps65910_clear_bits);
133
134static int tps65910_i2c_probe(struct i2c_client *i2c,
135 const struct i2c_device_id *id)
136{
137 struct tps65910 *tps65910;
138 int ret = 0;
139
140 tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
141 if (tps65910 == NULL)
142 return -ENOMEM;
143
144 i2c_set_clientdata(i2c, tps65910);
145 tps65910->dev = &i2c->dev;
146 tps65910->i2c_client = i2c;
147 tps65910->read = tps65910_i2c_read;
148 tps65910->write = tps65910_i2c_write;
149 mutex_init(&tps65910->io_mutex);
150
151 ret = mfd_add_devices(tps65910->dev, -1,
152 tps65910s, ARRAY_SIZE(tps65910s),
153 NULL, 0);
154 if (ret < 0)
155 goto err;
156
157 return ret;
158
159err:
160 mfd_remove_devices(tps65910->dev);
161 kfree(tps65910);
162 return ret;
163}
164
165static int tps65910_i2c_remove(struct i2c_client *i2c)
166{
167 struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
168
169 mfd_remove_devices(tps65910->dev);
170 kfree(tps65910);
171
172 return 0;
173}
174
175static const struct i2c_device_id tps65910_i2c_id[] = {
176 { "tps65910", 0 },
177 { }
178};
179MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
180
181
182static struct i2c_driver tps65910_i2c_driver = {
183 .driver = {
184 .name = "tps65910",
185 .owner = THIS_MODULE,
186 },
187 .probe = tps65910_i2c_probe,
188 .remove = tps65910_i2c_remove,
189 .id_table = tps65910_i2c_id,
190};
191
192static int __init tps65910_i2c_init(void)
193{
194 return i2c_add_driver(&tps65910_i2c_driver);
195}
196/* init early so consumer devices can complete system boot */
197subsys_initcall(tps65910_i2c_init);
198
199static void __exit tps65910_i2c_exit(void)
200{
201 i2c_del_driver(&tps65910_i2c_driver);
202}
203module_exit(tps65910_i2c_exit);
204
205MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
206MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
207MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
208MODULE_LICENSE("GPL");