]>
Commit | Line | Data |
---|---|---|
39d047c0 QZ |
1 | /* |
2 | * MFD core driver for Intel Broxton Whiskey Cove PMIC | |
3 | * | |
4 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/acpi.h> | |
18 | #include <linux/err.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/interrupt.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/mfd/core.h> | |
f1e34ad8 | 23 | #include <linux/mfd/intel_soc_pmic.h> |
0c227c51 | 24 | #include <linux/mfd/intel_soc_pmic_bxtwc.h> |
39d047c0 QZ |
25 | #include <asm/intel_pmc_ipc.h> |
26 | ||
27 | /* PMIC device registers */ | |
28 | #define REG_ADDR_MASK 0xFF00 | |
29 | #define REG_ADDR_SHIFT 8 | |
30 | #define REG_OFFSET_MASK 0xFF | |
31 | ||
32 | /* Interrupt Status Registers */ | |
33 | #define BXTWC_IRQLVL1 0x4E02 | |
34 | #define BXTWC_PWRBTNIRQ 0x4E03 | |
35 | ||
36 | #define BXTWC_THRM0IRQ 0x4E04 | |
37 | #define BXTWC_THRM1IRQ 0x4E05 | |
38 | #define BXTWC_THRM2IRQ 0x4E06 | |
39 | #define BXTWC_BCUIRQ 0x4E07 | |
40 | #define BXTWC_ADCIRQ 0x4E08 | |
41 | #define BXTWC_CHGR0IRQ 0x4E09 | |
42 | #define BXTWC_CHGR1IRQ 0x4E0A | |
43 | #define BXTWC_GPIOIRQ0 0x4E0B | |
44 | #define BXTWC_GPIOIRQ1 0x4E0C | |
45 | #define BXTWC_CRITIRQ 0x4E0D | |
957ae509 | 46 | #define BXTWC_TMUIRQ 0x4FB6 |
39d047c0 QZ |
47 | |
48 | /* Interrupt MASK Registers */ | |
49 | #define BXTWC_MIRQLVL1 0x4E0E | |
50 | #define BXTWC_MPWRTNIRQ 0x4E0F | |
51 | ||
9c6235c8 BG |
52 | #define BXTWC_MIRQLVL1_MCHGR BIT(5) |
53 | ||
39d047c0 QZ |
54 | #define BXTWC_MTHRM0IRQ 0x4E12 |
55 | #define BXTWC_MTHRM1IRQ 0x4E13 | |
56 | #define BXTWC_MTHRM2IRQ 0x4E14 | |
57 | #define BXTWC_MBCUIRQ 0x4E15 | |
58 | #define BXTWC_MADCIRQ 0x4E16 | |
59 | #define BXTWC_MCHGR0IRQ 0x4E17 | |
60 | #define BXTWC_MCHGR1IRQ 0x4E18 | |
61 | #define BXTWC_MGPIO0IRQ 0x4E19 | |
62 | #define BXTWC_MGPIO1IRQ 0x4E1A | |
63 | #define BXTWC_MCRITIRQ 0x4E1B | |
957ae509 | 64 | #define BXTWC_MTMUIRQ 0x4FB7 |
39d047c0 QZ |
65 | |
66 | /* Whiskey Cove PMIC share same ACPI ID between different platforms */ | |
67 | #define BROXTON_PMIC_WC_HRV 4 | |
68 | ||
69 | /* Manage in two IRQ chips since mask registers are not consecutive */ | |
70 | enum bxtwc_irqs { | |
71 | /* Level 1 */ | |
72 | BXTWC_PWRBTN_LVL1_IRQ = 0, | |
73 | BXTWC_TMU_LVL1_IRQ, | |
74 | BXTWC_THRM_LVL1_IRQ, | |
75 | BXTWC_BCU_LVL1_IRQ, | |
76 | BXTWC_ADC_LVL1_IRQ, | |
77 | BXTWC_CHGR_LVL1_IRQ, | |
78 | BXTWC_GPIO_LVL1_IRQ, | |
79 | BXTWC_CRIT_LVL1_IRQ, | |
80 | ||
81 | /* Level 2 */ | |
82 | BXTWC_PWRBTN_IRQ, | |
83 | }; | |
84 | ||
57129044 | 85 | enum bxtwc_irqs_bcu { |
c4949630 | 86 | BXTWC_BCU_IRQ = 0, |
57129044 KS |
87 | }; |
88 | ||
89 | enum bxtwc_irqs_adc { | |
90 | BXTWC_ADC_IRQ = 0, | |
91 | }; | |
92 | ||
93 | enum bxtwc_irqs_chgr { | |
94 | BXTWC_USBC_IRQ = 0, | |
39d047c0 QZ |
95 | BXTWC_CHGR0_IRQ, |
96 | BXTWC_CHGR1_IRQ, | |
4533d855 KS |
97 | }; |
98 | ||
99 | enum bxtwc_irqs_tmu { | |
100 | BXTWC_TMU_IRQ = 0, | |
39d047c0 QZ |
101 | }; |
102 | ||
57129044 KS |
103 | enum bxtwc_irqs_crit { |
104 | BXTWC_CRIT_IRQ = 0, | |
105 | }; | |
106 | ||
39d047c0 QZ |
107 | static const struct regmap_irq bxtwc_regmap_irqs[] = { |
108 | REGMAP_IRQ_REG(BXTWC_PWRBTN_LVL1_IRQ, 0, BIT(0)), | |
109 | REGMAP_IRQ_REG(BXTWC_TMU_LVL1_IRQ, 0, BIT(1)), | |
110 | REGMAP_IRQ_REG(BXTWC_THRM_LVL1_IRQ, 0, BIT(2)), | |
111 | REGMAP_IRQ_REG(BXTWC_BCU_LVL1_IRQ, 0, BIT(3)), | |
112 | REGMAP_IRQ_REG(BXTWC_ADC_LVL1_IRQ, 0, BIT(4)), | |
113 | REGMAP_IRQ_REG(BXTWC_CHGR_LVL1_IRQ, 0, BIT(5)), | |
114 | REGMAP_IRQ_REG(BXTWC_GPIO_LVL1_IRQ, 0, BIT(6)), | |
115 | REGMAP_IRQ_REG(BXTWC_CRIT_LVL1_IRQ, 0, BIT(7)), | |
116 | REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 1, 0x03), | |
117 | }; | |
118 | ||
57129044 | 119 | static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { |
c4949630 | 120 | REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), |
57129044 KS |
121 | }; |
122 | ||
123 | static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { | |
124 | REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff), | |
125 | }; | |
126 | ||
127 | static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { | |
128 | REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)), | |
129 | REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f), | |
130 | REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f), | |
39d047c0 QZ |
131 | }; |
132 | ||
957ae509 NB |
133 | static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { |
134 | REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), | |
135 | }; | |
136 | ||
57129044 KS |
137 | static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { |
138 | REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03), | |
139 | }; | |
140 | ||
39d047c0 QZ |
141 | static struct regmap_irq_chip bxtwc_regmap_irq_chip = { |
142 | .name = "bxtwc_irq_chip", | |
143 | .status_base = BXTWC_IRQLVL1, | |
144 | .mask_base = BXTWC_MIRQLVL1, | |
145 | .irqs = bxtwc_regmap_irqs, | |
146 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs), | |
147 | .num_regs = 2, | |
148 | }; | |
149 | ||
957ae509 NB |
150 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { |
151 | .name = "bxtwc_irq_chip_tmu", | |
152 | .status_base = BXTWC_TMUIRQ, | |
153 | .mask_base = BXTWC_MTMUIRQ, | |
154 | .irqs = bxtwc_regmap_irqs_tmu, | |
155 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu), | |
156 | .num_regs = 1, | |
157 | }; | |
158 | ||
57129044 KS |
159 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { |
160 | .name = "bxtwc_irq_chip_bcu", | |
161 | .status_base = BXTWC_BCUIRQ, | |
162 | .mask_base = BXTWC_MBCUIRQ, | |
163 | .irqs = bxtwc_regmap_irqs_bcu, | |
164 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu), | |
165 | .num_regs = 1, | |
166 | }; | |
167 | ||
168 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { | |
169 | .name = "bxtwc_irq_chip_adc", | |
170 | .status_base = BXTWC_ADCIRQ, | |
171 | .mask_base = BXTWC_MADCIRQ, | |
172 | .irqs = bxtwc_regmap_irqs_adc, | |
173 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc), | |
174 | .num_regs = 1, | |
175 | }; | |
176 | ||
177 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { | |
178 | .name = "bxtwc_irq_chip_chgr", | |
179 | .status_base = BXTWC_CHGR0IRQ, | |
180 | .mask_base = BXTWC_MCHGR0IRQ, | |
181 | .irqs = bxtwc_regmap_irqs_chgr, | |
182 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr), | |
183 | .num_regs = 2, | |
184 | }; | |
185 | ||
186 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { | |
187 | .name = "bxtwc_irq_chip_crit", | |
188 | .status_base = BXTWC_CRITIRQ, | |
189 | .mask_base = BXTWC_MCRITIRQ, | |
190 | .irqs = bxtwc_regmap_irqs_crit, | |
191 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit), | |
192 | .num_regs = 1, | |
193 | }; | |
194 | ||
39d047c0 | 195 | static struct resource gpio_resources[] = { |
a1d28c59 | 196 | DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), |
39d047c0 QZ |
197 | }; |
198 | ||
199 | static struct resource adc_resources[] = { | |
200 | DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"), | |
201 | }; | |
202 | ||
9c6235c8 | 203 | static struct resource usbc_resources[] = { |
96007020 | 204 | DEFINE_RES_IRQ(BXTWC_USBC_IRQ), |
9c6235c8 BG |
205 | }; |
206 | ||
39d047c0 QZ |
207 | static struct resource charger_resources[] = { |
208 | DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"), | |
209 | DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"), | |
210 | }; | |
211 | ||
212 | static struct resource thermal_resources[] = { | |
c4949630 | 213 | DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ), |
39d047c0 QZ |
214 | }; |
215 | ||
216 | static struct resource bcu_resources[] = { | |
217 | DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), | |
218 | }; | |
219 | ||
957ae509 NB |
220 | static struct resource tmu_resources[] = { |
221 | DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"), | |
222 | }; | |
223 | ||
39d047c0 QZ |
224 | static struct mfd_cell bxt_wc_dev[] = { |
225 | { | |
226 | .name = "bxt_wcove_gpadc", | |
227 | .num_resources = ARRAY_SIZE(adc_resources), | |
228 | .resources = adc_resources, | |
229 | }, | |
230 | { | |
231 | .name = "bxt_wcove_thermal", | |
232 | .num_resources = ARRAY_SIZE(thermal_resources), | |
233 | .resources = thermal_resources, | |
234 | }, | |
9c6235c8 BG |
235 | { |
236 | .name = "bxt_wcove_usbc", | |
237 | .num_resources = ARRAY_SIZE(usbc_resources), | |
238 | .resources = usbc_resources, | |
239 | }, | |
39d047c0 QZ |
240 | { |
241 | .name = "bxt_wcove_ext_charger", | |
242 | .num_resources = ARRAY_SIZE(charger_resources), | |
243 | .resources = charger_resources, | |
244 | }, | |
245 | { | |
246 | .name = "bxt_wcove_bcu", | |
247 | .num_resources = ARRAY_SIZE(bcu_resources), | |
248 | .resources = bcu_resources, | |
249 | }, | |
957ae509 NB |
250 | { |
251 | .name = "bxt_wcove_tmu", | |
252 | .num_resources = ARRAY_SIZE(tmu_resources), | |
253 | .resources = tmu_resources, | |
254 | }, | |
255 | ||
39d047c0 QZ |
256 | { |
257 | .name = "bxt_wcove_gpio", | |
258 | .num_resources = ARRAY_SIZE(gpio_resources), | |
259 | .resources = gpio_resources, | |
260 | }, | |
261 | { | |
262 | .name = "bxt_wcove_region", | |
263 | }, | |
264 | }; | |
265 | ||
266 | static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, | |
267 | unsigned int *val) | |
268 | { | |
269 | int ret; | |
270 | int i2c_addr; | |
271 | u8 ipc_in[2]; | |
272 | u8 ipc_out[4]; | |
273 | struct intel_soc_pmic *pmic = context; | |
274 | ||
b4ccc4d2 KS |
275 | if (!pmic) |
276 | return -EINVAL; | |
277 | ||
39d047c0 QZ |
278 | if (reg & REG_ADDR_MASK) |
279 | i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; | |
b4ccc4d2 | 280 | else |
39d047c0 | 281 | i2c_addr = BXTWC_DEVICE1_ADDR; |
b4ccc4d2 | 282 | |
39d047c0 QZ |
283 | reg &= REG_OFFSET_MASK; |
284 | ||
285 | ipc_in[0] = reg; | |
286 | ipc_in[1] = i2c_addr; | |
287 | ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS, | |
288 | PMC_IPC_PMIC_ACCESS_READ, | |
289 | ipc_in, sizeof(ipc_in), (u32 *)ipc_out, 1); | |
290 | if (ret) { | |
291 | dev_err(pmic->dev, "Failed to read from PMIC\n"); | |
292 | return ret; | |
293 | } | |
294 | *val = ipc_out[0]; | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
299 | static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, | |
300 | unsigned int val) | |
301 | { | |
302 | int ret; | |
303 | int i2c_addr; | |
304 | u8 ipc_in[3]; | |
305 | struct intel_soc_pmic *pmic = context; | |
306 | ||
b4ccc4d2 KS |
307 | if (!pmic) |
308 | return -EINVAL; | |
309 | ||
39d047c0 QZ |
310 | if (reg & REG_ADDR_MASK) |
311 | i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; | |
b4ccc4d2 | 312 | else |
39d047c0 | 313 | i2c_addr = BXTWC_DEVICE1_ADDR; |
b4ccc4d2 | 314 | |
39d047c0 QZ |
315 | reg &= REG_OFFSET_MASK; |
316 | ||
317 | ipc_in[0] = reg; | |
318 | ipc_in[1] = i2c_addr; | |
319 | ipc_in[2] = val; | |
320 | ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS, | |
321 | PMC_IPC_PMIC_ACCESS_WRITE, | |
322 | ipc_in, sizeof(ipc_in), NULL, 0); | |
323 | if (ret) { | |
324 | dev_err(pmic->dev, "Failed to write to PMIC\n"); | |
325 | return ret; | |
326 | } | |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
331 | /* sysfs interfaces to r/w PMIC registers, required by initial script */ | |
332 | static unsigned long bxtwc_reg_addr; | |
333 | static ssize_t bxtwc_reg_show(struct device *dev, | |
334 | struct device_attribute *attr, char *buf) | |
335 | { | |
336 | return sprintf(buf, "0x%lx\n", bxtwc_reg_addr); | |
337 | } | |
338 | ||
339 | static ssize_t bxtwc_reg_store(struct device *dev, | |
340 | struct device_attribute *attr, const char *buf, size_t count) | |
341 | { | |
342 | if (kstrtoul(buf, 0, &bxtwc_reg_addr)) { | |
343 | dev_err(dev, "Invalid register address\n"); | |
344 | return -EINVAL; | |
345 | } | |
346 | return (ssize_t)count; | |
347 | } | |
348 | ||
349 | static ssize_t bxtwc_val_show(struct device *dev, | |
350 | struct device_attribute *attr, char *buf) | |
351 | { | |
352 | int ret; | |
353 | unsigned int val; | |
354 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
355 | ||
356 | ret = regmap_read(pmic->regmap, bxtwc_reg_addr, &val); | |
357 | if (ret < 0) { | |
358 | dev_err(dev, "Failed to read 0x%lx\n", bxtwc_reg_addr); | |
359 | return -EIO; | |
360 | } | |
361 | ||
362 | return sprintf(buf, "0x%02x\n", val); | |
363 | } | |
364 | ||
365 | static ssize_t bxtwc_val_store(struct device *dev, | |
366 | struct device_attribute *attr, const char *buf, size_t count) | |
367 | { | |
368 | int ret; | |
369 | unsigned int val; | |
370 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
371 | ||
f3a654c5 DC |
372 | ret = kstrtouint(buf, 0, &val); |
373 | if (ret) | |
374 | return ret; | |
39d047c0 QZ |
375 | |
376 | ret = regmap_write(pmic->regmap, bxtwc_reg_addr, val); | |
377 | if (ret) { | |
378 | dev_err(dev, "Failed to write value 0x%02x to address 0x%lx", | |
379 | val, bxtwc_reg_addr); | |
380 | return -EIO; | |
381 | } | |
382 | return count; | |
383 | } | |
384 | ||
385 | static DEVICE_ATTR(addr, S_IWUSR | S_IRUSR, bxtwc_reg_show, bxtwc_reg_store); | |
386 | static DEVICE_ATTR(val, S_IWUSR | S_IRUSR, bxtwc_val_show, bxtwc_val_store); | |
387 | static struct attribute *bxtwc_attrs[] = { | |
388 | &dev_attr_addr.attr, | |
389 | &dev_attr_val.attr, | |
390 | NULL | |
391 | }; | |
392 | ||
393 | static const struct attribute_group bxtwc_group = { | |
394 | .attrs = bxtwc_attrs, | |
395 | }; | |
396 | ||
397 | static const struct regmap_config bxtwc_regmap_config = { | |
398 | .reg_bits = 16, | |
399 | .val_bits = 8, | |
400 | .reg_write = regmap_ipc_byte_reg_write, | |
401 | .reg_read = regmap_ipc_byte_reg_read, | |
402 | }; | |
403 | ||
57129044 KS |
404 | static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, |
405 | struct regmap_irq_chip_data *pdata, | |
406 | int pirq, int irq_flags, | |
407 | const struct regmap_irq_chip *chip, | |
408 | struct regmap_irq_chip_data **data) | |
409 | { | |
410 | int irq; | |
411 | ||
412 | irq = regmap_irq_get_virq(pdata, pirq); | |
413 | if (irq < 0) { | |
414 | dev_err(pmic->dev, | |
415 | "Failed to get parent vIRQ(%d) for chip %s, ret:%d\n", | |
416 | pirq, chip->name, irq); | |
417 | return irq; | |
418 | } | |
419 | ||
420 | return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, | |
421 | 0, chip, data); | |
422 | } | |
423 | ||
39d047c0 QZ |
424 | static int bxtwc_probe(struct platform_device *pdev) |
425 | { | |
426 | int ret; | |
427 | acpi_handle handle; | |
428 | acpi_status status; | |
429 | unsigned long long hrv; | |
430 | struct intel_soc_pmic *pmic; | |
431 | ||
432 | handle = ACPI_HANDLE(&pdev->dev); | |
433 | status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); | |
434 | if (ACPI_FAILURE(status)) { | |
435 | dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n"); | |
436 | return -ENODEV; | |
437 | } | |
438 | if (hrv != BROXTON_PMIC_WC_HRV) { | |
439 | dev_err(&pdev->dev, "Invalid PMIC hardware revision: %llu\n", | |
440 | hrv); | |
441 | return -ENODEV; | |
442 | } | |
443 | ||
444 | pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); | |
445 | if (!pmic) | |
446 | return -ENOMEM; | |
447 | ||
448 | ret = platform_get_irq(pdev, 0); | |
449 | if (ret < 0) { | |
450 | dev_err(&pdev->dev, "Invalid IRQ\n"); | |
451 | return ret; | |
452 | } | |
453 | pmic->irq = ret; | |
454 | ||
455 | dev_set_drvdata(&pdev->dev, pmic); | |
456 | pmic->dev = &pdev->dev; | |
457 | ||
458 | pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic, | |
459 | &bxtwc_regmap_config); | |
460 | if (IS_ERR(pmic->regmap)) { | |
461 | ret = PTR_ERR(pmic->regmap); | |
462 | dev_err(&pdev->dev, "Failed to initialise regmap: %d\n", ret); | |
463 | return ret; | |
464 | } | |
465 | ||
5131f072 KS |
466 | ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, |
467 | IRQF_ONESHOT | IRQF_SHARED, | |
468 | 0, &bxtwc_regmap_irq_chip, | |
469 | &pmic->irq_chip_data); | |
39d047c0 QZ |
470 | if (ret) { |
471 | dev_err(&pdev->dev, "Failed to add IRQ chip\n"); | |
472 | return ret; | |
473 | } | |
474 | ||
57129044 KS |
475 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, |
476 | BXTWC_TMU_LVL1_IRQ, | |
477 | IRQF_ONESHOT, | |
478 | &bxtwc_regmap_irq_chip_tmu, | |
479 | &pmic->irq_chip_data_tmu); | |
39d047c0 | 480 | if (ret) { |
57129044 | 481 | dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); |
5131f072 | 482 | return ret; |
39d047c0 QZ |
483 | } |
484 | ||
57129044 KS |
485 | /* Add chained IRQ handler for BCU IRQs */ |
486 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
487 | BXTWC_BCU_LVL1_IRQ, | |
488 | IRQF_ONESHOT, | |
489 | &bxtwc_regmap_irq_chip_bcu, | |
490 | &pmic->irq_chip_data_bcu); | |
491 | ||
492 | ||
957ae509 | 493 | if (ret) { |
57129044 KS |
494 | dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n"); |
495 | return ret; | |
496 | } | |
497 | ||
498 | /* Add chained IRQ handler for ADC IRQs */ | |
499 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
500 | BXTWC_ADC_LVL1_IRQ, | |
501 | IRQF_ONESHOT, | |
502 | &bxtwc_regmap_irq_chip_adc, | |
503 | &pmic->irq_chip_data_adc); | |
504 | ||
505 | ||
506 | if (ret) { | |
507 | dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n"); | |
508 | return ret; | |
509 | } | |
510 | ||
511 | /* Add chained IRQ handler for CHGR IRQs */ | |
512 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
513 | BXTWC_CHGR_LVL1_IRQ, | |
514 | IRQF_ONESHOT, | |
515 | &bxtwc_regmap_irq_chip_chgr, | |
516 | &pmic->irq_chip_data_chgr); | |
517 | ||
518 | ||
519 | if (ret) { | |
520 | dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n"); | |
521 | return ret; | |
522 | } | |
523 | ||
524 | /* Add chained IRQ handler for CRIT IRQs */ | |
525 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
526 | BXTWC_CRIT_LVL1_IRQ, | |
527 | IRQF_ONESHOT, | |
528 | &bxtwc_regmap_irq_chip_crit, | |
529 | &pmic->irq_chip_data_crit); | |
530 | ||
531 | ||
532 | if (ret) { | |
533 | dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n"); | |
5131f072 | 534 | return ret; |
957ae509 NB |
535 | } |
536 | ||
5131f072 KS |
537 | ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, |
538 | ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); | |
39d047c0 QZ |
539 | if (ret) { |
540 | dev_err(&pdev->dev, "Failed to add devices\n"); | |
5131f072 | 541 | return ret; |
39d047c0 QZ |
542 | } |
543 | ||
544 | ret = sysfs_create_group(&pdev->dev.kobj, &bxtwc_group); | |
545 | if (ret) { | |
546 | dev_err(&pdev->dev, "Failed to create sysfs group %d\n", ret); | |
5131f072 | 547 | return ret; |
39d047c0 QZ |
548 | } |
549 | ||
9c6235c8 BG |
550 | /* |
551 | * There is known hw bug. Upon reset BIT 5 of register | |
552 | * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However, | |
553 | * later it's set to 1(masked) automatically by hardware. So we | |
554 | * have the software workaround here to unmaksed it in order to let | |
555 | * charger interrutp work. | |
556 | */ | |
557 | regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, | |
558 | BXTWC_MIRQLVL1_MCHGR, 0); | |
559 | ||
39d047c0 | 560 | return 0; |
39d047c0 QZ |
561 | } |
562 | ||
563 | static int bxtwc_remove(struct platform_device *pdev) | |
564 | { | |
39d047c0 | 565 | sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group); |
39d047c0 QZ |
566 | |
567 | return 0; | |
568 | } | |
569 | ||
570 | static void bxtwc_shutdown(struct platform_device *pdev) | |
571 | { | |
572 | struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev); | |
573 | ||
574 | disable_irq(pmic->irq); | |
575 | } | |
576 | ||
577 | #ifdef CONFIG_PM_SLEEP | |
578 | static int bxtwc_suspend(struct device *dev) | |
579 | { | |
580 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
581 | ||
582 | disable_irq(pmic->irq); | |
583 | ||
584 | return 0; | |
585 | } | |
586 | ||
587 | static int bxtwc_resume(struct device *dev) | |
588 | { | |
589 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
590 | ||
591 | enable_irq(pmic->irq); | |
592 | return 0; | |
593 | } | |
594 | #endif | |
595 | static SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); | |
596 | ||
597 | static const struct acpi_device_id bxtwc_acpi_ids[] = { | |
598 | { "INT34D3", }, | |
599 | { } | |
600 | }; | |
f57576e7 | 601 | MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); |
39d047c0 QZ |
602 | |
603 | static struct platform_driver bxtwc_driver = { | |
604 | .probe = bxtwc_probe, | |
605 | .remove = bxtwc_remove, | |
606 | .shutdown = bxtwc_shutdown, | |
607 | .driver = { | |
608 | .name = "BXTWC PMIC", | |
609 | .pm = &bxtwc_pm_ops, | |
610 | .acpi_match_table = ACPI_PTR(bxtwc_acpi_ids), | |
611 | }, | |
612 | }; | |
613 | ||
614 | module_platform_driver(bxtwc_driver); | |
615 | ||
616 | MODULE_LICENSE("GPL v2"); | |
617 | MODULE_AUTHOR("Qipeng Zha<qipeng.zha@intel.com>"); |