xref: /openbmc/linux/drivers/mfd/max14577.c (revision 0f28379e)
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 			&reg_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