mm: mm_event: add compaction stat
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / drivers / mfd / s2mpu09-irq.c
1 /*
2 * s2mpu09-irq.c - Interrupt controller support for S2MPU09
3 *
4 * Copyright (C) 2016 Samsung Electronics Co.Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include <linux/err.h>
23 #include <linux/irq.h>
24 #include <linux/interrupt.h>
25 #include <linux/gpio.h>
26 #include <linux/mfd/samsung/s2mpu09.h>
27 #include <linux/mfd/samsung/s2mpu09-regulator.h>
28
29 static const u8 s2mpu09_mask_reg[] = {
30 /* TODO: Need to check other INTMASK */
31 [PMIC_INT1] = S2MPU09_PMIC_REG_INT1M,
32 [PMIC_INT2] = S2MPU09_PMIC_REG_INT2M,
33 [PMIC_INT3] = S2MPU09_PMIC_REG_INT3M,
34 [PMIC_INT4] = S2MPU09_PMIC_REG_INT4M,
35 [PMIC_INT5] = S2MPU09_PMIC_REG_INT5M,
36 };
37
38 static struct i2c_client *get_i2c(struct s2mpu09_dev *s2mpu09,
39 enum s2mpu09_irq_source src)
40 {
41 switch (src) {
42 case PMIC_INT1 ... PMIC_INT5:
43 return s2mpu09->pmic;
44 default:
45 return ERR_PTR(-EINVAL);
46 }
47 }
48
49 struct s2mpu09_irq_data {
50 int mask;
51 enum s2mpu09_irq_source group;
52 };
53
54 #define DECLARE_IRQ(idx, _group, _mask) \
55 [(idx)] = { .group = (_group), .mask = (_mask) }
56 static const struct s2mpu09_irq_data s2mpu09_irqs[] = {
57 DECLARE_IRQ(S2MPU09_PMIC_IRQ_PWRONR_INT1, PMIC_INT1, 1 << 1),
58 DECLARE_IRQ(S2MPU09_PMIC_IRQ_PWRONF_INT1, PMIC_INT1, 1 << 0),
59 DECLARE_IRQ(S2MPU09_PMIC_IRQ_JIGONBF_INT1, PMIC_INT1, 1 << 2),
60 DECLARE_IRQ(S2MPU09_PMIC_IRQ_JIGONBR_INT1, PMIC_INT1, 1 << 3),
61 DECLARE_IRQ(S2MPU09_PMIC_IRQ_ACOKF_INT1, PMIC_INT1, 1 << 4),
62 DECLARE_IRQ(S2MPU09_PMIC_IRQ_ACOKR_INT1, PMIC_INT1, 1 << 5),
63 DECLARE_IRQ(S2MPU09_PMIC_IRQ_PWRON1S_INT1, PMIC_INT1, 1 << 6),
64 DECLARE_IRQ(S2MPU09_PMIC_IRQ_MRB_INT1, PMIC_INT1, 1 << 7),
65
66 DECLARE_IRQ(S2MPU09_PMIC_IRQ_RTC60S_INT2, PMIC_INT2, 1 << 0),
67 DECLARE_IRQ(S2MPU09_PMIC_IRQ_RTCA1_INT2, PMIC_INT2, 1 << 1),
68 DECLARE_IRQ(S2MPU09_PMIC_IRQ_RTCA0_INT2, PMIC_INT2, 1 << 2),
69 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SMPL_INT2, PMIC_INT2, 1 << 3),
70 DECLARE_IRQ(S2MPU09_PMIC_IRQ_RTC1S_INT2, PMIC_INT2, 1 << 4),
71 DECLARE_IRQ(S2MPU09_PMIC_IRQ_WTSR_INT2, PMIC_INT2, 1 << 5),
72 DECLARE_IRQ(S2MPU09_PMIC_IRQ_WTSRB_INT2, PMIC_INT2, 1 << 7),
73
74 DECLARE_IRQ(S2MPU09_PMIC_IRQ_120C_INT3, PMIC_INT3, 1 << 0),
75 DECLARE_IRQ(S2MPU09_PMIC_IRQ_140C_INT3, PMIC_INT3, 1 << 1),
76 DECLARE_IRQ(S2MPU09_PMIC_IRQ_TSD_INT3, PMIC_INT3, 1 << 2),
77 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB1_INT3, PMIC_INT3, 1 << 6),
78 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB2_INT3, PMIC_INT3, 1 << 7),
79
80 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB3_INT4, PMIC_INT4, 1 << 0),
81 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB4_INT4, PMIC_INT4, 1 << 1),
82 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB5_INT4, PMIC_INT4, 1 << 2),
83 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB6_INT4, PMIC_INT4, 1 << 3),
84 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB7_INT4, PMIC_INT4, 1 << 4),
85 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB8_INT4, PMIC_INT4, 1 << 5),
86 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB9_INT4, PMIC_INT4, 1 << 6),
87 DECLARE_IRQ(S2MPU09_PMIC_IRQ_OCPB10_INT4, PMIC_INT4, 1 << 7),
88
89 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO2_INT5, PMIC_INT5, 1 << 0),
90 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO18_INT5, PMIC_INT5, 1 << 1),
91 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO19_INT5, PMIC_INT5, 1 << 2),
92 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO33_INT5, PMIC_INT5, 1 << 3),
93 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO34_INT5, PMIC_INT5, 1 << 4),
94 DECLARE_IRQ(S2MPU09_PMIC_IRQ_SCLDO35_INT5, PMIC_INT5, 1 << 5),
95 };
96
97 static void s2mpu09_irq_lock(struct irq_data *data)
98 {
99 struct s2mpu09_dev *s2mpu09 = irq_get_chip_data(data->irq);
100
101 mutex_lock(&s2mpu09->irqlock);
102 }
103
104 static void s2mpu09_irq_sync_unlock(struct irq_data *data)
105 {
106 struct s2mpu09_dev *s2mpu09 = irq_get_chip_data(data->irq);
107 int i;
108
109 for (i = 0; i < S2MPU09_IRQ_GROUP_NR; i++) {
110 u8 mask_reg = s2mpu09_mask_reg[i];
111 struct i2c_client *i2c = get_i2c(s2mpu09, i);
112
113 if (mask_reg == S2MPU09_REG_INVALID ||
114 IS_ERR_OR_NULL(i2c))
115 continue;
116 s2mpu09->irq_masks_cache[i] = s2mpu09->irq_masks_cur[i];
117
118 s2mpu09_write_reg(i2c, s2mpu09_mask_reg[i],
119 s2mpu09->irq_masks_cur[i]);
120 }
121
122 mutex_unlock(&s2mpu09->irqlock);
123 }
124
125 static const inline struct s2mpu09_irq_data *
126 irq_to_s2mpu09_irq(struct s2mpu09_dev *s2mpu09, int irq)
127 {
128 return &s2mpu09_irqs[irq - s2mpu09->irq_base];
129 }
130
131 static void s2mpu09_irq_mask(struct irq_data *data)
132 {
133 struct s2mpu09_dev *s2mpu09 = irq_get_chip_data(data->irq);
134 const struct s2mpu09_irq_data *irq_data =
135 irq_to_s2mpu09_irq(s2mpu09, data->irq);
136
137 if (irq_data->group >= S2MPU09_IRQ_GROUP_NR)
138 return;
139
140 s2mpu09->irq_masks_cur[irq_data->group] |= irq_data->mask;
141 }
142
143 static void s2mpu09_irq_unmask(struct irq_data *data)
144 {
145 struct s2mpu09_dev *s2mpu09 = irq_get_chip_data(data->irq);
146 const struct s2mpu09_irq_data *irq_data =
147 irq_to_s2mpu09_irq(s2mpu09, data->irq);
148
149 if (irq_data->group >= S2MPU09_IRQ_GROUP_NR)
150 return;
151
152 s2mpu09->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
153 }
154
155 static struct irq_chip s2mpu09_irq_chip = {
156 .name = MFD_DEV_NAME,
157 .irq_bus_lock = s2mpu09_irq_lock,
158 .irq_bus_sync_unlock = s2mpu09_irq_sync_unlock,
159 .irq_mask = s2mpu09_irq_mask,
160 .irq_unmask = s2mpu09_irq_unmask,
161 };
162
163 static irqreturn_t s2mpu09_irq_thread(int irq, void *data)
164 {
165 struct s2mpu09_dev *s2mpu09 = data;
166 u8 irq_reg[S2MPU09_IRQ_GROUP_NR] = {0};
167 u8 irq_src;
168 int i, ret;
169
170 //pr_debug("%s: irq gpio pre-state(0x%02x)\n", __func__,
171 pr_err("%s: irq gpio pre-state(0x%02x)\n", __func__,
172 gpio_get_value(s2mpu09->irq_gpio));
173
174 ret = s2mpu09_read_reg(s2mpu09->i2c,
175 S2MPU09_PMIC_REG_INTSRC, &irq_src);
176 pr_err("%s: interrupt source(0x%02x)\n", __func__, irq_src);
177 if (ret) {
178 pr_err("%s:%s Failed to read interrupt source: %d\n",
179 MFD_DEV_NAME, __func__, ret);
180 return IRQ_NONE;
181 }
182
183 pr_info("%s: interrupt source(0x%02x)\n", __func__, irq_src);
184
185 if (irq_src & S2MPU09_IRQSRC_PMIC) {
186 /* PMIC_INT */
187 ret = s2mpu09_bulk_read(s2mpu09->pmic, S2MPU09_PMIC_REG_INT1,
188 S2MPU09_NUM_IRQ_PMIC_REGS, &irq_reg[PMIC_INT1]);
189 if (ret) {
190 pr_err("%s:%s Failed to read pmic interrupt: %d\n",
191 MFD_DEV_NAME, __func__, ret);
192 return IRQ_NONE;
193 }
194
195 pr_info("%s: pmic interrupt(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
196 __func__, irq_reg[PMIC_INT1], irq_reg[PMIC_INT2], irq_reg[PMIC_INT3],
197 irq_reg[PMIC_INT4], irq_reg[PMIC_INT5]);
198 }
199
200 /* Apply masking */
201 for (i = 0; i < S2MPU09_IRQ_GROUP_NR; i++)
202 irq_reg[i] &= ~s2mpu09->irq_masks_cur[i];
203
204 /* Report */
205 for (i = 0; i < S2MPU09_IRQ_NR; i++) {
206 if (irq_reg[s2mpu09_irqs[i].group] & s2mpu09_irqs[i].mask)
207 handle_nested_irq(s2mpu09->irq_base + i);
208 }
209
210 return IRQ_HANDLED;
211 }
212
213 int s2mpu09_irq_init(struct s2mpu09_dev *s2mpu09)
214 {
215 int i;
216 int ret;
217 u8 i2c_data;
218 int cur_irq;
219
220 if (!s2mpu09->irq_gpio) {
221 dev_warn(s2mpu09->dev, "No interrupt specified.\n");
222 s2mpu09->irq_base = 0;
223 return 0;
224 }
225
226 if (!s2mpu09->irq_base) {
227 dev_err(s2mpu09->dev, "No interrupt base specified.\n");
228 return 0;
229 }
230
231 mutex_init(&s2mpu09->irqlock);
232
233 s2mpu09->irq = gpio_to_irq(s2mpu09->irq_gpio);
234 pr_info("%s:%s irq=%d, irq->gpio=%d\n", MFD_DEV_NAME, __func__,
235 s2mpu09->irq, s2mpu09->irq_gpio);
236
237 ret = gpio_request(s2mpu09->irq_gpio, "pmic_irq");
238 if (ret) {
239 dev_err(s2mpu09->dev, "%s: failed requesting gpio %d\n",
240 __func__, s2mpu09->irq_gpio);
241 return ret;
242 }
243 gpio_direction_input(s2mpu09->irq_gpio);
244 gpio_free(s2mpu09->irq_gpio);
245
246 /* Mask individual interrupt sources */
247 for (i = 0; i < S2MPU09_IRQ_GROUP_NR; i++) {
248 struct i2c_client *i2c;
249
250 s2mpu09->irq_masks_cur[i] = 0xff;
251 s2mpu09->irq_masks_cache[i] = 0xff;
252
253 i2c = get_i2c(s2mpu09, i);
254
255 if (IS_ERR_OR_NULL(i2c))
256 continue;
257 if (s2mpu09_mask_reg[i] == S2MPU09_REG_INVALID)
258 continue;
259
260 s2mpu09_write_reg(i2c, s2mpu09_mask_reg[i], 0xff);
261 }
262
263 /* Register with genirq */
264 for (i = 0; i < S2MPU09_IRQ_NR; i++) {
265 cur_irq = i + s2mpu09->irq_base;
266 irq_set_chip_data(cur_irq, s2mpu09);
267 irq_set_chip_and_handler(cur_irq, &s2mpu09_irq_chip,
268 handle_level_irq);
269 irq_set_nested_thread(cur_irq, 1);
270 #ifdef CONFIG_ARM
271 set_irq_flags(cur_irq, IRQF_VALID);
272 #else
273 irq_set_noprobe(cur_irq);
274 #endif
275 }
276
277 s2mpu09_write_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_INTSRC_MASK, 0xff);
278 /* Unmask s2mpu09 interrupt */
279 ret = s2mpu09_read_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_INTSRC_MASK,
280 &i2c_data);
281 if (ret) {
282 pr_err("%s:%s fail to read intsrc mask reg\n",
283 MFD_DEV_NAME, __func__);
284 return ret;
285 }
286
287 i2c_data &= ~(S2MPU09_IRQSRC_PMIC); /* Unmask pmic interrupt */
288 s2mpu09_write_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_INTSRC_MASK,
289 i2c_data);
290
291 pr_info("%s:%s s2mpu09_PMIC_REG_INTSRC_MASK=0x%02x\n",
292 MFD_DEV_NAME, __func__, i2c_data);
293
294 ret = request_threaded_irq(s2mpu09->irq, NULL, s2mpu09_irq_thread,
295 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
296 "s2mpu09-irq", s2mpu09);
297
298 if (ret) {
299 dev_err(s2mpu09->dev, "Failed to request IRQ %d: %d\n",
300 s2mpu09->irq, ret);
301 return ret;
302 }
303
304 return 0;
305 }
306
307 void s2mpu09_irq_exit(struct s2mpu09_dev *s2mpu09)
308 {
309 if (s2mpu09->irq)
310 free_irq(s2mpu09->irq, s2mpu09);
311 }