Commit | Line | Data |
---|---|---|
3008ddbe | 1 | /* |
aee2a57c | 2 | * max14577.c - mfd core driver for the Maxim 14577/77836 |
3008ddbe | 3 | * |
aee2a57c | 4 | * Copyright (C) 2014 Samsung Electrnoics |
3008ddbe CC |
5 | * Chanwoo Choi <cw00.choi@samsung.com> |
6 | * Krzysztof Kozlowski <k.kozlowski@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 | * This driver is based on max8997.c | |
19 | */ | |
20 | ||
c8016d45 | 21 | #include <linux/err.h> |
3008ddbe CC |
22 | #include <linux/module.h> |
23 | #include <linux/interrupt.h> | |
eccb80cc | 24 | #include <linux/of_device.h> |
3008ddbe CC |
25 | #include <linux/mfd/core.h> |
26 | #include <linux/mfd/max14577.h> | |
27 | #include <linux/mfd/max14577-private.h> | |
28 | ||
29 | static struct mfd_cell max14577_devs[] = { | |
a0b0ea49 KK |
30 | { |
31 | .name = "max14577-muic", | |
32 | .of_compatible = "maxim,max14577-muic", | |
33 | }, | |
41096801 KK |
34 | { |
35 | .name = "max14577-regulator", | |
36 | .of_compatible = "maxim,max14577-regulator", | |
37 | }, | |
3008ddbe CC |
38 | { .name = "max14577-charger", }, |
39 | }; | |
40 | ||
aee2a57c KK |
41 | static struct mfd_cell max77836_devs[] = { |
42 | { | |
43 | .name = "max77836-muic", | |
44 | .of_compatible = "maxim,max77836-muic", | |
45 | }, | |
46 | { | |
47 | .name = "max77836-regulator", | |
48 | .of_compatible = "maxim,max77836-regulator", | |
49 | }, | |
50 | { | |
51 | .name = "max77836-charger", | |
52 | .of_compatible = "maxim,max77836-charger", | |
53 | }, | |
54 | { | |
55 | .name = "max77836-battery", | |
56 | .of_compatible = "maxim,max77836-battery", | |
57 | }, | |
58 | }; | |
59 | ||
eccb80cc KK |
60 | static struct of_device_id max14577_dt_match[] = { |
61 | { | |
62 | .compatible = "maxim,max14577", | |
63 | .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, | |
64 | }, | |
aee2a57c KK |
65 | { |
66 | .compatible = "maxim,max77836", | |
67 | .data = (void *)MAXIM_DEVICE_TYPE_MAX77836, | |
68 | }, | |
eccb80cc KK |
69 | {}, |
70 | }; | |
71 | ||
575343d1 | 72 | static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg) |
3008ddbe CC |
73 | { |
74 | switch (reg) { | |
75 | case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3: | |
76 | return true; | |
77 | default: | |
78 | break; | |
79 | } | |
80 | return false; | |
81 | } | |
82 | ||
aee2a57c KK |
83 | static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg) |
84 | { | |
85 | /* Any max14577 volatile registers are also max77836 volatile. */ | |
86 | if (max14577_muic_volatile_reg(dev, reg)) | |
87 | return true; | |
88 | ||
89 | switch (reg) { | |
90 | case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB: | |
91 | case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB: | |
92 | case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L: | |
93 | case MAX77836_PMIC_REG_INTSRC: | |
94 | case MAX77836_PMIC_REG_TOPSYS_INT: | |
95 | case MAX77836_PMIC_REG_TOPSYS_STAT: | |
96 | return true; | |
97 | default: | |
98 | break; | |
99 | } | |
100 | return false; | |
101 | } | |
102 | ||
575343d1 | 103 | static const struct regmap_config max14577_muic_regmap_config = { |
3008ddbe CC |
104 | .reg_bits = 8, |
105 | .val_bits = 8, | |
575343d1 | 106 | .volatile_reg = max14577_muic_volatile_reg, |
3008ddbe CC |
107 | .max_register = MAX14577_REG_END, |
108 | }; | |
109 | ||
aee2a57c KK |
110 | static const struct regmap_config max77836_pmic_regmap_config = { |
111 | .reg_bits = 8, | |
112 | .val_bits = 8, | |
113 | .volatile_reg = max77836_muic_volatile_reg, | |
114 | .max_register = MAX77836_PMIC_REG_END, | |
115 | }; | |
116 | ||
3008ddbe CC |
117 | static const struct regmap_irq max14577_irqs[] = { |
118 | /* INT1 interrupts */ | |
c7846852 KK |
119 | { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, |
120 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, | |
121 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, | |
3008ddbe | 122 | /* INT2 interrupts */ |
c7846852 KK |
123 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, |
124 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, | |
125 | { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, | |
126 | { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, | |
127 | { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, | |
3008ddbe | 128 | /* INT3 interrupts */ |
c7846852 KK |
129 | { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, |
130 | { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, | |
131 | { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, | |
132 | { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, | |
3008ddbe CC |
133 | }; |
134 | ||
135 | static const struct regmap_irq_chip max14577_irq_chip = { | |
136 | .name = "max14577", | |
137 | .status_base = MAX14577_REG_INT1, | |
138 | .mask_base = MAX14577_REG_INTMASK1, | |
aee2a57c | 139 | .mask_invert = true, |
3008ddbe CC |
140 | .num_regs = 3, |
141 | .irqs = max14577_irqs, | |
142 | .num_irqs = ARRAY_SIZE(max14577_irqs), | |
143 | }; | |
144 | ||
aee2a57c KK |
145 | static const struct regmap_irq max77836_muic_irqs[] = { |
146 | /* INT1 interrupts */ | |
147 | { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, | |
148 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, | |
149 | { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, | |
4706a525 | 150 | { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, }, |
aee2a57c KK |
151 | /* INT2 interrupts */ |
152 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, | |
153 | { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, | |
154 | { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, | |
155 | { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, | |
156 | { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, | |
157 | { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, }, | |
158 | /* INT3 interrupts */ | |
159 | { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, | |
160 | { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, | |
161 | { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, | |
162 | { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, | |
163 | }; | |
164 | ||
165 | static const struct regmap_irq_chip max77836_muic_irq_chip = { | |
166 | .name = "max77836-muic", | |
167 | .status_base = MAX14577_REG_INT1, | |
168 | .mask_base = MAX14577_REG_INTMASK1, | |
169 | .mask_invert = true, | |
170 | .num_regs = 3, | |
171 | .irqs = max77836_muic_irqs, | |
172 | .num_irqs = ARRAY_SIZE(max77836_muic_irqs), | |
173 | }; | |
174 | ||
175 | static const struct regmap_irq max77836_pmic_irqs[] = { | |
176 | { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, }, | |
177 | { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, }, | |
178 | }; | |
179 | ||
180 | static const struct regmap_irq_chip max77836_pmic_irq_chip = { | |
181 | .name = "max77836-pmic", | |
182 | .status_base = MAX77836_PMIC_REG_TOPSYS_INT, | |
183 | .mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK, | |
184 | .mask_invert = false, | |
185 | .num_regs = 1, | |
186 | .irqs = max77836_pmic_irqs, | |
187 | .num_irqs = ARRAY_SIZE(max77836_pmic_irqs), | |
188 | }; | |
189 | ||
eccb80cc KK |
190 | static void max14577_print_dev_type(struct max14577 *max14577) |
191 | { | |
192 | u8 reg_data, vendor_id, device_id; | |
193 | int ret; | |
194 | ||
195 | ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, | |
196 | ®_data); | |
197 | if (ret) { | |
198 | dev_err(max14577->dev, | |
199 | "Failed to read DEVICEID register: %d\n", ret); | |
200 | return; | |
201 | } | |
202 | ||
203 | vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> | |
204 | DEVID_VENDORID_SHIFT); | |
205 | device_id = ((reg_data & DEVID_DEVICEID_MASK) >> | |
206 | DEVID_DEVICEID_SHIFT); | |
207 | ||
208 | dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n", | |
209 | max14577->dev_type, device_id, vendor_id); | |
210 | } | |
211 | ||
aee2a57c KK |
212 | /* |
213 | * Max77836 specific initialization code for driver probe. | |
214 | * Adds new I2C dummy device, regmap and regmap IRQ chip. | |
215 | * Unmasks Interrupt Source register. | |
216 | * | |
217 | * On success returns 0. | |
218 | * On failure returns errno and reverts any changes done so far (e.g. remove | |
219 | * I2C dummy device), except masking the INT SRC register. | |
220 | */ | |
221 | static int max77836_init(struct max14577 *max14577) | |
222 | { | |
223 | int ret; | |
224 | u8 intsrc_mask; | |
225 | ||
226 | max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter, | |
227 | I2C_ADDR_PMIC); | |
228 | if (!max14577->i2c_pmic) { | |
229 | dev_err(max14577->dev, "Failed to register PMIC I2C device\n"); | |
230 | return -ENODEV; | |
231 | } | |
232 | i2c_set_clientdata(max14577->i2c_pmic, max14577); | |
233 | ||
234 | max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic, | |
235 | &max77836_pmic_regmap_config); | |
236 | if (IS_ERR(max14577->regmap_pmic)) { | |
237 | ret = PTR_ERR(max14577->regmap_pmic); | |
238 | dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n", | |
239 | ret); | |
240 | goto err; | |
241 | } | |
242 | ||
243 | /* Un-mask MAX77836 Interrupt Source register */ | |
244 | ret = max14577_read_reg(max14577->regmap_pmic, | |
245 | MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask); | |
246 | if (ret < 0) { | |
247 | dev_err(max14577->dev, "Failed to read PMIC register\n"); | |
248 | goto err; | |
249 | } | |
250 | ||
251 | intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK); | |
252 | intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK); | |
253 | ret = max14577_write_reg(max14577->regmap_pmic, | |
254 | MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask); | |
255 | if (ret < 0) { | |
256 | dev_err(max14577->dev, "Failed to write PMIC register\n"); | |
257 | goto err; | |
258 | } | |
259 | ||
260 | ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq, | |
261 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED, | |
262 | 0, &max77836_pmic_irq_chip, | |
263 | &max14577->irq_data_pmic); | |
264 | if (ret != 0) { | |
265 | dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n", | |
266 | max14577->irq, ret); | |
267 | goto err; | |
268 | } | |
269 | ||
270 | return 0; | |
271 | ||
272 | err: | |
273 | i2c_unregister_device(max14577->i2c_pmic); | |
274 | ||
275 | return ret; | |
276 | } | |
277 | ||
278 | /* | |
279 | * Max77836 specific de-initialization code for driver remove. | |
280 | */ | |
281 | static void max77836_remove(struct max14577 *max14577) | |
282 | { | |
283 | regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic); | |
284 | i2c_unregister_device(max14577->i2c_pmic); | |
285 | } | |
286 | ||
3008ddbe CC |
287 | static int max14577_i2c_probe(struct i2c_client *i2c, |
288 | const struct i2c_device_id *id) | |
289 | { | |
290 | struct max14577 *max14577; | |
291 | struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev); | |
292 | struct device_node *np = i2c->dev.of_node; | |
3008ddbe | 293 | int ret = 0; |
aee2a57c KK |
294 | const struct regmap_irq_chip *irq_chip; |
295 | struct mfd_cell *mfd_devs; | |
296 | unsigned int mfd_devs_size; | |
297 | int irq_flags; | |
3008ddbe CC |
298 | |
299 | if (np) { | |
300 | pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); | |
301 | if (!pdata) | |
302 | return -ENOMEM; | |
303 | i2c->dev.platform_data = pdata; | |
304 | } | |
305 | ||
306 | if (!pdata) { | |
aab5dc68 | 307 | dev_err(&i2c->dev, "No platform data found.\n"); |
3008ddbe CC |
308 | return -EINVAL; |
309 | } | |
310 | ||
311 | max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL); | |
312 | if (!max14577) | |
313 | return -ENOMEM; | |
314 | ||
315 | i2c_set_clientdata(i2c, max14577); | |
316 | max14577->dev = &i2c->dev; | |
317 | max14577->i2c = i2c; | |
318 | max14577->irq = i2c->irq; | |
319 | ||
575343d1 KK |
320 | max14577->regmap = devm_regmap_init_i2c(i2c, |
321 | &max14577_muic_regmap_config); | |
3008ddbe CC |
322 | if (IS_ERR(max14577->regmap)) { |
323 | ret = PTR_ERR(max14577->regmap); | |
324 | dev_err(max14577->dev, "Failed to allocate register map: %d\n", | |
325 | ret); | |
326 | return ret; | |
327 | } | |
328 | ||
eccb80cc KK |
329 | if (np) { |
330 | const struct of_device_id *of_id; | |
331 | ||
332 | of_id = of_match_device(max14577_dt_match, &i2c->dev); | |
333 | if (of_id) | |
334 | max14577->dev_type = (unsigned int)of_id->data; | |
335 | } else { | |
336 | max14577->dev_type = id->driver_data; | |
3008ddbe | 337 | } |
eccb80cc KK |
338 | |
339 | max14577_print_dev_type(max14577); | |
3008ddbe | 340 | |
aee2a57c KK |
341 | switch (max14577->dev_type) { |
342 | case MAXIM_DEVICE_TYPE_MAX77836: | |
343 | irq_chip = &max77836_muic_irq_chip; | |
344 | mfd_devs = max77836_devs; | |
345 | mfd_devs_size = ARRAY_SIZE(max77836_devs); | |
346 | irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED; | |
347 | break; | |
348 | case MAXIM_DEVICE_TYPE_MAX14577: | |
349 | default: | |
350 | irq_chip = &max14577_irq_chip; | |
351 | mfd_devs = max14577_devs; | |
352 | mfd_devs_size = ARRAY_SIZE(max14577_devs); | |
353 | irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | |
354 | break; | |
355 | } | |
356 | ||
3008ddbe | 357 | ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, |
aee2a57c | 358 | irq_flags, 0, irq_chip, |
3008ddbe CC |
359 | &max14577->irq_data); |
360 | if (ret != 0) { | |
361 | dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", | |
362 | max14577->irq, ret); | |
363 | return ret; | |
364 | } | |
365 | ||
aee2a57c KK |
366 | /* Max77836 specific initialization code (additional regmap) */ |
367 | if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) { | |
368 | ret = max77836_init(max14577); | |
369 | if (ret < 0) | |
370 | goto err_max77836; | |
371 | } | |
372 | ||
373 | ret = mfd_add_devices(max14577->dev, -1, mfd_devs, | |
374 | mfd_devs_size, NULL, 0, | |
3008ddbe CC |
375 | regmap_irq_get_domain(max14577->irq_data)); |
376 | if (ret < 0) | |
377 | goto err_mfd; | |
378 | ||
379 | device_init_wakeup(max14577->dev, 1); | |
380 | ||
381 | return 0; | |
382 | ||
383 | err_mfd: | |
aee2a57c KK |
384 | if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) |
385 | max77836_remove(max14577); | |
386 | err_max77836: | |
3008ddbe CC |
387 | regmap_del_irq_chip(max14577->irq, max14577->irq_data); |
388 | ||
389 | return ret; | |
390 | } | |
391 | ||
392 | static int max14577_i2c_remove(struct i2c_client *i2c) | |
393 | { | |
394 | struct max14577 *max14577 = i2c_get_clientdata(i2c); | |
395 | ||
396 | mfd_remove_devices(max14577->dev); | |
397 | regmap_del_irq_chip(max14577->irq, max14577->irq_data); | |
aee2a57c KK |
398 | if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) |
399 | max77836_remove(max14577); | |
3008ddbe CC |
400 | |
401 | return 0; | |
402 | } | |
403 | ||
404 | static const struct i2c_device_id max14577_i2c_id[] = { | |
eccb80cc | 405 | { "max14577", MAXIM_DEVICE_TYPE_MAX14577, }, |
aee2a57c | 406 | { "max77836", MAXIM_DEVICE_TYPE_MAX77836, }, |
3008ddbe CC |
407 | { } |
408 | }; | |
409 | MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); | |
410 | ||
3edeb1e4 | 411 | #ifdef CONFIG_PM_SLEEP |
3008ddbe CC |
412 | static int max14577_suspend(struct device *dev) |
413 | { | |
414 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | |
415 | struct max14577 *max14577 = i2c_get_clientdata(i2c); | |
416 | ||
417 | if (device_may_wakeup(dev)) { | |
418 | enable_irq_wake(max14577->irq); | |
419 | /* | |
420 | * MUIC IRQ must be disabled during suspend if this is | |
421 | * a wake up source because it will be handled before | |
422 | * resuming I2C. | |
423 | * | |
424 | * When device is woken up from suspend (e.g. by ADC change), | |
425 | * an interrupt occurs before resuming I2C bus controller. | |
426 | * Interrupt handler tries to read registers but this read | |
427 | * will fail because I2C is still suspended. | |
428 | */ | |
429 | disable_irq(max14577->irq); | |
430 | } | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
435 | static int max14577_resume(struct device *dev) | |
436 | { | |
437 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | |
438 | struct max14577 *max14577 = i2c_get_clientdata(i2c); | |
439 | ||
440 | if (device_may_wakeup(dev)) { | |
441 | disable_irq_wake(max14577->irq); | |
442 | enable_irq(max14577->irq); | |
443 | } | |
444 | ||
445 | return 0; | |
446 | } | |
3edeb1e4 | 447 | #endif /* CONFIG_PM_SLEEP */ |
3008ddbe | 448 | |
3008ddbe CC |
449 | static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); |
450 | ||
451 | static struct i2c_driver max14577_i2c_driver = { | |
452 | .driver = { | |
453 | .name = "max14577", | |
454 | .owner = THIS_MODULE, | |
455 | .pm = &max14577_pm, | |
ae679c12 | 456 | .of_match_table = max14577_dt_match, |
3008ddbe CC |
457 | }, |
458 | .probe = max14577_i2c_probe, | |
459 | .remove = max14577_i2c_remove, | |
460 | .id_table = max14577_i2c_id, | |
461 | }; | |
462 | ||
463 | static int __init max14577_i2c_init(void) | |
464 | { | |
eccb80cc KK |
465 | BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM); |
466 | BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM); | |
467 | ||
3008ddbe CC |
468 | return i2c_add_driver(&max14577_i2c_driver); |
469 | } | |
470 | subsys_initcall(max14577_i2c_init); | |
471 | ||
472 | static void __exit max14577_i2c_exit(void) | |
473 | { | |
474 | i2c_del_driver(&max14577_i2c_driver); | |
475 | } | |
476 | module_exit(max14577_i2c_exit); | |
477 | ||
478 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>"); | |
aee2a57c | 479 | MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver"); |
3008ddbe | 480 | MODULE_LICENSE("GPL"); |