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 */ 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 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 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, 212*911b8b42SAidan 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, 241*911b8b42SAidan 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 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 */ 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 */ 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 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) 405fab8445cSLee Jones max14577->dev_type = 406fab8445cSLee Jones (enum maxim_device_type)of_id->data; 407eccb80ccSKrzysztof Kozlowski } else { 408eccb80ccSKrzysztof Kozlowski max14577->dev_type = id->driver_data; 4093008ddbeSChanwoo Choi } 410eccb80ccSKrzysztof Kozlowski 411eccb80ccSKrzysztof Kozlowski max14577_print_dev_type(max14577); 4123008ddbeSChanwoo Choi 413aee2a57cSKrzysztof Kozlowski switch (max14577->dev_type) { 414aee2a57cSKrzysztof Kozlowski case MAXIM_DEVICE_TYPE_MAX77836: 415aee2a57cSKrzysztof Kozlowski irq_chip = &max77836_muic_irq_chip; 416aee2a57cSKrzysztof Kozlowski mfd_devs = max77836_devs; 417aee2a57cSKrzysztof Kozlowski mfd_devs_size = ARRAY_SIZE(max77836_devs); 4188163fbd9SKrzysztof Kozlowski irq_flags = IRQF_ONESHOT | IRQF_SHARED; 419aee2a57cSKrzysztof Kozlowski break; 420aee2a57cSKrzysztof Kozlowski case MAXIM_DEVICE_TYPE_MAX14577: 421aee2a57cSKrzysztof Kozlowski default: 422aee2a57cSKrzysztof Kozlowski irq_chip = &max14577_irq_chip; 423aee2a57cSKrzysztof Kozlowski mfd_devs = max14577_devs; 424aee2a57cSKrzysztof Kozlowski mfd_devs_size = ARRAY_SIZE(max14577_devs); 4258163fbd9SKrzysztof Kozlowski irq_flags = IRQF_ONESHOT; 426aee2a57cSKrzysztof Kozlowski break; 427aee2a57cSKrzysztof Kozlowski } 428aee2a57cSKrzysztof Kozlowski 4293008ddbeSChanwoo Choi ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, 430aee2a57cSKrzysztof Kozlowski irq_flags, 0, irq_chip, 4313008ddbeSChanwoo Choi &max14577->irq_data); 4323008ddbeSChanwoo Choi if (ret != 0) { 4333008ddbeSChanwoo Choi dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", 4343008ddbeSChanwoo Choi max14577->irq, ret); 4353008ddbeSChanwoo Choi return ret; 4363008ddbeSChanwoo Choi } 4373008ddbeSChanwoo Choi 438aee2a57cSKrzysztof Kozlowski /* Max77836 specific initialization code (additional regmap) */ 439aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) { 440aee2a57cSKrzysztof Kozlowski ret = max77836_init(max14577); 441aee2a57cSKrzysztof Kozlowski if (ret < 0) 442aee2a57cSKrzysztof Kozlowski goto err_max77836; 443aee2a57cSKrzysztof Kozlowski } 444aee2a57cSKrzysztof Kozlowski 445aee2a57cSKrzysztof Kozlowski ret = mfd_add_devices(max14577->dev, -1, mfd_devs, 446be69e9e0SKrzysztof Kozlowski mfd_devs_size, NULL, 0, NULL); 4473008ddbeSChanwoo Choi if (ret < 0) 4483008ddbeSChanwoo Choi goto err_mfd; 4493008ddbeSChanwoo Choi 4503008ddbeSChanwoo Choi device_init_wakeup(max14577->dev, 1); 4513008ddbeSChanwoo Choi 4523008ddbeSChanwoo Choi return 0; 4533008ddbeSChanwoo Choi 4543008ddbeSChanwoo Choi err_mfd: 455aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) 456aee2a57cSKrzysztof Kozlowski max77836_remove(max14577); 457aee2a57cSKrzysztof Kozlowski err_max77836: 4583008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data); 4593008ddbeSChanwoo Choi 4603008ddbeSChanwoo Choi return ret; 4613008ddbeSChanwoo Choi } 4623008ddbeSChanwoo Choi 463ed5c2f5fSUwe Kleine-König static void max14577_i2c_remove(struct i2c_client *i2c) 4643008ddbeSChanwoo Choi { 4653008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 4663008ddbeSChanwoo Choi 4673008ddbeSChanwoo Choi mfd_remove_devices(max14577->dev); 4683008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data); 469aee2a57cSKrzysztof Kozlowski if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) 470aee2a57cSKrzysztof Kozlowski max77836_remove(max14577); 4713008ddbeSChanwoo Choi } 4723008ddbeSChanwoo Choi 4733008ddbeSChanwoo Choi static const struct i2c_device_id max14577_i2c_id[] = { 474eccb80ccSKrzysztof Kozlowski { "max14577", MAXIM_DEVICE_TYPE_MAX14577, }, 475aee2a57cSKrzysztof Kozlowski { "max77836", MAXIM_DEVICE_TYPE_MAX77836, }, 4763008ddbeSChanwoo Choi { } 4773008ddbeSChanwoo Choi }; 4783008ddbeSChanwoo Choi MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); 4793008ddbeSChanwoo Choi 4803008ddbeSChanwoo Choi static int max14577_suspend(struct device *dev) 4813008ddbeSChanwoo Choi { 4821b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev); 4833008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 4843008ddbeSChanwoo Choi 485c4f725b5SKrzysztof Kozlowski if (device_may_wakeup(dev)) 4863008ddbeSChanwoo Choi enable_irq_wake(max14577->irq); 4873008ddbeSChanwoo Choi /* 488c4f725b5SKrzysztof Kozlowski * MUIC IRQ must be disabled during suspend because if it happens 489c4f725b5SKrzysztof Kozlowski * while suspended it will be handled before resuming I2C. 4903008ddbeSChanwoo Choi * 4913008ddbeSChanwoo Choi * When device is woken up from suspend (e.g. by ADC change), 4923008ddbeSChanwoo Choi * an interrupt occurs before resuming I2C bus controller. 4933008ddbeSChanwoo Choi * Interrupt handler tries to read registers but this read 4943008ddbeSChanwoo Choi * will fail because I2C is still suspended. 4953008ddbeSChanwoo Choi */ 4963008ddbeSChanwoo Choi disable_irq(max14577->irq); 4973008ddbeSChanwoo Choi 4983008ddbeSChanwoo Choi return 0; 4993008ddbeSChanwoo Choi } 5003008ddbeSChanwoo Choi 5013008ddbeSChanwoo Choi static int max14577_resume(struct device *dev) 5023008ddbeSChanwoo Choi { 5031b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev); 5043008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 5053008ddbeSChanwoo Choi 506c4f725b5SKrzysztof Kozlowski if (device_may_wakeup(dev)) 5073008ddbeSChanwoo Choi disable_irq_wake(max14577->irq); 5083008ddbeSChanwoo Choi enable_irq(max14577->irq); 5093008ddbeSChanwoo Choi 5103008ddbeSChanwoo Choi return 0; 5113008ddbeSChanwoo Choi } 5123008ddbeSChanwoo Choi 5138a8d0485SPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); 5143008ddbeSChanwoo Choi 5153008ddbeSChanwoo Choi static struct i2c_driver max14577_i2c_driver = { 5163008ddbeSChanwoo Choi .driver = { 5173008ddbeSChanwoo Choi .name = "max14577", 5188a8d0485SPaul Cercueil .pm = pm_sleep_ptr(&max14577_pm), 519ae679c12SSachin Kamat .of_match_table = max14577_dt_match, 5203008ddbeSChanwoo Choi }, 5218df21471SUwe Kleine-König .probe_new = max14577_i2c_probe, 5223008ddbeSChanwoo Choi .remove = max14577_i2c_remove, 5233008ddbeSChanwoo Choi .id_table = max14577_i2c_id, 5243008ddbeSChanwoo Choi }; 5253008ddbeSChanwoo Choi 5263008ddbeSChanwoo Choi static int __init max14577_i2c_init(void) 5273008ddbeSChanwoo Choi { 528eccb80ccSKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM); 529eccb80ccSKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM); 530eccb80ccSKrzysztof Kozlowski 531b8f139f6SKrzysztof Kozlowski /* Valid charger current values must be provided for each chipset */ 532b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM); 533b8f139f6SKrzysztof Kozlowski 534b8f139f6SKrzysztof Kozlowski /* Check for valid values for charger */ 535b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START + 536b8f139f6SKrzysztof Kozlowski MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf != 537b8f139f6SKrzysztof Kozlowski MAX14577_CHARGER_CURRENT_LIMIT_MAX); 538b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0); 539b8f139f6SKrzysztof Kozlowski 540b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START + 541b8f139f6SKrzysztof Kozlowski MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf != 542b8f139f6SKrzysztof Kozlowski MAX77836_CHARGER_CURRENT_LIMIT_MAX); 543b8f139f6SKrzysztof Kozlowski BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0); 544b8f139f6SKrzysztof Kozlowski 5453008ddbeSChanwoo Choi return i2c_add_driver(&max14577_i2c_driver); 5463008ddbeSChanwoo Choi } 5479961bf18SJavier Martinez Canillas module_init(max14577_i2c_init); 5483008ddbeSChanwoo Choi 5493008ddbeSChanwoo Choi static void __exit max14577_i2c_exit(void) 5503008ddbeSChanwoo Choi { 5513008ddbeSChanwoo Choi i2c_del_driver(&max14577_i2c_driver); 5523008ddbeSChanwoo Choi } 5533008ddbeSChanwoo Choi module_exit(max14577_i2c_exit); 5543008ddbeSChanwoo Choi 5558c5d0571SKrzysztof Kozlowski MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>"); 556aee2a57cSKrzysztof Kozlowski MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver"); 5573008ddbeSChanwoo Choi MODULE_LICENSE("GPL"); 558