1d7d8d7a2SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0+
2d7d8d7a2SKrzysztof Kozlowski //
3d7d8d7a2SKrzysztof Kozlowski // max14577.c - mfd core driver for the Maxim 14577/77836
4d7d8d7a2SKrzysztof Kozlowski //
5d7d8d7a2SKrzysztof Kozlowski // Copyright (C) 2014 Samsung Electronics
6d7d8d7a2SKrzysztof Kozlowski // Chanwoo Choi <cw00.choi@samsung.com>
7d7d8d7a2SKrzysztof Kozlowski // Krzysztof Kozlowski <krzk@kernel.org>
8d7d8d7a2SKrzysztof Kozlowski //
9d7d8d7a2SKrzysztof Kozlowski // This driver is based on max8997.c
103008ddbeSChanwoo Choi
11c8016d45SSachin Kamat #include <linux/err.h>
123008ddbeSChanwoo Choi #include <linux/module.h>
133008ddbeSChanwoo Choi #include <linux/interrupt.h>
14eccb80ccSKrzysztof Kozlowski #include <linux/of_device.h>
153008ddbeSChanwoo Choi #include <linux/mfd/core.h>
163008ddbeSChanwoo Choi #include <linux/mfd/max14577.h>
173008ddbeSChanwoo Choi #include <linux/mfd/max14577-private.h>
183008ddbeSChanwoo Choi
19b8f139f6SKrzysztof Kozlowski /*
20b8f139f6SKrzysztof Kozlowski * Table of valid charger currents for different Maxim chipsets.
21b8f139f6SKrzysztof Kozlowski * It is placed here because it is used by both charger and regulator driver.
22b8f139f6SKrzysztof Kozlowski */
23b8f139f6SKrzysztof Kozlowski const struct maxim_charger_current maxim_charger_currents[] = {
24b8f139f6SKrzysztof Kozlowski [MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
25b8f139f6SKrzysztof Kozlowski [MAXIM_DEVICE_TYPE_MAX14577] = {
26b8f139f6SKrzysztof Kozlowski .min = MAX14577_CHARGER_CURRENT_LIMIT_MIN,
27b8f139f6SKrzysztof Kozlowski .high_start = MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START,
28b8f139f6SKrzysztof Kozlowski .high_step = MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP,
29b8f139f6SKrzysztof Kozlowski .max = MAX14577_CHARGER_CURRENT_LIMIT_MAX,
30b8f139f6SKrzysztof Kozlowski },
31b8f139f6SKrzysztof Kozlowski [MAXIM_DEVICE_TYPE_MAX77836] = {
32b8f139f6SKrzysztof Kozlowski .min = MAX77836_CHARGER_CURRENT_LIMIT_MIN,
33b8f139f6SKrzysztof Kozlowski .high_start = MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START,
34b8f139f6SKrzysztof Kozlowski .high_step = MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP,
35b8f139f6SKrzysztof Kozlowski .max = MAX77836_CHARGER_CURRENT_LIMIT_MAX,
36b8f139f6SKrzysztof Kozlowski },
37b8f139f6SKrzysztof Kozlowski };
38b8f139f6SKrzysztof Kozlowski EXPORT_SYMBOL_GPL(maxim_charger_currents);
39b8f139f6SKrzysztof Kozlowski
40b8f139f6SKrzysztof Kozlowski /*
41b8f139f6SKrzysztof Kozlowski * maxim_charger_calc_reg_current - Calculate register value for current
42b8f139f6SKrzysztof Kozlowski * @limits: constraints for charger, matching the MBCICHWRC register
43b8f139f6SKrzysztof Kozlowski * @min_ua: minimal requested current, micro Amps
44b8f139f6SKrzysztof Kozlowski * @max_ua: maximum requested current, micro Amps
45b8f139f6SKrzysztof Kozlowski * @dst: destination to store calculated register value
46b8f139f6SKrzysztof Kozlowski *
47b8f139f6SKrzysztof Kozlowski * Calculates the value of MBCICHWRC (Fast Battery Charge Current) register
48b8f139f6SKrzysztof Kozlowski * for given current and stores it under pointed 'dst'. The stored value
49b8f139f6SKrzysztof Kozlowski * combines low bit (MBCICHWRCL) and high bits (MBCICHWRCH). It is also
50b8f139f6SKrzysztof Kozlowski * properly shifted.
51b8f139f6SKrzysztof Kozlowski *
52b8f139f6SKrzysztof Kozlowski * The calculated register value matches the current which:
53b8f139f6SKrzysztof Kozlowski * - is always between <limits.min, limits.max>;
54b8f139f6SKrzysztof Kozlowski * - is always less or equal to max_ua;
55b8f139f6SKrzysztof Kozlowski * - is the highest possible value;
56b8f139f6SKrzysztof Kozlowski * - may be lower than min_ua.
57b8f139f6SKrzysztof Kozlowski *
58b8f139f6SKrzysztof Kozlowski * On success returns 0. On error returns -EINVAL (requested min/max current
59b8f139f6SKrzysztof Kozlowski * is outside of given charger limits) and 'dst' is not set.
60b8f139f6SKrzysztof Kozlowski */
maxim_charger_calc_reg_current(const struct maxim_charger_current * limits,unsigned int min_ua,unsigned int max_ua,u8 * dst)61b8f139f6SKrzysztof Kozlowski int maxim_charger_calc_reg_current(const struct maxim_charger_current *limits,
62b8f139f6SKrzysztof Kozlowski unsigned int min_ua, unsigned int max_ua, u8 *dst)
63b8f139f6SKrzysztof Kozlowski {
641f0fa85cSColin Ian King unsigned int current_bits;
65b8f139f6SKrzysztof Kozlowski
66b8f139f6SKrzysztof Kozlowski if (min_ua > max_ua)
67b8f139f6SKrzysztof Kozlowski return -EINVAL;
68b8f139f6SKrzysztof Kozlowski
69b8f139f6SKrzysztof Kozlowski if (min_ua > limits->max || max_ua < limits->min)
70b8f139f6SKrzysztof Kozlowski return -EINVAL;
71b8f139f6SKrzysztof Kozlowski
72b8f139f6SKrzysztof Kozlowski if (max_ua < limits->high_start) {
73b8f139f6SKrzysztof Kozlowski /*
74b8f139f6SKrzysztof Kozlowski * Less than high_start, so set the minimal current
75b8f139f6SKrzysztof Kozlowski * (turn Low Bit off, 0 as high bits).
76b8f139f6SKrzysztof Kozlowski */
77b8f139f6SKrzysztof Kozlowski *dst = 0x0;
78b8f139f6SKrzysztof Kozlowski return 0;
79b8f139f6SKrzysztof Kozlowski }
80b8f139f6SKrzysztof Kozlowski
81b8f139f6SKrzysztof Kozlowski /* max_ua is in range: <high_start, infinite>, cut it to limits.max */
82b8f139f6SKrzysztof Kozlowski max_ua = min(limits->max, max_ua);
83b8f139f6SKrzysztof Kozlowski max_ua -= limits->high_start;
84b8f139f6SKrzysztof Kozlowski /*
85b8f139f6SKrzysztof Kozlowski * There is no risk of overflow 'max_ua' here because:
86b8f139f6SKrzysztof Kozlowski * - max_ua >= limits.high_start
87b8f139f6SKrzysztof Kozlowski * - BUILD_BUG checks that 'limits' are: max >= high_start + high_step
88b8f139f6SKrzysztof Kozlowski */
89b8f139f6SKrzysztof Kozlowski current_bits = max_ua / limits->high_step;
90b8f139f6SKrzysztof Kozlowski
91b8f139f6SKrzysztof Kozlowski /* Turn Low Bit on (use range <limits.high_start, limits.max>) ... */
92b8f139f6SKrzysztof Kozlowski *dst = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
93b8f139f6SKrzysztof Kozlowski /* and set proper High Bits */
94b8f139f6SKrzysztof Kozlowski *dst |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
95b8f139f6SKrzysztof Kozlowski
96b8f139f6SKrzysztof Kozlowski return 0;
97b8f139f6SKrzysztof Kozlowski }
98b8f139f6SKrzysztof Kozlowski EXPORT_SYMBOL_GPL(maxim_charger_calc_reg_current);
99b8f139f6SKrzysztof Kozlowski
10092725493SKrzysztof Kozlowski static const struct mfd_cell max14577_devs[] = {
101a0b0ea49SKrzysztof Kozlowski {
102a0b0ea49SKrzysztof Kozlowski .name = "max14577-muic",
103a0b0ea49SKrzysztof Kozlowski .of_compatible = "maxim,max14577-muic",
104a0b0ea49SKrzysztof Kozlowski },
10541096801SKrzysztof Kozlowski {
10641096801SKrzysztof Kozlowski .name = "max14577-regulator",
10741096801SKrzysztof Kozlowski .of_compatible = "maxim,max14577-regulator",
10841096801SKrzysztof Kozlowski },
1094476767cSKrzysztof Kozlowski {
1104476767cSKrzysztof Kozlowski .name = "max14577-charger",
1114476767cSKrzysztof Kozlowski .of_compatible = "maxim,max14577-charger",
1124476767cSKrzysztof Kozlowski },
1133008ddbeSChanwoo Choi };
1143008ddbeSChanwoo Choi
11592725493SKrzysztof Kozlowski static const struct mfd_cell max77836_devs[] = {
116aee2a57cSKrzysztof Kozlowski {
117aee2a57cSKrzysztof Kozlowski .name = "max77836-muic",
118aee2a57cSKrzysztof Kozlowski .of_compatible = "maxim,max77836-muic",
119aee2a57cSKrzysztof Kozlowski },
120aee2a57cSKrzysztof Kozlowski {
121aee2a57cSKrzysztof Kozlowski .name = "max77836-regulator",
122aee2a57cSKrzysztof Kozlowski .of_compatible = "maxim,max77836-regulator",
123aee2a57cSKrzysztof Kozlowski },
124aee2a57cSKrzysztof Kozlowski {
125aee2a57cSKrzysztof Kozlowski .name = "max77836-charger",
126aee2a57cSKrzysztof Kozlowski .of_compatible = "maxim,max77836-charger",
127aee2a57cSKrzysztof Kozlowski },
128aee2a57cSKrzysztof Kozlowski {
129aee2a57cSKrzysztof Kozlowski .name = "max77836-battery",
130aee2a57cSKrzysztof Kozlowski .of_compatible = "maxim,max77836-battery",
131aee2a57cSKrzysztof Kozlowski },
132aee2a57cSKrzysztof Kozlowski };
133aee2a57cSKrzysztof Kozlowski
1348f7f6270SKrzysztof Kozlowski static const struct of_device_id max14577_dt_match[] = {
135eccb80ccSKrzysztof Kozlowski {
136eccb80ccSKrzysztof Kozlowski .compatible = "maxim,max14577",
137eccb80ccSKrzysztof Kozlowski .data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
138eccb80ccSKrzysztof Kozlowski },
139aee2a57cSKrzysztof Kozlowski {
140aee2a57cSKrzysztof Kozlowski .compatible = "maxim,max77836",
141aee2a57cSKrzysztof Kozlowski .data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
142aee2a57cSKrzysztof Kozlowski },
143eccb80ccSKrzysztof Kozlowski {},
144eccb80ccSKrzysztof Kozlowski };
145eccb80ccSKrzysztof Kozlowski
max14577_muic_volatile_reg(struct device * dev,unsigned int reg)146575343d1SKrzysztof Kozlowski static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
1473008ddbeSChanwoo Choi {
1483008ddbeSChanwoo Choi switch (reg) {
1493008ddbeSChanwoo Choi case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
1503008ddbeSChanwoo Choi return true;
1513008ddbeSChanwoo Choi default:
1523008ddbeSChanwoo Choi break;
1533008ddbeSChanwoo Choi }
1543008ddbeSChanwoo Choi return false;
1553008ddbeSChanwoo Choi }
1563008ddbeSChanwoo Choi
max77836_muic_volatile_reg(struct device * dev,unsigned int reg)157aee2a57cSKrzysztof Kozlowski static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
158aee2a57cSKrzysztof Kozlowski {
159aee2a57cSKrzysztof Kozlowski /* Any max14577 volatile registers are also max77836 volatile. */
160aee2a57cSKrzysztof Kozlowski if (max14577_muic_volatile_reg(dev, reg))
161aee2a57cSKrzysztof Kozlowski return true;
162aee2a57cSKrzysztof Kozlowski
163aee2a57cSKrzysztof Kozlowski switch (reg) {
164aee2a57cSKrzysztof Kozlowski case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
165aee2a57cSKrzysztof Kozlowski case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
166aee2a57cSKrzysztof Kozlowski case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
167aee2a57cSKrzysztof Kozlowski case MAX77836_PMIC_REG_INTSRC:
168aee2a57cSKrzysztof Kozlowski case MAX77836_PMIC_REG_TOPSYS_INT:
169aee2a57cSKrzysztof Kozlowski case MAX77836_PMIC_REG_TOPSYS_STAT:
170aee2a57cSKrzysztof Kozlowski return true;
171aee2a57cSKrzysztof Kozlowski default:
172aee2a57cSKrzysztof Kozlowski break;
173aee2a57cSKrzysztof Kozlowski }
174aee2a57cSKrzysztof Kozlowski return false;
175aee2a57cSKrzysztof Kozlowski }
176aee2a57cSKrzysztof Kozlowski
177575343d1SKrzysztof Kozlowski static const struct regmap_config max14577_muic_regmap_config = {
1783008ddbeSChanwoo Choi .reg_bits = 8,
1793008ddbeSChanwoo Choi .val_bits = 8,
180575343d1SKrzysztof Kozlowski .volatile_reg = max14577_muic_volatile_reg,
1813008ddbeSChanwoo Choi .max_register = MAX14577_REG_END,
1823008ddbeSChanwoo Choi };
1833008ddbeSChanwoo Choi
184aee2a57cSKrzysztof Kozlowski static const struct regmap_config max77836_pmic_regmap_config = {
185aee2a57cSKrzysztof Kozlowski .reg_bits = 8,
186aee2a57cSKrzysztof Kozlowski .val_bits = 8,
187aee2a57cSKrzysztof Kozlowski .volatile_reg = max77836_muic_volatile_reg,
188aee2a57cSKrzysztof Kozlowski .max_register = MAX77836_PMIC_REG_END,
189aee2a57cSKrzysztof Kozlowski };
190aee2a57cSKrzysztof Kozlowski
1913008ddbeSChanwoo Choi static const struct regmap_irq max14577_irqs[] = {
1923008ddbeSChanwoo Choi /* INT1 interrupts */
193c7846852SKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
194c7846852SKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
195c7846852SKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
1963008ddbeSChanwoo Choi /* INT2 interrupts */
197c7846852SKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
198c7846852SKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
199c7846852SKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
200c7846852SKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
201c7846852SKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
2023008ddbeSChanwoo Choi /* INT3 interrupts */
203c7846852SKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
204c7846852SKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
205c7846852SKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
206c7846852SKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
2073008ddbeSChanwoo Choi };
2083008ddbeSChanwoo Choi
2093008ddbeSChanwoo Choi static const struct regmap_irq_chip max14577_irq_chip = {
2103008ddbeSChanwoo Choi .name = "max14577",
2113008ddbeSChanwoo Choi .status_base = MAX14577_REG_INT1,
212911b8b42SAidan MacDonald .unmask_base = MAX14577_REG_INTMASK1,
2133008ddbeSChanwoo Choi .num_regs = 3,
2143008ddbeSChanwoo Choi .irqs = max14577_irqs,
2153008ddbeSChanwoo Choi .num_irqs = ARRAY_SIZE(max14577_irqs),
2163008ddbeSChanwoo Choi };
2173008ddbeSChanwoo Choi
218aee2a57cSKrzysztof Kozlowski static const struct regmap_irq max77836_muic_irqs[] = {
219aee2a57cSKrzysztof Kozlowski /* INT1 interrupts */
220aee2a57cSKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
221aee2a57cSKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
222aee2a57cSKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
2234706a525SKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
224aee2a57cSKrzysztof Kozlowski /* INT2 interrupts */
225aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
226aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
227aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
228aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
229aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
230aee2a57cSKrzysztof Kozlowski { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
231aee2a57cSKrzysztof Kozlowski /* INT3 interrupts */
232aee2a57cSKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
233aee2a57cSKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
234aee2a57cSKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
235aee2a57cSKrzysztof Kozlowski { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
236aee2a57cSKrzysztof Kozlowski };
237aee2a57cSKrzysztof Kozlowski
238aee2a57cSKrzysztof Kozlowski static const struct regmap_irq_chip max77836_muic_irq_chip = {
239aee2a57cSKrzysztof Kozlowski .name = "max77836-muic",
240aee2a57cSKrzysztof Kozlowski .status_base = MAX14577_REG_INT1,
241911b8b42SAidan MacDonald .unmask_base = MAX14577_REG_INTMASK1,
242aee2a57cSKrzysztof Kozlowski .num_regs = 3,
243aee2a57cSKrzysztof Kozlowski .irqs = max77836_muic_irqs,
244aee2a57cSKrzysztof Kozlowski .num_irqs = ARRAY_SIZE(max77836_muic_irqs),
245aee2a57cSKrzysztof Kozlowski };
246aee2a57cSKrzysztof Kozlowski
247aee2a57cSKrzysztof Kozlowski static const struct regmap_irq max77836_pmic_irqs[] = {
248aee2a57cSKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
249aee2a57cSKrzysztof Kozlowski { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
250aee2a57cSKrzysztof Kozlowski };
251aee2a57cSKrzysztof Kozlowski
252aee2a57cSKrzysztof Kozlowski static const struct regmap_irq_chip max77836_pmic_irq_chip = {
253aee2a57cSKrzysztof Kozlowski .name = "max77836-pmic",
254aee2a57cSKrzysztof Kozlowski .status_base = MAX77836_PMIC_REG_TOPSYS_INT,
255aee2a57cSKrzysztof Kozlowski .mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
256aee2a57cSKrzysztof Kozlowski .num_regs = 1,
257aee2a57cSKrzysztof Kozlowski .irqs = max77836_pmic_irqs,
258aee2a57cSKrzysztof Kozlowski .num_irqs = ARRAY_SIZE(max77836_pmic_irqs),
259aee2a57cSKrzysztof Kozlowski };
260aee2a57cSKrzysztof Kozlowski
max14577_print_dev_type(struct max14577 * max14577)261eccb80ccSKrzysztof Kozlowski static void max14577_print_dev_type(struct max14577 *max14577)
262eccb80ccSKrzysztof Kozlowski {
263eccb80ccSKrzysztof Kozlowski u8 reg_data, vendor_id, device_id;
264eccb80ccSKrzysztof Kozlowski int ret;
265eccb80ccSKrzysztof Kozlowski
266eccb80ccSKrzysztof Kozlowski ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
267eccb80ccSKrzysztof Kozlowski ®_data);
268eccb80ccSKrzysztof Kozlowski if (ret) {
269eccb80ccSKrzysztof Kozlowski dev_err(max14577->dev,
270eccb80ccSKrzysztof Kozlowski "Failed to read DEVICEID register: %d\n", ret);
271eccb80ccSKrzysztof Kozlowski return;
272eccb80ccSKrzysztof Kozlowski }
273eccb80ccSKrzysztof Kozlowski
274eccb80ccSKrzysztof Kozlowski vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
275eccb80ccSKrzysztof Kozlowski DEVID_VENDORID_SHIFT);
276eccb80ccSKrzysztof Kozlowski device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
277eccb80ccSKrzysztof Kozlowski DEVID_DEVICEID_SHIFT);
278eccb80ccSKrzysztof Kozlowski
279eccb80ccSKrzysztof Kozlowski dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
280eccb80ccSKrzysztof Kozlowski max14577->dev_type, device_id, vendor_id);
281eccb80ccSKrzysztof Kozlowski }
282eccb80ccSKrzysztof Kozlowski
283aee2a57cSKrzysztof Kozlowski /*
284aee2a57cSKrzysztof Kozlowski * Max77836 specific initialization code for driver probe.
285aee2a57cSKrzysztof Kozlowski * Adds new I2C dummy device, regmap and regmap IRQ chip.
286aee2a57cSKrzysztof Kozlowski * Unmasks Interrupt Source register.
287aee2a57cSKrzysztof Kozlowski *
288aee2a57cSKrzysztof Kozlowski * On success returns 0.
289aee2a57cSKrzysztof Kozlowski * On failure returns errno and reverts any changes done so far (e.g. remove
290aee2a57cSKrzysztof Kozlowski * I2C dummy device), except masking the INT SRC register.
291aee2a57cSKrzysztof Kozlowski */
max77836_init(struct max14577 * max14577)292aee2a57cSKrzysztof Kozlowski static int max77836_init(struct max14577 *max14577)
293aee2a57cSKrzysztof Kozlowski {
294aee2a57cSKrzysztof Kozlowski int ret;
295aee2a57cSKrzysztof Kozlowski u8 intsrc_mask;
296aee2a57cSKrzysztof Kozlowski
297f6ae8129SWolfram Sang max14577->i2c_pmic = i2c_new_dummy_device(max14577->i2c->adapter,
298aee2a57cSKrzysztof Kozlowski I2C_ADDR_PMIC);
299f6ae8129SWolfram Sang if (IS_ERR(max14577->i2c_pmic)) {
300aee2a57cSKrzysztof Kozlowski dev_err(max14577->dev, "Failed to register PMIC I2C device\n");
301f6ae8129SWolfram Sang return PTR_ERR(max14577->i2c_pmic);
302aee2a57cSKrzysztof Kozlowski }
303aee2a57cSKrzysztof Kozlowski i2c_set_clientdata(max14577->i2c_pmic, max14577);
304aee2a57cSKrzysztof Kozlowski
305aee2a57cSKrzysztof Kozlowski max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic,
306aee2a57cSKrzysztof Kozlowski &max77836_pmic_regmap_config);
307aee2a57cSKrzysztof Kozlowski if (IS_ERR(max14577->regmap_pmic)) {
308aee2a57cSKrzysztof Kozlowski ret = PTR_ERR(max14577->regmap_pmic);
309aee2a57cSKrzysztof Kozlowski dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n",
310aee2a57cSKrzysztof Kozlowski ret);
311aee2a57cSKrzysztof Kozlowski goto err;
312aee2a57cSKrzysztof Kozlowski }
313aee2a57cSKrzysztof Kozlowski
314aee2a57cSKrzysztof Kozlowski /* Un-mask MAX77836 Interrupt Source register */
315aee2a57cSKrzysztof Kozlowski ret = max14577_read_reg(max14577->regmap_pmic,
316aee2a57cSKrzysztof Kozlowski MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
317aee2a57cSKrzysztof Kozlowski if (ret < 0) {
318aee2a57cSKrzysztof Kozlowski dev_err(max14577->dev, "Failed to read PMIC register\n");
319aee2a57cSKrzysztof Kozlowski goto err;
320aee2a57cSKrzysztof Kozlowski }
321aee2a57cSKrzysztof Kozlowski
322aee2a57cSKrzysztof Kozlowski intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
323aee2a57cSKrzysztof Kozlowski intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
324aee2a57cSKrzysztof Kozlowski ret = max14577_write_reg(max14577->regmap_pmic,
325aee2a57cSKrzysztof Kozlowski MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
326aee2a57cSKrzysztof Kozlowski if (ret < 0) {
327aee2a57cSKrzysztof Kozlowski dev_err(max14577->dev, "Failed to write PMIC register\n");
328aee2a57cSKrzysztof Kozlowski goto err;
329aee2a57cSKrzysztof Kozlowski }
330aee2a57cSKrzysztof Kozlowski
331aee2a57cSKrzysztof Kozlowski ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq,
3328163fbd9SKrzysztof Kozlowski IRQF_ONESHOT | IRQF_SHARED,
333aee2a57cSKrzysztof Kozlowski 0, &max77836_pmic_irq_chip,
334aee2a57cSKrzysztof Kozlowski &max14577->irq_data_pmic);
335aee2a57cSKrzysztof Kozlowski if (ret != 0) {
336aee2a57cSKrzysztof Kozlowski dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n",
337aee2a57cSKrzysztof Kozlowski max14577->irq, ret);
338aee2a57cSKrzysztof Kozlowski goto err;
339aee2a57cSKrzysztof Kozlowski }
340aee2a57cSKrzysztof Kozlowski
341aee2a57cSKrzysztof Kozlowski return 0;
342aee2a57cSKrzysztof Kozlowski
343aee2a57cSKrzysztof Kozlowski err:
344aee2a57cSKrzysztof Kozlowski i2c_unregister_device(max14577->i2c_pmic);
345aee2a57cSKrzysztof Kozlowski
346aee2a57cSKrzysztof Kozlowski return ret;
347aee2a57cSKrzysztof Kozlowski }
348aee2a57cSKrzysztof Kozlowski
349aee2a57cSKrzysztof Kozlowski /*
350aee2a57cSKrzysztof Kozlowski * Max77836 specific de-initialization code for driver remove.
351aee2a57cSKrzysztof Kozlowski */
max77836_remove(struct max14577 * max14577)352aee2a57cSKrzysztof Kozlowski static void max77836_remove(struct max14577 *max14577)
353aee2a57cSKrzysztof Kozlowski {
354aee2a57cSKrzysztof Kozlowski regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic);
355aee2a57cSKrzysztof Kozlowski i2c_unregister_device(max14577->i2c_pmic);
356aee2a57cSKrzysztof Kozlowski }
357aee2a57cSKrzysztof Kozlowski
max14577_i2c_probe(struct i2c_client * i2c)3588df21471SUwe Kleine-König static int max14577_i2c_probe(struct i2c_client *i2c)
3593008ddbeSChanwoo Choi {
3608df21471SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
3613008ddbeSChanwoo Choi struct max14577 *max14577;
3623008ddbeSChanwoo Choi struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
3633008ddbeSChanwoo Choi struct device_node *np = i2c->dev.of_node;
3643008ddbeSChanwoo Choi int ret = 0;
365aee2a57cSKrzysztof Kozlowski const struct regmap_irq_chip *irq_chip;
36692725493SKrzysztof Kozlowski const struct mfd_cell *mfd_devs;
367aee2a57cSKrzysztof Kozlowski unsigned int mfd_devs_size;
368aee2a57cSKrzysztof Kozlowski int irq_flags;
3693008ddbeSChanwoo Choi
3703008ddbeSChanwoo Choi if (np) {
3713008ddbeSChanwoo Choi pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
3723008ddbeSChanwoo Choi if (!pdata)
3733008ddbeSChanwoo Choi return -ENOMEM;
3743008ddbeSChanwoo Choi i2c->dev.platform_data = pdata;
3753008ddbeSChanwoo Choi }
3763008ddbeSChanwoo Choi
3773008ddbeSChanwoo Choi if (!pdata) {
378aab5dc68SDan Carpenter dev_err(&i2c->dev, "No platform data found.\n");
3793008ddbeSChanwoo Choi return -EINVAL;
3803008ddbeSChanwoo Choi }
3813008ddbeSChanwoo Choi
3823008ddbeSChanwoo Choi max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL);
3833008ddbeSChanwoo Choi if (!max14577)
3843008ddbeSChanwoo Choi return -ENOMEM;
3853008ddbeSChanwoo Choi
3863008ddbeSChanwoo Choi i2c_set_clientdata(i2c, max14577);
3873008ddbeSChanwoo Choi max14577->dev = &i2c->dev;
3883008ddbeSChanwoo Choi max14577->i2c = i2c;
3893008ddbeSChanwoo Choi max14577->irq = i2c->irq;
3903008ddbeSChanwoo Choi
391575343d1SKrzysztof Kozlowski max14577->regmap = devm_regmap_init_i2c(i2c,
392575343d1SKrzysztof Kozlowski &max14577_muic_regmap_config);
3933008ddbeSChanwoo Choi if (IS_ERR(max14577->regmap)) {
3943008ddbeSChanwoo Choi ret = PTR_ERR(max14577->regmap);
3953008ddbeSChanwoo Choi dev_err(max14577->dev, "Failed to allocate register map: %d\n",
3963008ddbeSChanwoo Choi ret);
3973008ddbeSChanwoo Choi return ret;
3983008ddbeSChanwoo Choi }
3993008ddbeSChanwoo Choi
400eccb80ccSKrzysztof Kozlowski if (np) {
401eccb80ccSKrzysztof Kozlowski const struct of_device_id *of_id;
402eccb80ccSKrzysztof Kozlowski
403eccb80ccSKrzysztof Kozlowski of_id = of_match_device(max14577_dt_match, &i2c->dev);
404eccb80ccSKrzysztof Kozlowski if (of_id)
405*0f28379eSKrzysztof Kozlowski max14577->dev_type = (uintptr_t)of_id->data;
406eccb80ccSKrzysztof Kozlowski } else {
407eccb80ccSKrzysztof Kozlowski max14577->dev_type = id->driver_data;
4083008ddbeSChanwoo Choi }
409eccb80ccSKrzysztof Kozlowski
410eccb80ccSKrzysztof Kozlowski max14577_print_dev_type(max14577);
4113008ddbeSChanwoo Choi
412aee2a57cSKrzysztof Kozlowski switch (max14577->dev_type) {
413aee2a57cSKrzysztof Kozlowski case MAXIM_DEVICE_TYPE_MAX77836:
414aee2a57cSKrzysztof Kozlowski irq_chip = &max77836_muic_irq_chip;
415aee2a57cSKrzysztof Kozlowski mfd_devs = max77836_devs;
416aee2a57cSKrzysztof Kozlowski mfd_devs_size = ARRAY_SIZE(max77836_devs);
4178163fbd9SKrzysztof Kozlowski irq_flags = IRQF_ONESHOT | IRQF_SHARED;
418aee2a57cSKrzysztof Kozlowski break;
419aee2a57cSKrzysztof Kozlowski case MAXIM_DEVICE_TYPE_MAX14577:
420aee2a57cSKrzysztof Kozlowski default:
421aee2a57cSKrzysztof Kozlowski irq_chip = &max14577_irq_chip;
422aee2a57cSKrzysztof Kozlowski mfd_devs = max14577_devs;
423aee2a57cSKrzysztof Kozlowski mfd_devs_size = ARRAY_SIZE(max14577_devs);
4248163fbd9SKrzysztof Kozlowski irq_flags = IRQF_ONESHOT;
425aee2a57cSKrzysztof Kozlowski break;
426aee2a57cSKrzysztof Kozlowski }
427aee2a57cSKrzysztof Kozlowski
4283008ddbeSChanwoo Choi ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
429aee2a57cSKrzysztof Kozlowski irq_flags, 0, irq_chip,
4303008ddbeSChanwoo Choi &max14577->irq_data);
4313008ddbeSChanwoo Choi if (ret != 0) {
4323008ddbeSChanwoo Choi dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
4333008ddbeSChanwoo Choi max14577->irq, ret);
4343008ddbeSChanwoo Choi return ret;
4353008ddbeSChanwoo Choi }
4363008ddbeSChanwoo Choi
437aee2a57cSKrzysztof Kozlowski /* Max77836 specific initialization code (additional regmap) */
438aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
439aee2a57cSKrzysztof Kozlowski ret = max77836_init(max14577);
440aee2a57cSKrzysztof Kozlowski if (ret < 0)
441aee2a57cSKrzysztof Kozlowski goto err_max77836;
442aee2a57cSKrzysztof Kozlowski }
443aee2a57cSKrzysztof Kozlowski
444aee2a57cSKrzysztof Kozlowski ret = mfd_add_devices(max14577->dev, -1, mfd_devs,
445be69e9e0SKrzysztof Kozlowski mfd_devs_size, NULL, 0, NULL);
4463008ddbeSChanwoo Choi if (ret < 0)
4473008ddbeSChanwoo Choi goto err_mfd;
4483008ddbeSChanwoo Choi
4493008ddbeSChanwoo Choi device_init_wakeup(max14577->dev, 1);
4503008ddbeSChanwoo Choi
4513008ddbeSChanwoo Choi return 0;
4523008ddbeSChanwoo Choi
4533008ddbeSChanwoo Choi err_mfd:
454aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
455aee2a57cSKrzysztof Kozlowski max77836_remove(max14577);
456aee2a57cSKrzysztof Kozlowski err_max77836:
4573008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data);
4583008ddbeSChanwoo Choi
4593008ddbeSChanwoo Choi return ret;
4603008ddbeSChanwoo Choi }
4613008ddbeSChanwoo Choi
max14577_i2c_remove(struct i2c_client * i2c)462ed5c2f5fSUwe Kleine-König static void max14577_i2c_remove(struct i2c_client *i2c)
4633008ddbeSChanwoo Choi {
4643008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c);
4653008ddbeSChanwoo Choi
4663008ddbeSChanwoo Choi mfd_remove_devices(max14577->dev);
4673008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data);
468aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
469aee2a57cSKrzysztof Kozlowski max77836_remove(max14577);
4703008ddbeSChanwoo Choi }
4713008ddbeSChanwoo Choi
4723008ddbeSChanwoo Choi static const struct i2c_device_id max14577_i2c_id[] = {
473eccb80ccSKrzysztof Kozlowski { "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
474aee2a57cSKrzysztof Kozlowski { "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
4753008ddbeSChanwoo Choi { }
4763008ddbeSChanwoo Choi };
4773008ddbeSChanwoo Choi MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
4783008ddbeSChanwoo Choi
max14577_suspend(struct device * dev)4793008ddbeSChanwoo Choi static int max14577_suspend(struct device *dev)
4803008ddbeSChanwoo Choi {
4811b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev);
4823008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c);
4833008ddbeSChanwoo Choi
484c4f725b5SKrzysztof Kozlowski if (device_may_wakeup(dev))
4853008ddbeSChanwoo Choi enable_irq_wake(max14577->irq);
4863008ddbeSChanwoo Choi /*
487c4f725b5SKrzysztof Kozlowski * MUIC IRQ must be disabled during suspend because if it happens
488c4f725b5SKrzysztof Kozlowski * while suspended it will be handled before resuming I2C.
4893008ddbeSChanwoo Choi *
4903008ddbeSChanwoo Choi * When device is woken up from suspend (e.g. by ADC change),
4913008ddbeSChanwoo Choi * an interrupt occurs before resuming I2C bus controller.
4923008ddbeSChanwoo Choi * Interrupt handler tries to read registers but this read
4933008ddbeSChanwoo Choi * will fail because I2C is still suspended.
4943008ddbeSChanwoo Choi */
4953008ddbeSChanwoo Choi disable_irq(max14577->irq);
4963008ddbeSChanwoo Choi
4973008ddbeSChanwoo Choi return 0;
4983008ddbeSChanwoo Choi }
4993008ddbeSChanwoo Choi
max14577_resume(struct device * dev)5003008ddbeSChanwoo Choi static int max14577_resume(struct device *dev)
5013008ddbeSChanwoo Choi {
5021b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev);
5033008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c);
5043008ddbeSChanwoo Choi
505c4f725b5SKrzysztof Kozlowski if (device_may_wakeup(dev))
5063008ddbeSChanwoo Choi disable_irq_wake(max14577->irq);
5073008ddbeSChanwoo Choi enable_irq(max14577->irq);
5083008ddbeSChanwoo Choi
5093008ddbeSChanwoo Choi return 0;
5103008ddbeSChanwoo Choi }
5113008ddbeSChanwoo Choi
5128a8d0485SPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
5133008ddbeSChanwoo Choi
5143008ddbeSChanwoo Choi static struct i2c_driver max14577_i2c_driver = {
5153008ddbeSChanwoo Choi .driver = {
5163008ddbeSChanwoo Choi .name = "max14577",
5178a8d0485SPaul Cercueil .pm = pm_sleep_ptr(&max14577_pm),
518ae679c12SSachin Kamat .of_match_table = max14577_dt_match,
5193008ddbeSChanwoo Choi },
5209816d859SUwe Kleine-König .probe = max14577_i2c_probe,
5213008ddbeSChanwoo Choi .remove = max14577_i2c_remove,
5223008ddbeSChanwoo Choi .id_table = max14577_i2c_id,
5233008ddbeSChanwoo Choi };
5243008ddbeSChanwoo Choi
max14577_i2c_init(void)5253008ddbeSChanwoo Choi static int __init max14577_i2c_init(void)
5263008ddbeSChanwoo Choi {
527eccb80ccSKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
528eccb80ccSKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
529eccb80ccSKrzysztof Kozlowski
530b8f139f6SKrzysztof Kozlowski /* Valid charger current values must be provided for each chipset */
531b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
532b8f139f6SKrzysztof Kozlowski
533b8f139f6SKrzysztof Kozlowski /* Check for valid values for charger */
534b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START +
535b8f139f6SKrzysztof Kozlowski MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf !=
536b8f139f6SKrzysztof Kozlowski MAX14577_CHARGER_CURRENT_LIMIT_MAX);
537b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0);
538b8f139f6SKrzysztof Kozlowski
539b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START +
540b8f139f6SKrzysztof Kozlowski MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf !=
541b8f139f6SKrzysztof Kozlowski MAX77836_CHARGER_CURRENT_LIMIT_MAX);
542b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0);
543b8f139f6SKrzysztof Kozlowski
5443008ddbeSChanwoo Choi return i2c_add_driver(&max14577_i2c_driver);
5453008ddbeSChanwoo Choi }
5469961bf18SJavier Martinez Canillas module_init(max14577_i2c_init);
5473008ddbeSChanwoo Choi
max14577_i2c_exit(void)5483008ddbeSChanwoo Choi static void __exit max14577_i2c_exit(void)
5493008ddbeSChanwoo Choi {
5503008ddbeSChanwoo Choi i2c_del_driver(&max14577_i2c_driver);
5513008ddbeSChanwoo Choi }
5523008ddbeSChanwoo Choi module_exit(max14577_i2c_exit);
5533008ddbeSChanwoo Choi
5548c5d0571SKrzysztof Kozlowski MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>");
555aee2a57cSKrzysztof Kozlowski MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
5563008ddbeSChanwoo Choi MODULE_LICENSE("GPL");
557