aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2012-09-28 13:46:28 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2012-09-28 14:50:15 -0400
commitdaa22703f14c007e93b464c45fa60019a36f546d (patch)
treea1a130b6e128dc9d57c35c026977e1b4953105e1 /drivers/mfd
parent5aa287dcf1b5879aa0150b0511833c52885f5b4c (diff)
Apply k4412 kernel from HardKernel for ODROID-X.
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig31
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/max77686-irq.c251
-rw-r--r--drivers/mfd/max77686.c388
-rw-r--r--drivers/mfd/max8698.c161
-rw-r--r--drivers/mfd/max8997.c32
-rw-r--r--drivers/mfd/s5m-core.c248
-rw-r--r--drivers/mfd/s5m-irq.c487
-rw-r--r--drivers/mfd/wm8994-core.c16
9 files changed, 1615 insertions, 2 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6ca938a6bf9..81a184098e1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -349,6 +349,37 @@ config MFD_MAX8998
349 additional drivers must be enabled in order to use the functionality 349 additional drivers must be enabled in order to use the functionality
350 of the device. 350 of the device.
351 351
352config MFD_MAX8698
353 bool "Maxim Semiconductor MAX8698 PMIC Support"
354 depends on I2C=y
355 select MFD_CORE
356 help
357 Say yes here to support for Maxim Semiconductor MAX8698. This is
358 a Power Management IC. This driver provies common support for
359 accessing the device, additional drivers must be enabled in order
360 to use the functionality of the device.
361
362config MFD_MAX77686
363 bool "Maxim Semiconductor MAX77686 PMIC Support"
364 depends on I2C=y && GENERIC_HARDIRQS
365 select MFD_CORE
366 help
367 Say yes here to support for Maxim Semiconductor MAX77686.
368 This is a Power Management IC with RTC on chip.
369 This driver provides common support for accessing the device;
370 additional drivers must be enabled in order to use the functionality
371 of the device.
372
373config MFD_S5M_CORE
374 bool "SAMSUNG S5M Series Support"
375 depends on I2C=y && GENERIC_HARDIRQS
376 select MFD_CORE
377 help
378 Support for the Samsung Electronics S5M MFD series.
379 This driver provies common support for accessing the device,
380 additional drivers must be enabled in order to use the functionality
381 of the device
382
352config MFD_WM8400 383config MFD_WM8400
353 tristate "Support Wolfson Microelectronics WM8400" 384 tristate "Support Wolfson Microelectronics WM8400"
354 select MFD_CORE 385 select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index d7d47d2a4c7..a761c91e227 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -64,6 +64,8 @@ max8925-objs := max8925-core.o max8925-i2c.o
64obj-$(CONFIG_MFD_MAX8925) += max8925.o 64obj-$(CONFIG_MFD_MAX8925) += max8925.o
65obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o 65obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
66obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o 66obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
67obj-$(CONFIG_MFD_MAX8698) += max8698.o
68obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o
67 69
68pcf50633-objs := pcf50633-core.o pcf50633-irq.o 70pcf50633-objs := pcf50633-core.o pcf50633-irq.o
69obj-$(CONFIG_MFD_PCF50633) += pcf50633.o 71obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
@@ -95,3 +97,4 @@ obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
95obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o 97obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
96obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o 98obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o
97obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o 99obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
100obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
diff --git a/drivers/mfd/max77686-irq.c b/drivers/mfd/max77686-irq.c
new file mode 100644
index 00000000000..8b58e3d36a6
--- /dev/null
+++ b/drivers/mfd/max77686-irq.c
@@ -0,0 +1,251 @@
1/*
2 * max77686-irq.c - Interrupt controller support for MAX77686
3 *
4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * MyungJoo Ham <myungjoo.ham@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * This driver is based on max8998-irq.c
22 */
23
24#include <linux/err.h>
25#include <linux/irq.h>
26#include <linux/interrupt.h>
27#include <linux/mfd/max77686.h>
28#include <linux/mfd/max77686-private.h>
29
30static const u8 max77686_mask_reg[] = {
31 [PMIC_INT1] = MAX77686_REG_INT1MSK,
32 [PMIC_INT2] = MAX77686_REG_INT2MSK,
33};
34
35static struct i2c_client *get_i2c(struct max77686_dev *max77686,
36 enum max77686_irq_source src)
37{
38 switch (src) {
39 case PMIC_INT1 ... PMIC_INT2:
40 return max77686->i2c;
41 default:
42 return ERR_PTR(-EINVAL);
43 }
44
45 return ERR_PTR(-EINVAL);
46}
47
48struct max77686_irq_data {
49 int mask;
50 enum max77686_irq_source group;
51};
52
53#define DECLARE_IRQ(idx, _group, _mask) \
54 [(idx)] = { .group = (_group), .mask = (_mask) }
55static const struct max77686_irq_data max77686_irqs[] = {
56 DECLARE_IRQ(MAX77686_TOPSYSIRQ_PWRONF, PMIC_INT1, 1 << 0),
57 DECLARE_IRQ(MAX77686_TOPSYSIRQ_PWRONR, PMIC_INT1, 1 << 1),
58 DECLARE_IRQ(MAX77686_TOPSYSIRQ_JIGONF, PMIC_INT1, 1 << 2),
59 DECLARE_IRQ(MAX77686_TOPSYSIRQ_JIGONR, PMIC_INT1, 1 << 3),
60 DECLARE_IRQ(MAX77686_TOPSYSIRQ_ACOKBF, PMIC_INT1, 1 << 4),
61 DECLARE_IRQ(MAX77686_TOPSYSIRQ_ACOKBR, PMIC_INT1, 1 << 5),
62 DECLARE_IRQ(MAX77686_TOPSYSIRQ_ONKEY1S, PMIC_INT1, 1 << 6),
63 DECLARE_IRQ(MAX77686_TOPSYSIRQ_MRSTB, PMIC_INT1, 1 << 7),
64
65 DECLARE_IRQ(MAX77686_TOPSYSIRQ_120C, PMIC_INT2, 1 << 0),
66 DECLARE_IRQ(MAX77686_TOPSYSIRQ_140C, PMIC_INT2, 1 << 1),
67};
68
69static void max77686_irq_lock(struct irq_data *data)
70{
71 struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
72
73 mutex_lock(&max77686->irqlock);
74}
75
76static void max77686_irq_sync_unlock(struct irq_data *data)
77{
78 struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
79 int i;
80
81 for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
82 u8 mask_reg = max77686_mask_reg[i];
83 struct i2c_client *i2c = get_i2c(max77686, i);
84
85 if (mask_reg == MAX77686_REG_INVALID ||
86 IS_ERR_OR_NULL(i2c))
87 continue;
88 max77686->irq_masks_cache[i] = max77686->irq_masks_cur[i];
89
90 max77686_write_reg(i2c, max77686_mask_reg[i],
91 max77686->irq_masks_cur[i]);
92 }
93
94 mutex_unlock(&max77686->irqlock);
95}
96
97static const inline struct max77686_irq_data *
98irq_to_max77686_irq(struct max77686_dev *max77686, int irq)
99{
100 return &max77686_irqs[irq - max77686->irq_base];
101}
102
103static void max77686_irq_mask(struct irq_data *data)
104{
105 struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
106 const struct max77686_irq_data *irq_data = irq_to_max77686_irq(max77686,
107 data->irq);
108
109 max77686->irq_masks_cur[irq_data->group] |= irq_data->mask;
110}
111
112static void max77686_irq_unmask(struct irq_data *data)
113{
114 struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
115 const struct max77686_irq_data *irq_data = irq_to_max77686_irq(max77686,
116 data->irq);
117
118 max77686->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
119}
120
121static struct irq_chip max77686_irq_chip = {
122 .name = "max77686",
123 .irq_bus_lock = max77686_irq_lock,
124 .irq_bus_sync_unlock = max77686_irq_sync_unlock,
125 .irq_mask = max77686_irq_mask,
126 .irq_unmask = max77686_irq_unmask,
127};
128
129#define MAX77686_IRQSRC_PMIC (1 << 1)
130static irqreturn_t max77686_irq_thread(int irq, void *data)
131{
132 struct max77686_dev *max77686 = data;
133 u8 irq_reg[MAX77686_IRQ_GROUP_NR] = {};
134 u8 irq_src;
135 int ret;
136 int i;
137
138 ret = max77686_read_reg(max77686->i2c, MAX77686_REG_INTSRC, &irq_src);
139 if (ret < 0) {
140 dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
141 ret);
142 return IRQ_NONE;
143 }
144
145 if (irq_src & MAX77686_IRQSRC_PMIC) {
146 /* PMIC INT1 ~ INT4 */
147 max77686_bulk_read(max77686->i2c, MAX77686_REG_INT1, 2,
148 &irq_reg[PMIC_INT1]);
149 }
150
151 /* Apply masking */
152 for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++)
153 irq_reg[i] &= ~max77686->irq_masks_cur[i];
154
155 /* Report */
156 for (i = 0; i < MAX77686_IRQ_NR; i++) {
157 if (irq_reg[max77686_irqs[i].group] & max77686_irqs[i].mask)
158 handle_nested_irq(max77686->irq_base + i);
159 }
160
161 return IRQ_HANDLED;
162}
163
164int max77686_irq_resume(struct max77686_dev *max77686)
165{
166 if (max77686->irq && max77686->irq_base)
167 max77686_irq_thread(max77686->irq_base, max77686);
168 return 0;
169}
170
171int max77686_irq_init(struct max77686_dev *max77686)
172{
173 int i;
174 int cur_irq;
175 int ret;
176
177 if (!max77686->irq) {
178 dev_warn(max77686->dev, "No interrupt specified.\n");
179 max77686->irq_base = 0;
180 return 0;
181 }
182
183 if (!max77686->irq_base) {
184 dev_err(max77686->dev, "No interrupt base specified.\n");
185 return 0;
186 }
187
188 mutex_init(&max77686->irqlock);
189
190 /* Mask individual interrupt sources */
191 for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
192 struct i2c_client *i2c;
193
194 max77686->irq_masks_cur[i] = 0xff;
195 max77686->irq_masks_cache[i] = 0xff;
196 i2c = get_i2c(max77686, i);
197
198 if (IS_ERR_OR_NULL(i2c))
199 continue;
200 if (max77686_mask_reg[i] == MAX77686_REG_INVALID)
201 continue;
202
203 max77686_write_reg(i2c, max77686_mask_reg[i], 0xff);
204 }
205
206 /* Register with genirq */
207 for (i = 0; i < MAX77686_IRQ_NR; i++) {
208 cur_irq = i + max77686->irq_base;
209 irq_set_chip_data(cur_irq, max77686);
210 irq_set_chip_and_handler(cur_irq, &max77686_irq_chip,
211 handle_edge_irq);
212 irq_set_nested_thread(cur_irq, 1);
213#ifdef CONFIG_ARM
214 set_irq_flags(cur_irq, IRQF_VALID);
215#else
216 irq_set_noprobe(cur_irq);
217#endif
218 }
219
220 ret = request_threaded_irq(max77686->irq, NULL, max77686_irq_thread,
221 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
222 "max77686-irq", max77686);
223
224 if (ret) {
225 dev_err(max77686->dev, "Failed to request IRQ %d: %d\n",
226 max77686->irq, ret);
227 return ret;
228 }
229
230 if (!max77686->ono)
231 return 0;
232
233 ret = request_threaded_irq(max77686->ono, NULL, max77686_irq_thread,
234 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
235 IRQF_ONESHOT, "max77686-ono", max77686);
236
237 if (ret)
238 dev_err(max77686->dev, "Failed to request ono-IRQ %d: %d\n",
239 max77686->ono, ret);
240
241 return 0;
242}
243
244void max77686_irq_exit(struct max77686_dev *max77686)
245{
246 if (max77686->ono)
247 free_irq(max77686->ono, max77686);
248
249 if (max77686->irq)
250 free_irq(max77686->irq, max77686);
251}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
new file mode 100644
index 00000000000..ba94af7e26b
--- /dev/null
+++ b/drivers/mfd/max77686.c
@@ -0,0 +1,388 @@
1/*
2 * max77686.c - mfd core driver for the Maxim 8966 and 8997
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * MyungJoo Ham <myungjoo.ham@smasung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * This driver is based on max8998.c
22 */
23
24#include <linux/slab.h>
25#include <linux/i2c.h>
26#include <linux/interrupt.h>
27#include <linux/pm_runtime.h>
28#include <linux/mutex.h>
29#include <linux/mfd/core.h>
30#include <linux/mfd/max77686.h>
31#include <linux/mfd/max77686-private.h>
32
33#define I2C_ADDR_PMIC (0x12 >> 1)
34#define I2C_ADDR_RTC (0x0C >> 1)
35
36static struct mfd_cell max77686_devs[] = {
37 { .name = "max77686-pmic", },
38 { .name = "max77686-rtc", },
39};
40
41int max77686_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
42{
43 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
44 int ret;
45
46 mutex_lock(&max77686->iolock);
47 ret = i2c_smbus_read_byte_data(i2c, reg);
48 mutex_unlock(&max77686->iolock);
49 if (ret < 0)
50 return ret;
51
52 ret &= 0xff;
53 *dest = ret;
54 return 0;
55}
56EXPORT_SYMBOL_GPL(max77686_read_reg);
57
58int max77686_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
59{
60 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
61 int ret;
62
63 mutex_lock(&max77686->iolock);
64 ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
65 mutex_unlock(&max77686->iolock);
66 if (ret < 0)
67 return ret;
68
69 return 0;
70}
71EXPORT_SYMBOL_GPL(max77686_bulk_read);
72
73int max77686_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
74{
75 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
76 int ret;
77
78 mutex_lock(&max77686->iolock);
79 ret = i2c_smbus_write_byte_data(i2c, reg, value);
80 mutex_unlock(&max77686->iolock);
81 return ret;
82}
83EXPORT_SYMBOL_GPL(max77686_write_reg);
84
85int max77686_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
86{
87 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
88 int ret;
89
90 mutex_lock(&max77686->iolock);
91 ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
92 mutex_unlock(&max77686->iolock);
93 if (ret < 0)
94 return ret;
95
96 return 0;
97}
98EXPORT_SYMBOL_GPL(max77686_bulk_write);
99
100int max77686_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
101{
102 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
103 int ret;
104
105 mutex_lock(&max77686->iolock);
106 ret = i2c_smbus_read_byte_data(i2c, reg);
107 if (ret >= 0) {
108 u8 old_val = ret & 0xff;
109 u8 new_val = (val & mask) | (old_val & (~mask));
110 ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
111 }
112 mutex_unlock(&max77686->iolock);
113 return ret;
114}
115EXPORT_SYMBOL_GPL(max77686_update_reg);
116
117static int max77686_i2c_probe(struct i2c_client *i2c,
118 const struct i2c_device_id *id)
119{
120 struct max77686_dev *max77686;
121 struct max77686_platform_data *pdata = i2c->dev.platform_data;
122 int ret = 0;
123
124 max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
125 if (max77686 == NULL)
126 return -ENOMEM;
127
128 i2c_set_clientdata(i2c, max77686);
129 max77686->dev = &i2c->dev;
130 max77686->i2c = i2c;
131 max77686->type = id->driver_data;
132 max77686->irq = i2c->irq;
133
134 if (!pdata)
135 goto err;
136
137 max77686->irq_base = pdata->irq_base;
138 max77686->ono = pdata->ono;
139
140 mutex_init(&max77686->iolock);
141
142 max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
143 i2c_set_clientdata(max77686->rtc, max77686);
144
145 pm_runtime_set_active(max77686->dev);
146
147 max77686_irq_init(max77686);
148
149 mfd_add_devices(max77686->dev, -1, max77686_devs,
150 ARRAY_SIZE(max77686_devs),
151 NULL, 0);
152
153 /*
154 * TODO: enable others (flash, muic, rtc, battery, ...) and
155 * check the return value
156 */
157
158 if (ret < 0)
159 goto err_mfd;
160
161 /* MAX77686 has a power button input. */
162 device_init_wakeup(max77686->dev, pdata->wakeup);
163
164 return ret;
165
166err_mfd:
167 mfd_remove_devices(max77686->dev);
168 i2c_unregister_device(max77686->rtc);
169err:
170 kfree(max77686);
171 return ret;
172}
173
174static int max77686_i2c_remove(struct i2c_client *i2c)
175{
176 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
177
178 mfd_remove_devices(max77686->dev);
179 i2c_unregister_device(max77686->rtc);
180 kfree(max77686);
181
182 return 0;
183}
184
185static const struct i2c_device_id max77686_i2c_id[] = {
186 { "max77686", 0 },
187 { }
188};
189MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
190
191u8 max77686_dumpaddr_pmic[] = {
192 MAX77686_REG_DEVICE_ID,
193 MAX77686_REG_INTSRC,
194 MAX77686_REG_INT1,
195 MAX77686_REG_INT2,
196 MAX77686_REG_INT1MSK,
197 MAX77686_REG_INT2MSK,
198
199 MAX77686_REG_STATUS1,
200 MAX77686_REG_STATUS2,
201
202 MAX77686_REG_PWRON,
203 MAX77686_REG_ONOFFDELAY,
204 MAX77686_REG_MRSTB,
205
206 MAX77686_REG_BUCK1CTRL,
207 MAX77686_REG_BUCK1OUT,
208
209 MAX77686_REG_BUCK2CTRL1,
210 MAX77686_REG_BUCK234FREQ,
211 MAX77686_REG_BUCK2DVS1,
212 MAX77686_REG_BUCK2DVS2,
213 MAX77686_REG_BUCK2DVS3,
214 MAX77686_REG_BUCK2DVS4,
215 MAX77686_REG_BUCK2DVS5,
216 MAX77686_REG_BUCK2DVS6,
217 MAX77686_REG_BUCK2DVS7,
218 MAX77686_REG_BUCK2DVS8,
219
220 MAX77686_REG_BUCK3CTRL1,
221 MAX77686_REG_BUCK3DVS1,
222 MAX77686_REG_BUCK3DVS2,
223 MAX77686_REG_BUCK3DVS3,
224 MAX77686_REG_BUCK3DVS4,
225 MAX77686_REG_BUCK3DVS5,
226 MAX77686_REG_BUCK3DVS6,
227 MAX77686_REG_BUCK3DVS7,
228 MAX77686_REG_BUCK3DVS8,
229
230 MAX77686_REG_BUCK4CTRL1,
231 MAX77686_REG_BUCK4DVS1,
232 MAX77686_REG_BUCK4DVS2,
233 MAX77686_REG_BUCK4DVS3,
234 MAX77686_REG_BUCK4DVS4,
235 MAX77686_REG_BUCK4DVS5,
236 MAX77686_REG_BUCK4DVS6,
237 MAX77686_REG_BUCK4DVS7,
238 MAX77686_REG_BUCK4DVS8,
239
240 MAX77686_REG_BUCK5CTRL,
241 MAX77686_REG_BUCK5OUT,
242 MAX77686_REG_BUCK6CTRL,
243 MAX77686_REG_BUCK6OUT,
244 MAX77686_REG_BUCK7CTRL,
245 MAX77686_REG_BUCK7OUT,
246 MAX77686_REG_BUCK8CTRL,
247 MAX77686_REG_BUCK8OUT,
248 MAX77686_REG_BUCK9CTRL,
249 MAX77686_REG_BUCK9OUT,
250
251 MAX77686_REG_LDO1CTRL1,
252 MAX77686_REG_LDO2CTRL1,
253 MAX77686_REG_LDO3CTRL1,
254 MAX77686_REG_LDO4CTRL1,
255 MAX77686_REG_LDO5CTRL1,
256 MAX77686_REG_LDO6CTRL1,
257 MAX77686_REG_LDO7CTRL1,
258 MAX77686_REG_LDO8CTRL1,
259 MAX77686_REG_LDO9CTRL1,
260 MAX77686_REG_LDO10CTRL1,
261 MAX77686_REG_LDO11CTRL1,
262 MAX77686_REG_LDO12CTRL1,
263 MAX77686_REG_LDO13CTRL1,
264 MAX77686_REG_LDO14CTRL1,
265 MAX77686_REG_LDO15CTRL1,
266 MAX77686_REG_LDO16CTRL1,
267 MAX77686_REG_LDO17CTRL1,
268 MAX77686_REG_LDO18CTRL1,
269 MAX77686_REG_LDO19CTRL1,
270 MAX77686_REG_LDO20CTRL1,
271 MAX77686_REG_LDO21CTRL1,
272 MAX77686_REG_LDO22CTRL1,
273 MAX77686_REG_LDO23CTRL1,
274 MAX77686_REG_LDO24CTRL1,
275 MAX77686_REG_LDO25CTRL1,
276 MAX77686_REG_LDO26CTRL1,
277
278 MAX77686_REG_LDO1CTRL2,
279 MAX77686_REG_LDO2CTRL2,
280 MAX77686_REG_LDO3CTRL2,
281 MAX77686_REG_LDO4CTRL2,
282 MAX77686_REG_LDO5CTRL2,
283 MAX77686_REG_LDO6CTRL2,
284 MAX77686_REG_LDO7CTRL2,
285 MAX77686_REG_LDO8CTRL2,
286 MAX77686_REG_LDO9CTRL2,
287 MAX77686_REG_LDO10CTRL2,
288 MAX77686_REG_LDO11CTRL2,
289 MAX77686_REG_LDO12CTRL2,
290 MAX77686_REG_LDO13CTRL2,
291 MAX77686_REG_LDO14CTRL2,
292 MAX77686_REG_LDO15CTRL2,
293 MAX77686_REG_LDO16CTRL2,
294 MAX77686_REG_LDO17CTRL2,
295 MAX77686_REG_LDO18CTRL2,
296 MAX77686_REG_LDO19CTRL2,
297 MAX77686_REG_LDO20CTRL2,
298 MAX77686_REG_LDO21CTRL2,
299 MAX77686_REG_LDO22CTRL2,
300 MAX77686_REG_LDO23CTRL2,
301 MAX77686_REG_LDO24CTRL2,
302 MAX77686_REG_LDO25CTRL2,
303 MAX77686_REG_LDO26CTRL2,
304
305 MAX77686_REG_BBAT_CHARGER,
306 MAX77686_REG_32KHZ,
307};
308
309static int max77686_freeze(struct device *dev)
310{
311 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
312 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
313 int i;
314
315 for (i = 0; i < ARRAY_SIZE(max77686_dumpaddr_pmic); i++)
316 max77686_read_reg(i2c, max77686_dumpaddr_pmic[i],
317 &max77686->reg_dump[i]);
318
319 return 0;
320}
321
322static int max77686_restore(struct device *dev)
323{
324 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
325 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
326 int i;
327
328 for (i = 0; i < ARRAY_SIZE(max77686_dumpaddr_pmic); i++)
329 max77686_write_reg(i2c, max77686_dumpaddr_pmic[i],
330 max77686->reg_dump[i]);
331
332 return 0;
333}
334
335static int max77686_suspend(struct device *dev)
336{
337 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
338 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
339
340 if (device_may_wakeup(dev))
341 irq_set_irq_wake(max77686->irq, 1);
342 return 0;
343}
344
345static int max77686_resume(struct device *dev)
346{
347 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
348 struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
349
350 if (device_may_wakeup(dev))
351 irq_set_irq_wake(max77686->irq, 0);
352 return max77686_irq_resume(max77686);
353}
354
355const struct dev_pm_ops max77686_pm = {
356 .suspend = max77686_suspend,
357 .resume = max77686_resume,
358 .freeze = max77686_freeze,
359 .restore = max77686_restore,
360};
361
362static struct i2c_driver max77686_i2c_driver = {
363 .driver = {
364 .name = "max77686",
365 .owner = THIS_MODULE,
366 .pm = &max77686_pm,
367 },
368 .probe = max77686_i2c_probe,
369 .remove = max77686_i2c_remove,
370 .id_table = max77686_i2c_id,
371};
372
373static int __init max77686_i2c_init(void)
374{
375 return i2c_add_driver(&max77686_i2c_driver);
376}
377/* init early so consumer devices can complete system boot */
378subsys_initcall(max77686_i2c_init);
379
380static void __exit max77686_i2c_exit(void)
381{
382 i2c_del_driver(&max77686_i2c_driver);
383}
384module_exit(max77686_i2c_exit);
385
386MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver");
387MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
388MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max8698.c b/drivers/mfd/max8698.c
new file mode 100644
index 00000000000..9dd60042920
--- /dev/null
+++ b/drivers/mfd/max8698.c
@@ -0,0 +1,161 @@
1/*
2 * max8698.c - mfd core driver for the Maxim 8698
3 *
4 * Copyright (C) 2009-2010 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com>
6 * Marek Szyprowski <m.szyprowski@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * 2010.10.26
23 * Modified by Taekki Kim <taekki.kim@samsung.com>
24 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <linux/i2c.h>
31#include <linux/mutex.h>
32#include <linux/mfd/core.h>
33#include <linux/mfd/max8698.h>
34#include <linux/mfd/max8698-private.h>
35
36static struct mfd_cell max8698_devs[] = {
37 {
38 .name = "max8698-pmic",
39 }
40};
41
42static int max8698_i2c_device_read(struct max8698_dev *max8698, u8 reg, u8 *dest)
43{
44 struct i2c_client *client = max8698->i2c_client;
45 int ret;
46
47 mutex_lock(&max8698->iolock);
48 ret = i2c_smbus_read_byte_data(client, reg);
49 mutex_unlock(&max8698->iolock);
50 if (ret < 0)
51 return ret;
52
53 ret &= 0xff;
54 *dest = ret;
55 return 0;
56}
57
58static int max8698_i2c_device_write(struct max8698_dev *max8698, u8 reg, u8 value)
59{
60 struct i2c_client *client = max8698->i2c_client;
61 int ret;
62
63 mutex_lock(&max8698->iolock);
64 ret = i2c_smbus_write_byte_data(client, reg, value);
65 mutex_unlock(&max8698->iolock);
66 return ret;
67}
68
69static int max8698_i2c_device_update(struct max8698_dev *max8698, u8 reg,
70 u8 val, u8 mask)
71{
72 struct i2c_client *client = max8698->i2c_client;
73 int ret;
74
75 mutex_lock(&max8698->iolock);
76 ret = i2c_smbus_read_byte_data(client, reg);
77 if (ret >= 0) {
78 u8 old_val = ret & 0xff;
79 u8 new_val = (val & mask) | (old_val & (~mask));
80 ret = i2c_smbus_write_byte_data(client, reg, new_val);
81 if (ret >= 0)
82 ret = 0;
83 }
84 mutex_unlock(&max8698->iolock);
85 return ret;
86}
87
88static int max8698_i2c_probe(struct i2c_client *i2c,
89 const struct i2c_device_id *id)
90{
91 struct max8698_dev *max8698;
92 int ret = 0;
93
94 max8698 = kzalloc(sizeof(struct max8698_dev), GFP_KERNEL);
95 if (max8698 == NULL)
96 return -ENOMEM;
97
98 i2c_set_clientdata(i2c, max8698);
99 max8698->dev = &i2c->dev;
100 max8698->i2c_client = i2c;
101 max8698->dev_read = max8698_i2c_device_read;
102 max8698->dev_write = max8698_i2c_device_write;
103 max8698->dev_update = max8698_i2c_device_update;
104 mutex_init(&max8698->iolock);
105
106 ret = mfd_add_devices(max8698->dev, -1,
107 max8698_devs, ARRAY_SIZE(max8698_devs),
108 NULL, 0);
109 if (ret < 0)
110 goto err;
111
112 return ret;
113
114err:
115 mfd_remove_devices(max8698->dev);
116 kfree(max8698);
117 return ret;
118}
119
120static int max8698_i2c_remove(struct i2c_client *i2c)
121{
122 struct max8698_dev *max8698 = i2c_get_clientdata(i2c);
123
124 mfd_remove_devices(max8698->dev);
125 kfree(max8698);
126
127 return 0;
128}
129
130static const struct i2c_device_id max8698_i2c_id[] = {
131 { "max8698", 0 },
132 { }
133};
134MODULE_DEVICE_TABLE(i2c, max8698_i2c_id);
135
136static struct i2c_driver max8698_i2c_driver = {
137 .driver = {
138 .name = "max8698",
139 .owner = THIS_MODULE,
140 },
141 .probe = max8698_i2c_probe,
142 .remove = max8698_i2c_remove,
143 .id_table = max8698_i2c_id,
144};
145
146static int __init max8698_i2c_init(void)
147{
148 return i2c_add_driver(&max8698_i2c_driver);
149}
150/* init early so consumer devices can complete system boot */
151subsys_initcall(max8698_i2c_init);
152
153static void __exit max8698_i2c_exit(void)
154{
155 i2c_del_driver(&max8698_i2c_driver);
156}
157module_exit(max8698_i2c_exit);
158
159MODULE_DESCRIPTION("MAXIM 8698 multi-function core driver");
160MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
161MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 5d1fca0277e..dc58750bb71 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -23,6 +23,7 @@
23 23
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/i2c.h> 25#include <linux/i2c.h>
26#include <linux/interrupt.h>
26#include <linux/pm_runtime.h> 27#include <linux/pm_runtime.h>
27#include <linux/mutex.h> 28#include <linux/mutex.h>
28#include <linux/mfd/core.h> 29#include <linux/mfd/core.h>
@@ -135,11 +136,13 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
135 max8997->dev = &i2c->dev; 136 max8997->dev = &i2c->dev;
136 max8997->i2c = i2c; 137 max8997->i2c = i2c;
137 max8997->type = id->driver_data; 138 max8997->type = id->driver_data;
139 max8997->irq = i2c->irq;
138 140
139 if (!pdata) 141 if (!pdata)
140 goto err; 142 goto err;
141 143
142 max8997->wakeup = pdata->wakeup; 144 max8997->irq_base = pdata->irq_base;
145 max8997->ono = pdata->ono;
143 146
144 mutex_init(&max8997->iolock); 147 mutex_init(&max8997->iolock);
145 148
@@ -152,6 +155,8 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
152 155
153 pm_runtime_set_active(max8997->dev); 156 pm_runtime_set_active(max8997->dev);
154 157
158 max8997_irq_init(max8997);
159
155 mfd_add_devices(max8997->dev, -1, max8997_devs, 160 mfd_add_devices(max8997->dev, -1, max8997_devs,
156 ARRAY_SIZE(max8997_devs), 161 ARRAY_SIZE(max8997_devs),
157 NULL, 0); 162 NULL, 0);
@@ -164,6 +169,9 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
164 if (ret < 0) 169 if (ret < 0)
165 goto err_mfd; 170 goto err_mfd;
166 171
172 /* MAX8997 has a power button input. */
173 device_init_wakeup(max8997->dev, pdata->wakeup);
174
167 return ret; 175 return ret;
168 176
169err_mfd: 177err_mfd:
@@ -393,7 +401,29 @@ static int max8997_restore(struct device *dev)
393 return 0; 401 return 0;
394} 402}
395 403
404static int max8997_suspend(struct device *dev)
405{
406 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
407 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
408
409 if (device_may_wakeup(dev))
410 irq_set_irq_wake(max8997->irq, 1);
411 return 0;
412}
413
414static int max8997_resume(struct device *dev)
415{
416 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
417 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
418
419 if (device_may_wakeup(dev))
420 irq_set_irq_wake(max8997->irq, 0);
421 return max8997_irq_resume(max8997);
422}
423
396const struct dev_pm_ops max8997_pm = { 424const struct dev_pm_ops max8997_pm = {
425 .suspend = max8997_suspend,
426 .resume = max8997_resume,
397 .freeze = max8997_freeze, 427 .freeze = max8997_freeze,
398 .restore = max8997_restore, 428 .restore = max8997_restore,
399}; 429};
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
new file mode 100644
index 00000000000..43fde54faba
--- /dev/null
+++ b/drivers/mfd/s5m-core.c
@@ -0,0 +1,248 @@
1/*
2 * s5m87xx.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/i2c.h>
19#include <linux/interrupt.h>
20#include <linux/pm_runtime.h>
21#include <linux/mutex.h>
22#include <linux/mfd/core.h>
23#include <linux/mfd/s5m87xx/s5m-core.h>
24#include <linux/mfd/s5m87xx/s5m-pmic.h>
25#include <linux/mfd/s5m87xx/s5m-rtc.h>
26
27static struct mfd_cell s5m87xx_devs[] = {
28 {
29 .name = "s5m8767-pmic",
30 }, {
31 .name = "s5m8763-pmic",
32 }, {
33 .name = "s5m-rtc",
34 },
35};
36
37int s5m_reg_read(struct i2c_client *i2c, u8 reg, u8 *dest)
38{
39 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
40 int ret;
41
42 mutex_lock(&s5m87xx->iolock);
43 ret = i2c_smbus_read_byte_data(i2c, reg);
44 mutex_unlock(&s5m87xx->iolock);
45 if (ret < 0)
46 return ret;
47
48 ret &= 0xff;
49 *dest = ret;
50 return 0;
51}
52EXPORT_SYMBOL(s5m_reg_read);
53
54int s5m_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
55{
56 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
57 int ret;
58
59 mutex_lock(&s5m87xx->iolock);
60 ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
61 mutex_unlock(&s5m87xx->iolock);
62 if (ret < 0)
63 return ret;
64
65 return 0;
66}
67EXPORT_SYMBOL(s5m_bulk_read);
68
69int s5m_reg_write(struct i2c_client *i2c, u8 reg, u8 value)
70{
71 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
72 int ret;
73
74 mutex_lock(&s5m87xx->iolock);
75 ret = i2c_smbus_write_byte_data(i2c, reg, value);
76 mutex_unlock(&s5m87xx->iolock);
77 return ret;
78}
79EXPORT_SYMBOL(s5m_reg_write);
80
81int s5m_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
82{
83 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
84 int ret;
85
86 mutex_lock(&s5m87xx->iolock);
87 ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
88 mutex_unlock(&s5m87xx->iolock);
89 if (ret < 0)
90 return ret;
91
92 return 0;
93}
94EXPORT_SYMBOL(s5m_bulk_write);
95
96int s5m_reg_update(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
97{
98 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
99 int ret;
100
101 mutex_lock(&s5m87xx->iolock);
102 ret = i2c_smbus_read_byte_data(i2c, reg);
103 if (ret >= 0) {
104 u8 old_val = ret & 0xff;
105 u8 new_val = (val & mask) | (old_val & (~mask));
106 ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
107 }
108 mutex_unlock(&s5m87xx->iolock);
109 return ret;
110}
111EXPORT_SYMBOL(s5m_reg_update);
112
113static int s5m87xx_i2c_probe(struct i2c_client *i2c,
114 const struct i2c_device_id *id)
115{
116 struct s5m_platform_data *pdata = i2c->dev.platform_data;
117 struct s5m87xx_dev *s5m87xx;
118 int ret = 0;
119
120 s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
121 if (s5m87xx == NULL)
122 return -ENOMEM;
123
124 i2c_set_clientdata(i2c, s5m87xx);
125 s5m87xx->dev = &i2c->dev;
126 s5m87xx->i2c = i2c;
127 s5m87xx->irq = i2c->irq;
128 s5m87xx->type = id->driver_data;
129
130 if (pdata) {
131 s5m87xx->device_type = pdata->device_type;
132 s5m87xx->ono = pdata->ono;
133 s5m87xx->irq_base = pdata->irq_base;
134 s5m87xx->wakeup = pdata->wakeup;
135 s5m87xx->wtsr_smpl = pdata->wtsr_smpl;
136 }
137
138 mutex_init(&s5m87xx->iolock);
139
140 s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
141 i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
142
143 if (pdata && pdata->cfg_pmic_irq)
144 pdata->cfg_pmic_irq();
145
146 s5m_irq_init(s5m87xx);
147
148 pm_runtime_set_active(s5m87xx->dev);
149
150 ret = mfd_add_devices(s5m87xx->dev, -1,
151 s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
152 NULL, 0);
153
154 if (ret < 0)
155 goto err;
156
157 dev_info(s5m87xx->dev ,"S5M87xx MFD probe done!!! \n");
158 return ret;
159
160err:
161 mfd_remove_devices(s5m87xx->dev);
162 s5m_irq_exit(s5m87xx);
163 i2c_unregister_device(s5m87xx->rtc);
164 kfree(s5m87xx);
165 return ret;
166}
167
168static int s5m87xx_i2c_remove(struct i2c_client *i2c)
169{
170 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
171
172 mfd_remove_devices(s5m87xx->dev);
173 s5m_irq_exit(s5m87xx);
174 i2c_unregister_device(s5m87xx->rtc);
175 kfree(s5m87xx);
176
177 return 0;
178}
179
180static const struct i2c_device_id s5m87xx_i2c_id[] = {
181 { "s5m87xx", 0 },
182 { }
183};
184MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
185
186#ifdef CONFIG_PM
187static int s5m_suspend(struct device *dev)
188{
189 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
190 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
191
192 if (s5m87xx->wakeup)
193 enable_irq_wake(s5m87xx->irq);
194
195 disable_irq(s5m87xx->irq);
196
197 return 0;
198}
199
200static int s5m_resume(struct device *dev)
201{
202 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
203 struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
204
205 if (s5m87xx->wakeup)
206 disable_irq_wake(s5m87xx->irq);
207
208 enable_irq(s5m87xx->irq);
209
210 return 0;
211}
212#else
213#define s5m_suspend NULL
214#define s5m_resume NULL
215#endif /* CONFIG_PM */
216
217const struct dev_pm_ops s5m87xx_apm = {
218 .suspend = s5m_suspend,
219 .resume = s5m_resume,
220};
221
222static struct i2c_driver s5m87xx_i2c_driver = {
223 .driver = {
224 .name = "s5m87xx",
225 .owner = THIS_MODULE,
226 .pm = &s5m87xx_apm,
227 },
228 .probe = s5m87xx_i2c_probe,
229 .remove = s5m87xx_i2c_remove,
230 .id_table = s5m87xx_i2c_id,
231};
232
233static int __init s5m87xx_i2c_init(void)
234{
235 return i2c_add_driver(&s5m87xx_i2c_driver);
236}
237
238subsys_initcall(s5m87xx_i2c_init);
239
240static void __exit s5m87xx_i2c_exit(void)
241{
242 i2c_del_driver(&s5m87xx_i2c_driver);
243}
244module_exit(s5m87xx_i2c_exit);
245
246MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
247MODULE_DESCRIPTION("Core support for the S5M87XX MFD");
248MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
new file mode 100644
index 00000000000..dbf1b7a0f17
--- /dev/null
+++ b/drivers/mfd/s5m-irq.c
@@ -0,0 +1,487 @@
1/*
2 * s5m87xx-irq.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/device.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/mfd/s5m87xx/s5m-core.h>
18
19struct s5m_irq_data {
20 int reg;
21 int mask;
22};
23
24static struct s5m_irq_data s5m8767_irqs[] = {
25 [S5M8767_IRQ_PWRR] = {
26 .reg = 1,
27 .mask = S5M8767_IRQ_PWRR_MASK,
28 },
29 [S5M8767_IRQ_PWRF] = {
30 .reg = 1,
31 .mask = S5M8767_IRQ_PWRF_MASK,
32 },
33 [S5M8767_IRQ_PWR1S] = {
34 .reg = 1,
35 .mask = S5M8767_IRQ_PWR1S_MASK,
36 },
37 [S5M8767_IRQ_JIGR] = {
38 .reg = 1,
39 .mask = S5M8767_IRQ_JIGR_MASK,
40 },
41 [S5M8767_IRQ_JIGF] = {
42 .reg = 1,
43 .mask = S5M8767_IRQ_JIGF_MASK,
44 },
45 [S5M8767_IRQ_LOWBAT2] = {
46 .reg = 1,
47 .mask = S5M8767_IRQ_LOWBAT2_MASK,
48 },
49 [S5M8767_IRQ_LOWBAT1] = {
50 .reg = 1,
51 .mask = S5M8767_IRQ_LOWBAT1_MASK,
52 },
53 [S5M8767_IRQ_MRB] = {
54 .reg = 2,
55 .mask = S5M8767_IRQ_MRB_MASK,
56 },
57 [S5M8767_IRQ_DVSOK2] = {
58 .reg = 2,
59 .mask = S5M8767_IRQ_DVSOK2_MASK,
60 },
61 [S5M8767_IRQ_DVSOK3] = {
62 .reg = 2,
63 .mask = S5M8767_IRQ_DVSOK3_MASK,
64 },
65 [S5M8767_IRQ_DVSOK4] = {
66 .reg = 2,
67 .mask = S5M8767_IRQ_DVSOK4_MASK,
68 },
69 [S5M8767_IRQ_RTC60S] = {
70 .reg = 3,
71 .mask = S5M8767_IRQ_RTC60S_MASK,
72 },
73 [S5M8767_IRQ_RTCA1] = {
74 .reg = 3,
75 .mask = S5M8767_IRQ_RTCA1_MASK,
76 },
77 [S5M8767_IRQ_RTCA2] = {
78 .reg = 3,
79 .mask = S5M8767_IRQ_RTCA2_MASK,
80 },
81 [S5M8767_IRQ_SMPL] = {
82 .reg = 3,
83 .mask = S5M8767_IRQ_SMPL_MASK,
84 },
85 [S5M8767_IRQ_RTC1S] = {
86 .reg = 3,
87 .mask = S5M8767_IRQ_RTC1S_MASK,
88 },
89 [S5M8767_IRQ_WTSR] = {
90 .reg = 3,
91 .mask = S5M8767_IRQ_WTSR_MASK,
92 },
93};
94
95static struct s5m_irq_data s5m8763_irqs[] = {
96 [S5M8763_IRQ_DCINF] = {
97 .reg = 1,
98 .mask = S5M8763_IRQ_DCINF_MASK,
99 },
100 [S5M8763_IRQ_DCINR] = {
101 .reg = 1,
102 .mask = S5M8763_IRQ_DCINR_MASK,
103 },
104 [S5M8763_IRQ_JIGF] = {
105 .reg = 1,
106 .mask = S5M8763_IRQ_JIGF_MASK,
107 },
108 [S5M8763_IRQ_JIGR] = {
109 .reg = 1,
110 .mask = S5M8763_IRQ_JIGR_MASK,
111 },
112 [S5M8763_IRQ_PWRONF] = {
113 .reg = 1,
114 .mask = S5M8763_IRQ_PWRONF_MASK,
115 },
116 [S5M8763_IRQ_PWRONR] = {
117 .reg = 1,
118 .mask = S5M8763_IRQ_PWRONR_MASK,
119 },
120 [S5M8763_IRQ_WTSREVNT] = {
121 .reg = 2,
122 .mask = S5M8763_IRQ_WTSREVNT_MASK,
123 },
124 [S5M8763_IRQ_SMPLEVNT] = {
125 .reg = 2,
126 .mask = S5M8763_IRQ_SMPLEVNT_MASK,
127 },
128 [S5M8763_IRQ_ALARM1] = {
129 .reg = 2,
130 .mask = S5M8763_IRQ_ALARM1_MASK,
131 },
132 [S5M8763_IRQ_ALARM0] = {
133 .reg = 2,
134 .mask = S5M8763_IRQ_ALARM0_MASK,
135 },
136 [S5M8763_IRQ_ONKEY1S] = {
137 .reg = 3,
138 .mask = S5M8763_IRQ_ONKEY1S_MASK,
139 },
140 [S5M8763_IRQ_TOPOFFR] = {
141 .reg = 3,
142 .mask = S5M8763_IRQ_TOPOFFR_MASK,
143 },
144 [S5M8763_IRQ_DCINOVPR] = {
145 .reg = 3,
146 .mask = S5M8763_IRQ_DCINOVPR_MASK,
147 },
148 [S5M8763_IRQ_CHGRSTF] = {
149 .reg = 3,
150 .mask = S5M8763_IRQ_CHGRSTF_MASK,
151 },
152 [S5M8763_IRQ_DONER] = {
153 .reg = 3,
154 .mask = S5M8763_IRQ_DONER_MASK,
155 },
156 [S5M8763_IRQ_CHGFAULT] = {
157 .reg = 3,
158 .mask = S5M8763_IRQ_CHGFAULT_MASK,
159 },
160 [S5M8763_IRQ_LOBAT1] = {
161 .reg = 4,
162 .mask = S5M8763_IRQ_LOBAT1_MASK,
163 },
164 [S5M8763_IRQ_LOBAT2] = {
165 .reg = 4,
166 .mask = S5M8763_IRQ_LOBAT2_MASK,
167 },
168};
169
170static inline struct s5m_irq_data *
171irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
172{
173 return &s5m8767_irqs[irq - s5m87xx->irq_base];
174}
175
176static void s5m8767_irq_lock(struct irq_data *data)
177{
178 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
179
180 mutex_lock(&s5m87xx->irqlock);
181}
182
183static void s5m8767_irq_sync_unlock(struct irq_data *data)
184{
185 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
186 int i;
187
188 for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
189 if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
190 s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
191 s5m_reg_write(s5m87xx->i2c, S5M8767_REG_INT1M + i,
192 s5m87xx->irq_masks_cur[i]);
193 }
194 }
195
196 mutex_unlock(&s5m87xx->irqlock);
197}
198
199static void s5m8767_irq_unmask(struct irq_data *data)
200{
201 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
202 struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
203 data->irq);
204
205 s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
206}
207
208static void s5m8767_irq_mask(struct irq_data *data)
209{
210 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
211 struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
212 data->irq);
213
214 s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
215}
216
217static struct irq_chip s5m8767_irq_chip = {
218 .name = "s5m8767",
219 .irq_bus_lock = s5m8767_irq_lock,
220 .irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
221 .irq_mask = s5m8767_irq_mask,
222 .irq_unmask = s5m8767_irq_unmask,
223};
224
225static inline struct s5m_irq_data *
226irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
227{
228 return &s5m8763_irqs[irq - s5m87xx->irq_base];
229}
230
231static void s5m8763_irq_lock(struct irq_data *data)
232{
233 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
234
235 mutex_lock(&s5m87xx->irqlock);
236}
237
238static void s5m8763_irq_sync_unlock(struct irq_data *data)
239{
240 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
241 int i;
242
243 for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
244 if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
245 s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
246 s5m_reg_write(s5m87xx->i2c, S5M8763_REG_IRQM1 + i,
247 s5m87xx->irq_masks_cur[i]);
248 }
249 }
250
251 mutex_unlock(&s5m87xx->irqlock);
252}
253
254static void s5m8763_irq_unmask(struct irq_data *data)
255{
256 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
257 struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
258 data->irq);
259
260 s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
261}
262
263static void s5m8763_irq_mask(struct irq_data *data)
264{
265 struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
266 struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
267 data->irq);
268
269 s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
270}
271
272static struct irq_chip s5m8763_irq_chip = {
273 .name = "s5m8763",
274 .irq_bus_lock = s5m8763_irq_lock,
275 .irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
276 .irq_mask = s5m8763_irq_mask,
277 .irq_unmask = s5m8763_irq_unmask,
278};
279
280
281static irqreturn_t s5m8767_irq_thread(int irq, void *data)
282{
283 struct s5m87xx_dev *s5m87xx = data;
284 u8 irq_reg[NUM_IRQ_REGS-1];
285 int ret;
286 int i;
287
288
289 ret = s5m_bulk_read(s5m87xx->i2c, S5M8767_REG_INT1,
290 NUM_IRQ_REGS - 1, irq_reg);
291 if (ret < 0) {
292 dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
293 ret);
294 return IRQ_NONE;
295 }
296
297 for (i = 0; i < NUM_IRQ_REGS - 1; i++)
298 irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
299
300 for (i = 0; i < S5M8767_IRQ_NR; i++) {
301 if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
302 handle_nested_irq(s5m87xx->irq_base + i);
303 }
304
305 return IRQ_HANDLED;
306}
307
308static irqreturn_t s5m8763_irq_thread(int irq, void *data)
309{
310 struct s5m87xx_dev *s5m87xx = data;
311 u8 irq_reg[NUM_IRQ_REGS];
312 int ret;
313 int i;
314
315 ret = s5m_bulk_read(s5m87xx->i2c, S5M8763_REG_IRQ1,
316 NUM_IRQ_REGS, irq_reg);
317 if (ret < 0) {
318 dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
319 ret);
320 return IRQ_NONE;
321 }
322
323 for (i = 0; i < NUM_IRQ_REGS; i++)
324 irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
325
326 for (i = 0; i < S5M8763_IRQ_NR; i++) {
327 if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
328 handle_nested_irq(s5m87xx->irq_base + i);
329 }
330
331 return IRQ_HANDLED;
332}
333
334int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
335{
336 if (s5m87xx->irq && s5m87xx->irq_base){
337 switch (s5m87xx->device_type) {
338 case S5M8763X:
339 s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
340 break;
341 case S5M8767X:
342 s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
343 break;
344 default:
345 break;
346
347 }
348 }
349 return 0;
350}
351
352int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
353{
354 int i;
355 int cur_irq;
356 int ret = 0;
357 int type = s5m87xx->device_type;
358
359 if (!s5m87xx->irq) {
360 dev_warn(s5m87xx->dev,
361 "No interrupt specified, no interrupts\n");
362 s5m87xx->irq_base = 0;
363 return 0;
364 }
365
366 if (!s5m87xx->irq_base) {
367 dev_err(s5m87xx->dev,
368 "No interrupt base specified, no interrupts\n");
369 return 0;
370 }
371
372 mutex_init(&s5m87xx->irqlock);
373
374 switch (type) {
375 case S5M8763X:
376 for (i = 0; i < NUM_IRQ_REGS; i++) {
377 s5m87xx->irq_masks_cur[i] = 0xff;
378 s5m87xx->irq_masks_cache[i] = 0xff;
379 s5m_reg_write(s5m87xx->i2c, S5M8763_REG_IRQM1 + i,
380 0xff);
381 }
382
383 s5m_reg_write(s5m87xx->i2c, S5M8763_REG_STATUSM1, 0xff);
384 s5m_reg_write(s5m87xx->i2c, S5M8763_REG_STATUSM2, 0xff);
385
386 for (i = 0; i < S5M8763_IRQ_NR; i++) {
387 cur_irq = i + s5m87xx->irq_base;
388 irq_set_chip_data(cur_irq, s5m87xx);
389 irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
390 handle_edge_irq);
391 irq_set_nested_thread(cur_irq, 1);
392#ifdef CONFIG_ARM
393 set_irq_flags(cur_irq, IRQF_VALID);
394#else
395 irq_set_noprobe(cur_irq);
396#endif
397 }
398
399 ret = request_threaded_irq(s5m87xx->irq, NULL,
400 s5m8763_irq_thread,
401 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
402 "s5m87xx-irq", s5m87xx);
403 if (ret) {
404 dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
405 s5m87xx->irq, ret);
406 return ret;
407 }
408 break;
409 case S5M8767X:
410 for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
411 s5m87xx->irq_masks_cur[i] = 0xff;
412 s5m87xx->irq_masks_cache[i] = 0xff;
413 s5m_reg_write(s5m87xx->i2c, S5M8767_REG_INT1M + i,
414 0xff);
415 }
416 for (i = 0; i < S5M8767_IRQ_NR; i++) {
417 cur_irq = i + s5m87xx->irq_base;
418 ret = irq_set_chip_data(cur_irq, s5m87xx);
419 if (ret) {
420 dev_err(s5m87xx->dev,
421 "Failed to irq_set_chip_data %d: %d\n",
422 s5m87xx->irq, ret);
423 return ret;
424 }
425
426 irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
427 handle_edge_irq);
428 irq_set_nested_thread(cur_irq, 1);
429#ifdef CONFIG_ARM
430 set_irq_flags(cur_irq, IRQF_VALID);
431#else
432 irq_set_noprobe(cur_irq);
433#endif
434 }
435
436 ret = request_threaded_irq(s5m87xx->irq, NULL,
437 s5m8767_irq_thread,
438 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
439 "s5m87xx-irq", s5m87xx);
440 if (ret) {
441 dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
442 s5m87xx->irq, ret);
443 return ret;
444 }
445 break;
446 default:
447 break;
448 }
449
450 if (!s5m87xx->ono)
451 return 0;
452
453 switch (type) {
454 case S5M8763X:
455 ret = request_threaded_irq(s5m87xx->ono, NULL,
456 s5m8763_irq_thread,
457 IRQF_TRIGGER_FALLING |
458 IRQF_TRIGGER_RISING |
459 IRQF_ONESHOT, "s5m87xx-ono",
460 s5m87xx);
461 break;
462 case S5M8767X:
463 ret = request_threaded_irq(s5m87xx->ono, NULL,
464 s5m8767_irq_thread,
465 IRQF_TRIGGER_FALLING |
466 IRQF_TRIGGER_RISING |
467 IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
468 break;
469 default:
470 break;
471 }
472
473 if (ret)
474 dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
475 s5m87xx->ono, ret);
476
477 return 0;
478}
479
480void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
481{
482 if (s5m87xx->ono)
483 free_irq(s5m87xx->ono, s5m87xx);
484
485 if (s5m87xx->irq)
486 free_irq(s5m87xx->irq, s5m87xx);
487}
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index e198d40292e..f9c04de57d4 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -348,6 +348,19 @@ static int wm8994_resume(struct device *dev)
348 348
349 return 0; 349 return 0;
350} 350}
351
352static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
353{
354 return wm8994_suspend(&i2c->dev);
355}
356
357static int wm8994_i2c_resume(struct i2c_client *i2c)
358{
359 return wm8994_resume(&i2c->dev);
360}
361#else
362#define wm8994_i2c_suspend NULL
363#define wm8994_i2c_resume NULL
351#endif 364#endif
352 365
353#ifdef CONFIG_REGULATOR 366#ifdef CONFIG_REGULATOR
@@ -653,10 +666,11 @@ static struct i2c_driver wm8994_i2c_driver = {
653 .driver = { 666 .driver = {
654 .name = "wm8994", 667 .name = "wm8994",
655 .owner = THIS_MODULE, 668 .owner = THIS_MODULE,
656 .pm = &wm8994_pm_ops,
657 }, 669 },
658 .probe = wm8994_i2c_probe, 670 .probe = wm8994_i2c_probe,
659 .remove = wm8994_i2c_remove, 671 .remove = wm8994_i2c_remove,
672 .suspend = wm8994_i2c_suspend,
673 .resume = wm8994_i2c_resume,
660 .id_table = wm8994_i2c_id, 674 .id_table = wm8994_i2c_id,
661}; 675};
662 676