]>
Commit | Line | Data |
---|---|---|
26c7e05a | 1 | // SPDX-License-Identifier: GPL-2.0 |
39d047c0 QZ |
2 | /* |
3 | * MFD core driver for Intel Broxton Whiskey Cove PMIC | |
4 | * | |
5 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | |
39d047c0 QZ |
6 | */ |
7 | ||
39d047c0 | 8 | #include <linux/acpi.h> |
39d047c0 | 9 | #include <linux/delay.h> |
51eeee8e | 10 | #include <linux/err.h> |
39d047c0 QZ |
11 | #include <linux/interrupt.h> |
12 | #include <linux/kernel.h> | |
13 | #include <linux/mfd/core.h> | |
f1e34ad8 | 14 | #include <linux/mfd/intel_soc_pmic.h> |
0c227c51 | 15 | #include <linux/mfd/intel_soc_pmic_bxtwc.h> |
51eeee8e AS |
16 | #include <linux/module.h> |
17 | ||
4181bc8f | 18 | #include <asm/intel_scu_ipc.h> |
39d047c0 QZ |
19 | |
20 | /* PMIC device registers */ | |
21 | #define REG_ADDR_MASK 0xFF00 | |
22 | #define REG_ADDR_SHIFT 8 | |
23 | #define REG_OFFSET_MASK 0xFF | |
24 | ||
25 | /* Interrupt Status Registers */ | |
26 | #define BXTWC_IRQLVL1 0x4E02 | |
39d047c0 | 27 | |
9f8ddee1 | 28 | #define BXTWC_PWRBTNIRQ 0x4E03 |
39d047c0 QZ |
29 | #define BXTWC_THRM0IRQ 0x4E04 |
30 | #define BXTWC_THRM1IRQ 0x4E05 | |
31 | #define BXTWC_THRM2IRQ 0x4E06 | |
32 | #define BXTWC_BCUIRQ 0x4E07 | |
33 | #define BXTWC_ADCIRQ 0x4E08 | |
34 | #define BXTWC_CHGR0IRQ 0x4E09 | |
35 | #define BXTWC_CHGR1IRQ 0x4E0A | |
36 | #define BXTWC_GPIOIRQ0 0x4E0B | |
37 | #define BXTWC_GPIOIRQ1 0x4E0C | |
38 | #define BXTWC_CRITIRQ 0x4E0D | |
957ae509 | 39 | #define BXTWC_TMUIRQ 0x4FB6 |
39d047c0 QZ |
40 | |
41 | /* Interrupt MASK Registers */ | |
42 | #define BXTWC_MIRQLVL1 0x4E0E | |
9c6235c8 BG |
43 | #define BXTWC_MIRQLVL1_MCHGR BIT(5) |
44 | ||
9f8ddee1 | 45 | #define BXTWC_MPWRBTNIRQ 0x4E0F |
39d047c0 QZ |
46 | #define BXTWC_MTHRM0IRQ 0x4E12 |
47 | #define BXTWC_MTHRM1IRQ 0x4E13 | |
48 | #define BXTWC_MTHRM2IRQ 0x4E14 | |
49 | #define BXTWC_MBCUIRQ 0x4E15 | |
50 | #define BXTWC_MADCIRQ 0x4E16 | |
51 | #define BXTWC_MCHGR0IRQ 0x4E17 | |
52 | #define BXTWC_MCHGR1IRQ 0x4E18 | |
53 | #define BXTWC_MGPIO0IRQ 0x4E19 | |
54 | #define BXTWC_MGPIO1IRQ 0x4E1A | |
55 | #define BXTWC_MCRITIRQ 0x4E1B | |
957ae509 | 56 | #define BXTWC_MTMUIRQ 0x4FB7 |
39d047c0 QZ |
57 | |
58 | /* Whiskey Cove PMIC share same ACPI ID between different platforms */ | |
59 | #define BROXTON_PMIC_WC_HRV 4 | |
60 | ||
4181bc8f MW |
61 | #define PMC_PMIC_ACCESS 0xFF |
62 | #define PMC_PMIC_READ 0x0 | |
63 | #define PMC_PMIC_WRITE 0x1 | |
64 | ||
39d047c0 | 65 | enum bxtwc_irqs { |
39d047c0 QZ |
66 | BXTWC_PWRBTN_LVL1_IRQ = 0, |
67 | BXTWC_TMU_LVL1_IRQ, | |
68 | BXTWC_THRM_LVL1_IRQ, | |
69 | BXTWC_BCU_LVL1_IRQ, | |
70 | BXTWC_ADC_LVL1_IRQ, | |
71 | BXTWC_CHGR_LVL1_IRQ, | |
72 | BXTWC_GPIO_LVL1_IRQ, | |
73 | BXTWC_CRIT_LVL1_IRQ, | |
9f8ddee1 | 74 | }; |
39d047c0 | 75 | |
9f8ddee1 AS |
76 | enum bxtwc_irqs_pwrbtn { |
77 | BXTWC_PWRBTN_IRQ = 0, | |
78 | BXTWC_UIBTN_IRQ, | |
39d047c0 QZ |
79 | }; |
80 | ||
57129044 | 81 | enum bxtwc_irqs_bcu { |
c4949630 | 82 | BXTWC_BCU_IRQ = 0, |
57129044 KS |
83 | }; |
84 | ||
85 | enum bxtwc_irqs_adc { | |
86 | BXTWC_ADC_IRQ = 0, | |
87 | }; | |
88 | ||
89 | enum bxtwc_irqs_chgr { | |
90 | BXTWC_USBC_IRQ = 0, | |
39d047c0 QZ |
91 | BXTWC_CHGR0_IRQ, |
92 | BXTWC_CHGR1_IRQ, | |
4533d855 KS |
93 | }; |
94 | ||
95 | enum bxtwc_irqs_tmu { | |
96 | BXTWC_TMU_IRQ = 0, | |
39d047c0 QZ |
97 | }; |
98 | ||
57129044 KS |
99 | enum bxtwc_irqs_crit { |
100 | BXTWC_CRIT_IRQ = 0, | |
101 | }; | |
102 | ||
39d047c0 QZ |
103 | static const struct regmap_irq bxtwc_regmap_irqs[] = { |
104 | REGMAP_IRQ_REG(BXTWC_PWRBTN_LVL1_IRQ, 0, BIT(0)), | |
105 | REGMAP_IRQ_REG(BXTWC_TMU_LVL1_IRQ, 0, BIT(1)), | |
106 | REGMAP_IRQ_REG(BXTWC_THRM_LVL1_IRQ, 0, BIT(2)), | |
107 | REGMAP_IRQ_REG(BXTWC_BCU_LVL1_IRQ, 0, BIT(3)), | |
108 | REGMAP_IRQ_REG(BXTWC_ADC_LVL1_IRQ, 0, BIT(4)), | |
109 | REGMAP_IRQ_REG(BXTWC_CHGR_LVL1_IRQ, 0, BIT(5)), | |
110 | REGMAP_IRQ_REG(BXTWC_GPIO_LVL1_IRQ, 0, BIT(6)), | |
111 | REGMAP_IRQ_REG(BXTWC_CRIT_LVL1_IRQ, 0, BIT(7)), | |
9f8ddee1 AS |
112 | }; |
113 | ||
114 | static const struct regmap_irq bxtwc_regmap_irqs_pwrbtn[] = { | |
115 | REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, 0x01), | |
39d047c0 QZ |
116 | }; |
117 | ||
57129044 | 118 | static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { |
c4949630 | 119 | REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), |
57129044 KS |
120 | }; |
121 | ||
122 | static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { | |
123 | REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff), | |
124 | }; | |
125 | ||
126 | static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { | |
9f8ddee1 | 127 | REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, 0x20), |
57129044 KS |
128 | REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f), |
129 | REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f), | |
39d047c0 QZ |
130 | }; |
131 | ||
957ae509 NB |
132 | static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { |
133 | REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), | |
134 | }; | |
135 | ||
57129044 KS |
136 | static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { |
137 | REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03), | |
138 | }; | |
139 | ||
39d047c0 QZ |
140 | static struct regmap_irq_chip bxtwc_regmap_irq_chip = { |
141 | .name = "bxtwc_irq_chip", | |
142 | .status_base = BXTWC_IRQLVL1, | |
143 | .mask_base = BXTWC_MIRQLVL1, | |
144 | .irqs = bxtwc_regmap_irqs, | |
145 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs), | |
9f8ddee1 AS |
146 | .num_regs = 1, |
147 | }; | |
148 | ||
149 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { | |
150 | .name = "bxtwc_irq_chip_pwrbtn", | |
151 | .status_base = BXTWC_PWRBTNIRQ, | |
152 | .mask_base = BXTWC_MPWRBTNIRQ, | |
153 | .irqs = bxtwc_regmap_irqs_pwrbtn, | |
154 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_pwrbtn), | |
155 | .num_regs = 1, | |
39d047c0 QZ |
156 | }; |
157 | ||
957ae509 NB |
158 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { |
159 | .name = "bxtwc_irq_chip_tmu", | |
160 | .status_base = BXTWC_TMUIRQ, | |
161 | .mask_base = BXTWC_MTMUIRQ, | |
162 | .irqs = bxtwc_regmap_irqs_tmu, | |
163 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu), | |
164 | .num_regs = 1, | |
165 | }; | |
166 | ||
57129044 KS |
167 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { |
168 | .name = "bxtwc_irq_chip_bcu", | |
169 | .status_base = BXTWC_BCUIRQ, | |
170 | .mask_base = BXTWC_MBCUIRQ, | |
171 | .irqs = bxtwc_regmap_irqs_bcu, | |
172 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu), | |
173 | .num_regs = 1, | |
174 | }; | |
175 | ||
176 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { | |
177 | .name = "bxtwc_irq_chip_adc", | |
178 | .status_base = BXTWC_ADCIRQ, | |
179 | .mask_base = BXTWC_MADCIRQ, | |
180 | .irqs = bxtwc_regmap_irqs_adc, | |
181 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc), | |
182 | .num_regs = 1, | |
183 | }; | |
184 | ||
185 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { | |
186 | .name = "bxtwc_irq_chip_chgr", | |
187 | .status_base = BXTWC_CHGR0IRQ, | |
188 | .mask_base = BXTWC_MCHGR0IRQ, | |
189 | .irqs = bxtwc_regmap_irqs_chgr, | |
190 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr), | |
191 | .num_regs = 2, | |
192 | }; | |
193 | ||
194 | static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { | |
195 | .name = "bxtwc_irq_chip_crit", | |
196 | .status_base = BXTWC_CRITIRQ, | |
197 | .mask_base = BXTWC_MCRITIRQ, | |
198 | .irqs = bxtwc_regmap_irqs_crit, | |
199 | .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit), | |
200 | .num_regs = 1, | |
201 | }; | |
202 | ||
bf4cceb6 | 203 | static const struct resource gpio_resources[] = { |
a1d28c59 | 204 | DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), |
39d047c0 QZ |
205 | }; |
206 | ||
bf4cceb6 | 207 | static const struct resource adc_resources[] = { |
39d047c0 QZ |
208 | DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"), |
209 | }; | |
210 | ||
bf4cceb6 | 211 | static const struct resource usbc_resources[] = { |
96007020 | 212 | DEFINE_RES_IRQ(BXTWC_USBC_IRQ), |
9c6235c8 BG |
213 | }; |
214 | ||
bf4cceb6 | 215 | static const struct resource charger_resources[] = { |
39d047c0 QZ |
216 | DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"), |
217 | DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"), | |
218 | }; | |
219 | ||
bf4cceb6 | 220 | static const struct resource thermal_resources[] = { |
c4949630 | 221 | DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ), |
39d047c0 QZ |
222 | }; |
223 | ||
bf4cceb6 | 224 | static const struct resource bcu_resources[] = { |
39d047c0 QZ |
225 | DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), |
226 | }; | |
227 | ||
bf4cceb6 | 228 | static const struct resource tmu_resources[] = { |
957ae509 NB |
229 | DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"), |
230 | }; | |
231 | ||
39d047c0 QZ |
232 | static struct mfd_cell bxt_wc_dev[] = { |
233 | { | |
234 | .name = "bxt_wcove_gpadc", | |
235 | .num_resources = ARRAY_SIZE(adc_resources), | |
236 | .resources = adc_resources, | |
237 | }, | |
238 | { | |
239 | .name = "bxt_wcove_thermal", | |
240 | .num_resources = ARRAY_SIZE(thermal_resources), | |
241 | .resources = thermal_resources, | |
242 | }, | |
9c6235c8 BG |
243 | { |
244 | .name = "bxt_wcove_usbc", | |
245 | .num_resources = ARRAY_SIZE(usbc_resources), | |
246 | .resources = usbc_resources, | |
247 | }, | |
39d047c0 QZ |
248 | { |
249 | .name = "bxt_wcove_ext_charger", | |
250 | .num_resources = ARRAY_SIZE(charger_resources), | |
251 | .resources = charger_resources, | |
252 | }, | |
253 | { | |
254 | .name = "bxt_wcove_bcu", | |
255 | .num_resources = ARRAY_SIZE(bcu_resources), | |
256 | .resources = bcu_resources, | |
257 | }, | |
957ae509 NB |
258 | { |
259 | .name = "bxt_wcove_tmu", | |
260 | .num_resources = ARRAY_SIZE(tmu_resources), | |
261 | .resources = tmu_resources, | |
262 | }, | |
263 | ||
39d047c0 QZ |
264 | { |
265 | .name = "bxt_wcove_gpio", | |
266 | .num_resources = ARRAY_SIZE(gpio_resources), | |
267 | .resources = gpio_resources, | |
268 | }, | |
269 | { | |
270 | .name = "bxt_wcove_region", | |
271 | }, | |
272 | }; | |
273 | ||
274 | static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, | |
275 | unsigned int *val) | |
276 | { | |
277 | int ret; | |
278 | int i2c_addr; | |
279 | u8 ipc_in[2]; | |
280 | u8 ipc_out[4]; | |
281 | struct intel_soc_pmic *pmic = context; | |
282 | ||
b4ccc4d2 KS |
283 | if (!pmic) |
284 | return -EINVAL; | |
285 | ||
39d047c0 QZ |
286 | if (reg & REG_ADDR_MASK) |
287 | i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; | |
b4ccc4d2 | 288 | else |
39d047c0 | 289 | i2c_addr = BXTWC_DEVICE1_ADDR; |
b4ccc4d2 | 290 | |
39d047c0 QZ |
291 | reg &= REG_OFFSET_MASK; |
292 | ||
293 | ipc_in[0] = reg; | |
294 | ipc_in[1] = i2c_addr; | |
4181bc8f MW |
295 | ret = intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, |
296 | PMC_PMIC_READ, ipc_in, sizeof(ipc_in), | |
297 | ipc_out, sizeof(ipc_out)); | |
298 | if (ret) | |
39d047c0 | 299 | return ret; |
4181bc8f | 300 | |
39d047c0 QZ |
301 | *val = ipc_out[0]; |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, | |
307 | unsigned int val) | |
308 | { | |
39d047c0 QZ |
309 | int i2c_addr; |
310 | u8 ipc_in[3]; | |
311 | struct intel_soc_pmic *pmic = context; | |
312 | ||
b4ccc4d2 KS |
313 | if (!pmic) |
314 | return -EINVAL; | |
315 | ||
39d047c0 QZ |
316 | if (reg & REG_ADDR_MASK) |
317 | i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; | |
b4ccc4d2 | 318 | else |
39d047c0 | 319 | i2c_addr = BXTWC_DEVICE1_ADDR; |
b4ccc4d2 | 320 | |
39d047c0 QZ |
321 | reg &= REG_OFFSET_MASK; |
322 | ||
323 | ipc_in[0] = reg; | |
324 | ipc_in[1] = i2c_addr; | |
325 | ipc_in[2] = val; | |
4181bc8f MW |
326 | return intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, |
327 | PMC_PMIC_WRITE, ipc_in, sizeof(ipc_in), | |
328 | NULL, 0); | |
39d047c0 QZ |
329 | } |
330 | ||
331 | /* sysfs interfaces to r/w PMIC registers, required by initial script */ | |
332 | static unsigned long bxtwc_reg_addr; | |
5089e34f ZL |
333 | static ssize_t addr_show(struct device *dev, |
334 | struct device_attribute *attr, char *buf) | |
39d047c0 QZ |
335 | { |
336 | return sprintf(buf, "0x%lx\n", bxtwc_reg_addr); | |
337 | } | |
338 | ||
5089e34f ZL |
339 | static ssize_t addr_store(struct device *dev, |
340 | struct device_attribute *attr, const char *buf, size_t count) | |
39d047c0 QZ |
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 | ||
5089e34f ZL |
349 | static ssize_t val_show(struct device *dev, |
350 | struct device_attribute *attr, char *buf) | |
39d047c0 QZ |
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 | ||
5089e34f ZL |
365 | static ssize_t val_store(struct device *dev, |
366 | struct device_attribute *attr, const char *buf, size_t count) | |
39d047c0 QZ |
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 | ||
5089e34f ZL |
385 | static DEVICE_ATTR_ADMIN_RW(addr); |
386 | static DEVICE_ATTR_ADMIN_RW(val); | |
39d047c0 QZ |
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); | |
802d9bd4 | 449 | if (ret < 0) |
39d047c0 | 450 | return ret; |
39d047c0 QZ |
451 | pmic->irq = ret; |
452 | ||
453 | dev_set_drvdata(&pdev->dev, pmic); | |
454 | pmic->dev = &pdev->dev; | |
455 | ||
4181bc8f MW |
456 | pmic->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); |
457 | if (!pmic->scu) | |
458 | return -EPROBE_DEFER; | |
459 | ||
39d047c0 QZ |
460 | pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic, |
461 | &bxtwc_regmap_config); | |
462 | if (IS_ERR(pmic->regmap)) { | |
463 | ret = PTR_ERR(pmic->regmap); | |
464 | dev_err(&pdev->dev, "Failed to initialise regmap: %d\n", ret); | |
465 | return ret; | |
466 | } | |
467 | ||
5131f072 KS |
468 | ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, |
469 | IRQF_ONESHOT | IRQF_SHARED, | |
470 | 0, &bxtwc_regmap_irq_chip, | |
471 | &pmic->irq_chip_data); | |
39d047c0 QZ |
472 | if (ret) { |
473 | dev_err(&pdev->dev, "Failed to add IRQ chip\n"); | |
474 | return ret; | |
475 | } | |
476 | ||
9f8ddee1 AS |
477 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, |
478 | BXTWC_PWRBTN_LVL1_IRQ, | |
479 | IRQF_ONESHOT, | |
480 | &bxtwc_regmap_irq_chip_pwrbtn, | |
481 | &pmic->irq_chip_data_pwrbtn); | |
482 | if (ret) { | |
483 | dev_err(&pdev->dev, "Failed to add PWRBTN IRQ chip\n"); | |
484 | return ret; | |
485 | } | |
486 | ||
57129044 KS |
487 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, |
488 | BXTWC_TMU_LVL1_IRQ, | |
489 | IRQF_ONESHOT, | |
490 | &bxtwc_regmap_irq_chip_tmu, | |
491 | &pmic->irq_chip_data_tmu); | |
39d047c0 | 492 | if (ret) { |
57129044 | 493 | dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); |
5131f072 | 494 | return ret; |
39d047c0 QZ |
495 | } |
496 | ||
57129044 KS |
497 | /* Add chained IRQ handler for BCU IRQs */ |
498 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
499 | BXTWC_BCU_LVL1_IRQ, | |
500 | IRQF_ONESHOT, | |
501 | &bxtwc_regmap_irq_chip_bcu, | |
502 | &pmic->irq_chip_data_bcu); | |
503 | ||
504 | ||
957ae509 | 505 | if (ret) { |
57129044 KS |
506 | dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n"); |
507 | return ret; | |
508 | } | |
509 | ||
510 | /* Add chained IRQ handler for ADC IRQs */ | |
511 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
512 | BXTWC_ADC_LVL1_IRQ, | |
513 | IRQF_ONESHOT, | |
514 | &bxtwc_regmap_irq_chip_adc, | |
515 | &pmic->irq_chip_data_adc); | |
516 | ||
517 | ||
518 | if (ret) { | |
519 | dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n"); | |
520 | return ret; | |
521 | } | |
522 | ||
523 | /* Add chained IRQ handler for CHGR IRQs */ | |
524 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
525 | BXTWC_CHGR_LVL1_IRQ, | |
526 | IRQF_ONESHOT, | |
527 | &bxtwc_regmap_irq_chip_chgr, | |
528 | &pmic->irq_chip_data_chgr); | |
529 | ||
530 | ||
531 | if (ret) { | |
532 | dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n"); | |
533 | return ret; | |
534 | } | |
535 | ||
536 | /* Add chained IRQ handler for CRIT IRQs */ | |
537 | ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, | |
538 | BXTWC_CRIT_LVL1_IRQ, | |
539 | IRQF_ONESHOT, | |
540 | &bxtwc_regmap_irq_chip_crit, | |
541 | &pmic->irq_chip_data_crit); | |
542 | ||
543 | ||
544 | if (ret) { | |
545 | dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n"); | |
5131f072 | 546 | return ret; |
957ae509 NB |
547 | } |
548 | ||
5131f072 KS |
549 | ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, |
550 | ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); | |
39d047c0 QZ |
551 | if (ret) { |
552 | dev_err(&pdev->dev, "Failed to add devices\n"); | |
5131f072 | 553 | return ret; |
39d047c0 QZ |
554 | } |
555 | ||
556 | ret = sysfs_create_group(&pdev->dev.kobj, &bxtwc_group); | |
557 | if (ret) { | |
558 | dev_err(&pdev->dev, "Failed to create sysfs group %d\n", ret); | |
5131f072 | 559 | return ret; |
39d047c0 QZ |
560 | } |
561 | ||
9c6235c8 BG |
562 | /* |
563 | * There is known hw bug. Upon reset BIT 5 of register | |
564 | * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However, | |
565 | * later it's set to 1(masked) automatically by hardware. So we | |
566 | * have the software workaround here to unmaksed it in order to let | |
567 | * charger interrutp work. | |
568 | */ | |
569 | regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, | |
570 | BXTWC_MIRQLVL1_MCHGR, 0); | |
571 | ||
39d047c0 | 572 | return 0; |
39d047c0 QZ |
573 | } |
574 | ||
575 | static int bxtwc_remove(struct platform_device *pdev) | |
576 | { | |
39d047c0 | 577 | sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group); |
39d047c0 QZ |
578 | |
579 | return 0; | |
580 | } | |
581 | ||
582 | static void bxtwc_shutdown(struct platform_device *pdev) | |
583 | { | |
584 | struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev); | |
585 | ||
586 | disable_irq(pmic->irq); | |
587 | } | |
588 | ||
589 | #ifdef CONFIG_PM_SLEEP | |
590 | static int bxtwc_suspend(struct device *dev) | |
591 | { | |
592 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
593 | ||
594 | disable_irq(pmic->irq); | |
595 | ||
596 | return 0; | |
597 | } | |
598 | ||
599 | static int bxtwc_resume(struct device *dev) | |
600 | { | |
601 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
602 | ||
603 | enable_irq(pmic->irq); | |
604 | return 0; | |
605 | } | |
606 | #endif | |
607 | static SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); | |
608 | ||
609 | static const struct acpi_device_id bxtwc_acpi_ids[] = { | |
610 | { "INT34D3", }, | |
611 | { } | |
612 | }; | |
f57576e7 | 613 | MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); |
39d047c0 QZ |
614 | |
615 | static struct platform_driver bxtwc_driver = { | |
616 | .probe = bxtwc_probe, | |
617 | .remove = bxtwc_remove, | |
618 | .shutdown = bxtwc_shutdown, | |
619 | .driver = { | |
620 | .name = "BXTWC PMIC", | |
621 | .pm = &bxtwc_pm_ops, | |
622 | .acpi_match_table = ACPI_PTR(bxtwc_acpi_ids), | |
623 | }, | |
624 | }; | |
625 | ||
626 | module_platform_driver(bxtwc_driver); | |
627 | ||
628 | MODULE_LICENSE("GPL v2"); | |
629 | MODULE_AUTHOR("Qipeng Zha<qipeng.zha@intel.com>"); |