aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMargarita Olaya <magi@slimlogic.co.uk>2011-06-09 15:50:00 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-07-31 17:28:22 -0400
commit36e52873c6393b569f2befcdd1847929211892b8 (patch)
treedbc25ce026ec1bfe69702766048db78c5e7e3702 /drivers/mfd
parent8504d638041d50901b8bfba4fe646bd0bbb5cbb9 (diff)
mfd: tps65912: Add new mfd device
The tps65912 chip is a power management IC. It contains the following components: - Regulators - GPIO controller The core driver is registered as a platform driver, it provides communication through I2C and SPI interfaces. Signed-off-by: Margarita Olaya Cabrera <magi@slimlogic.co.uk> Acked-by: Samuel Ortiz <sameo@linux.intel.com> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig22
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/tps65912-core.c164
-rw-r--r--drivers/mfd/tps65912-i2c.c139
-rw-r--r--drivers/mfd/tps65912-spi.c142
5 files changed, 471 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1e2c9f03629b..f94036a4f33d 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -171,6 +171,28 @@ config MFD_TPS6586X
171 This driver can also be built as a module. If so, the module 171 This driver can also be built as a module. If so, the module
172 will be called tps6586x. 172 will be called tps6586x.
173 173
174config MFD_TPS65912
175 bool "TPS65912 PMIC"
176 depends on GPIOLIB
177
178config MFD_TPS65912_I2C
179 bool "TPS95612 Power Management chip with I2C"
180 select MFD_CORE
181 select MFD_TPS65912
182 depends on I2C=y && GPIOLIB
183 help
184 If you say yes here you get support for the TPS65912 series of
185 PM chips with I2C interface.
186
187config MFD_TPS65912_SPI
188 bool "TPS65912 Power Management chip with SPI"
189 select MFD_CORE
190 select MFD_TPS65912
191 depends on SPI_MASTER && GPIOLIB
192 help
193 If you say yes here you get support for the TPS65912 series of
194 PM chips with SPI interface.
195
174config MENELAUS 196config MENELAUS
175 bool "Texas Instruments TWL92330/Menelaus PM chip" 197 bool "Texas Instruments TWL92330/Menelaus PM chip"
176 depends on I2C=y && ARCH_OMAP2 198 depends on I2C=y && ARCH_OMAP2
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 0889f53c8b02..c9925e5dad99 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -36,6 +36,10 @@ obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
36obj-$(CONFIG_TPS6105X) += tps6105x.o 36obj-$(CONFIG_TPS6105X) += tps6105x.o
37obj-$(CONFIG_TPS65010) += tps65010.o 37obj-$(CONFIG_TPS65010) += tps65010.o
38obj-$(CONFIG_TPS6507X) += tps6507x.o 38obj-$(CONFIG_TPS6507X) += tps6507x.o
39tps65912-objs := tps65912-core.o
40obj-$(CONFIG_MFD_TPS65912) += tps65912.o
41obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
42obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
39obj-$(CONFIG_MENELAUS) += menelaus.o 43obj-$(CONFIG_MENELAUS) += menelaus.o
40 44
41obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o 45obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
new file mode 100644
index 000000000000..10baf7655542
--- /dev/null
+++ b/drivers/mfd/tps65912-core.c
@@ -0,0 +1,164 @@
1/*
2 * tps65912-core.c -- TI TPS65912x
3 *
4 * Copyright 2011 Texas Instruments Inc.
5 *
6 * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This driver is based on wm8350 implementation.
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/gpio.h>
21#include <linux/mfd/core.h>
22#include <linux/mfd/tps65912.h>
23
24static struct mfd_cell tps65912s[] = {
25 {
26 .name = "tps65912-pmic",
27 },
28};
29
30int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
31{
32 u8 data;
33 int err;
34
35 mutex_lock(&tps65912->io_mutex);
36
37 err = tps65912->read(tps65912, reg, 1, &data);
38 if (err) {
39 dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
40 goto out;
41 }
42
43 data |= mask;
44 err = tps65912->write(tps65912, reg, 1, &data);
45 if (err)
46 dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
47
48out:
49 mutex_unlock(&tps65912->io_mutex);
50 return err;
51}
52EXPORT_SYMBOL_GPL(tps65912_set_bits);
53
54int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
55{
56 u8 data;
57 int err;
58
59 mutex_lock(&tps65912->io_mutex);
60 err = tps65912->read(tps65912, reg, 1, &data);
61 if (err) {
62 dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
63 goto out;
64 }
65
66 data &= ~mask;
67 err = tps65912->write(tps65912, reg, 1, &data);
68 if (err)
69 dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
70
71out:
72 mutex_unlock(&tps65912->io_mutex);
73 return err;
74}
75EXPORT_SYMBOL_GPL(tps65912_clear_bits);
76
77static inline int tps65912_read(struct tps65912 *tps65912, u8 reg)
78{
79 u8 val;
80 int err;
81
82 err = tps65912->read(tps65912, reg, 1, &val);
83 if (err < 0)
84 return err;
85
86 return val;
87}
88
89static inline int tps65912_write(struct tps65912 *tps65912, u8 reg, u8 val)
90{
91 return tps65912->write(tps65912, reg, 1, &val);
92}
93
94int tps65912_reg_read(struct tps65912 *tps65912, u8 reg)
95{
96 int data;
97
98 mutex_lock(&tps65912->io_mutex);
99
100 data = tps65912_read(tps65912, reg);
101 if (data < 0)
102 dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
103
104 mutex_unlock(&tps65912->io_mutex);
105 return data;
106}
107EXPORT_SYMBOL_GPL(tps65912_reg_read);
108
109int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val)
110{
111 int err;
112
113 mutex_lock(&tps65912->io_mutex);
114
115 err = tps65912_write(tps65912, reg, val);
116 if (err < 0)
117 dev_err(tps65912->dev, "Write for reg 0x%x failed\n", reg);
118
119 mutex_unlock(&tps65912->io_mutex);
120 return err;
121}
122EXPORT_SYMBOL_GPL(tps65912_reg_write);
123
124int tps65912_device_init(struct tps65912 *tps65912)
125{
126 struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data;
127 int ret, dcdc_avs, value;
128
129 mutex_init(&tps65912->io_mutex);
130 dev_set_drvdata(tps65912->dev, tps65912);
131
132 dcdc_avs = (pmic_plat_data->is_dcdc1_avs << 0 |
133 pmic_plat_data->is_dcdc2_avs << 1 |
134 pmic_plat_data->is_dcdc3_avs << 2 |
135 pmic_plat_data->is_dcdc4_avs << 3);
136 if (dcdc_avs) {
137 tps65912->read(tps65912, TPS65912_I2C_SPI_CFG, 1, &value);
138 dcdc_avs |= value;
139 tps65912->write(tps65912, TPS65912_I2C_SPI_CFG, 1, &dcdc_avs);
140 }
141
142 ret = mfd_add_devices(tps65912->dev, -1,
143 tps65912s, ARRAY_SIZE(tps65912s),
144 NULL, 0);
145 if (ret < 0)
146 goto err;
147
148 return ret;
149
150err:
151 mfd_remove_devices(tps65912->dev);
152 kfree(tps65912);
153 return ret;
154}
155
156void tps65912_device_exit(struct tps65912 *tps65912)
157{
158 mfd_remove_devices(tps65912->dev);
159 kfree(tps65912);
160}
161
162MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
163MODULE_DESCRIPTION("TPS65912x chip family multi-function driver");
164MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c
new file mode 100644
index 000000000000..9ed123aa6624
--- /dev/null
+++ b/drivers/mfd/tps65912-i2c.c
@@ -0,0 +1,139 @@
1/*
2 * tps65912-i2c.c -- I2C access for TI TPS65912x PMIC
3 *
4 * Copyright 2011 Texas Instruments Inc.
5 *
6 * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This driver is based on wm8350 implementation.
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/gpio.h>
21#include <linux/i2c.h>
22#include <linux/mfd/core.h>
23#include <linux/mfd/tps65912.h>
24
25static int tps65912_i2c_read(struct tps65912 *tps65912, u8 reg,
26 int bytes, void *dest)
27{
28 struct i2c_client *i2c = tps65912->control_data;
29 struct i2c_msg xfer[2];
30 int ret;
31
32 /* Write register */
33 xfer[0].addr = i2c->addr;
34 xfer[0].flags = 0;
35 xfer[0].len = 1;
36 xfer[0].buf = &reg;
37
38 /* Read data */
39 xfer[1].addr = i2c->addr;
40 xfer[1].flags = I2C_M_RD;
41 xfer[1].len = bytes;
42 xfer[1].buf = dest;
43
44 ret = i2c_transfer(i2c->adapter, xfer, 2);
45 if (ret == 2)
46 ret = 0;
47 else if (ret >= 0)
48 ret = -EIO;
49 return ret;
50}
51
52static int tps65912_i2c_write(struct tps65912 *tps65912, u8 reg,
53 int bytes, void *src)
54{
55 struct i2c_client *i2c = tps65912->control_data;
56 /* we add 1 byte for device register */
57 u8 msg[TPS6591X_MAX_REGISTER + 1];
58 int ret;
59
60 if (bytes > (TPS6591X_MAX_REGISTER + 1))
61 return -EINVAL;
62
63 msg[0] = reg;
64 memcpy(&msg[1], src, bytes);
65
66 ret = i2c_master_send(i2c, msg, bytes + 1);
67 if (ret < 0)
68 return ret;
69 if (ret != bytes + 1)
70 return -EIO;
71
72 return 0;
73}
74
75static int tps65912_i2c_probe(struct i2c_client *i2c,
76 const struct i2c_device_id *id)
77{
78 struct tps65912 *tps65912;
79
80 tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
81 if (tps65912 == NULL)
82 return -ENOMEM;
83
84 i2c_set_clientdata(i2c, tps65912);
85 tps65912->dev = &i2c->dev;
86 tps65912->control_data = i2c;
87 tps65912->read = tps65912_i2c_read;
88 tps65912->write = tps65912_i2c_write;
89
90 return tps65912_device_init(tps65912);
91}
92
93static int tps65912_i2c_remove(struct i2c_client *i2c)
94{
95 struct tps65912 *tps65912 = i2c_get_clientdata(i2c);
96
97 tps65912_device_exit(tps65912);
98
99 return 0;
100}
101
102static const struct i2c_device_id tps65912_i2c_id[] = {
103 {"tps65912", 0 },
104 { }
105};
106MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id);
107
108static struct i2c_driver tps65912_i2c_driver = {
109 .driver = {
110 .name = "tps65912",
111 .owner = THIS_MODULE,
112 },
113 .probe = tps65912_i2c_probe,
114 .remove = tps65912_i2c_remove,
115 .id_table = tps65912_i2c_id,
116};
117
118static int __init tps65912_i2c_init(void)
119{
120 int ret;
121
122 ret = i2c_add_driver(&tps65912_i2c_driver);
123 if (ret != 0)
124 pr_err("Failed to register TPS65912 I2C driver: %d\n", ret);
125
126 return ret;
127}
128/* init early so consumer devices can complete system boot */
129subsys_initcall(tps65912_i2c_init);
130
131static void __exit tps65912_i2c_exit(void)
132{
133 i2c_del_driver(&tps65912_i2c_driver);
134}
135module_exit(tps65912_i2c_exit);
136
137MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
138MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
139MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
new file mode 100644
index 000000000000..6d71e0d25744
--- /dev/null
+++ b/drivers/mfd/tps65912-spi.c
@@ -0,0 +1,142 @@
1/*
2 * tps65912-spi.c -- SPI access for TI TPS65912x PMIC
3 *
4 * Copyright 2011 Texas Instruments Inc.
5 *
6 * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This driver is based on wm8350 implementation.
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/gpio.h>
21#include <linux/spi/spi.h>
22#include <linux/mfd/core.h>
23#include <linux/mfd/tps65912.h>
24
25static int tps65912_spi_write(struct tps65912 *tps65912, u8 addr,
26 int bytes, void *src)
27{
28 struct spi_device *spi = tps65912->control_data;
29 u8 *data = (u8 *) src;
30 int ret;
31 /* bit 23 is the read/write bit */
32 unsigned long spi_data = 1 << 23 | addr << 15 | *data;
33 struct spi_transfer xfer;
34 struct spi_message msg;
35 u32 tx_buf, rx_buf;
36
37 tx_buf = spi_data;
38 rx_buf = 0;
39
40 xfer.tx_buf = &tx_buf;
41 xfer.rx_buf = NULL;
42 xfer.len = sizeof(unsigned long);
43 xfer.bits_per_word = 24;
44
45 spi_message_init(&msg);
46 spi_message_add_tail(&xfer, &msg);
47
48 ret = spi_sync(spi, &msg);
49 return ret;
50}
51
52static int tps65912_spi_read(struct tps65912 *tps65912, u8 addr,
53 int bytes, void *dest)
54{
55 struct spi_device *spi = tps65912->control_data;
56 /* bit 23 is the read/write bit */
57 unsigned long spi_data = 0 << 23 | addr << 15;
58 struct spi_transfer xfer;
59 struct spi_message msg;
60 int ret;
61 u8 *data = (u8 *) dest;
62 u32 tx_buf, rx_buf;
63
64 tx_buf = spi_data;
65 rx_buf = 0;
66
67 xfer.tx_buf = &tx_buf;
68 xfer.rx_buf = &rx_buf;
69 xfer.len = sizeof(unsigned long);
70 xfer.bits_per_word = 24;
71
72 spi_message_init(&msg);
73 spi_message_add_tail(&xfer, &msg);
74
75 if (spi == NULL)
76 return 0;
77
78 ret = spi_sync(spi, &msg);
79 if (ret == 0)
80 *data = (u8) (rx_buf & 0xFF);
81 return ret;
82}
83
84static int __devinit tps65912_spi_probe(struct spi_device *spi)
85{
86 struct tps65912 *tps65912;
87
88 tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
89 if (tps65912 == NULL)
90 return -ENOMEM;
91
92 tps65912->dev = &spi->dev;
93 tps65912->control_data = spi;
94 tps65912->read = tps65912_spi_read;
95 tps65912->write = tps65912_spi_write;
96
97 spi_set_drvdata(spi, tps65912);
98
99 return tps65912_device_init(tps65912);
100}
101
102static int __devexit tps65912_spi_remove(struct spi_device *spi)
103{
104 struct tps65912 *tps65912 = spi_get_drvdata(spi);
105
106 tps65912_device_exit(tps65912);
107
108 return 0;
109}
110
111static struct spi_driver tps65912_spi_driver = {
112 .driver = {
113 .name = "tps65912",
114 .bus = &spi_bus_type,
115 .owner = THIS_MODULE,
116 },
117 .probe = tps65912_spi_probe,
118 .remove = __devexit_p(tps65912_spi_remove),
119};
120
121static int __init tps65912_spi_init(void)
122{
123 int ret;
124
125 ret = spi_register_driver(&tps65912_spi_driver);
126 if (ret != 0)
127 pr_err("Failed to register TPS65912 SPI driver: %d\n", ret);
128
129 return 0;
130}
131/* init early so consumer devices can complete system boot */
132subsys_initcall(tps65912_spi_init);
133
134static void __exit tps65912_spi_exit(void)
135{
136 spi_unregister_driver(&tps65912_spi_driver);
137}
138module_exit(tps65912_spi_exit);
139
140MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
141MODULE_DESCRIPTION("SPI support for TPS65912 chip family mfd");
142MODULE_LICENSE("GPL");