18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// max14577.c - mfd core driver for the Maxim 14577/77836 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2014 Samsung Electronics 68c2ecf20Sopenharmony_ci// Chanwoo Choi <cw00.choi@samsung.com> 78c2ecf20Sopenharmony_ci// Krzysztof Kozlowski <krzk@kernel.org> 88c2ecf20Sopenharmony_ci// 98c2ecf20Sopenharmony_ci// This driver is based on max8997.c 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 168c2ecf20Sopenharmony_ci#include <linux/mfd/max14577.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/max14577-private.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Table of valid charger currents for different Maxim chipsets. 218c2ecf20Sopenharmony_ci * It is placed here because it is used by both charger and regulator driver. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ciconst struct maxim_charger_current maxim_charger_currents[] = { 248c2ecf20Sopenharmony_ci [MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 }, 258c2ecf20Sopenharmony_ci [MAXIM_DEVICE_TYPE_MAX14577] = { 268c2ecf20Sopenharmony_ci .min = MAX14577_CHARGER_CURRENT_LIMIT_MIN, 278c2ecf20Sopenharmony_ci .high_start = MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START, 288c2ecf20Sopenharmony_ci .high_step = MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP, 298c2ecf20Sopenharmony_ci .max = MAX14577_CHARGER_CURRENT_LIMIT_MAX, 308c2ecf20Sopenharmony_ci }, 318c2ecf20Sopenharmony_ci [MAXIM_DEVICE_TYPE_MAX77836] = { 328c2ecf20Sopenharmony_ci .min = MAX77836_CHARGER_CURRENT_LIMIT_MIN, 338c2ecf20Sopenharmony_ci .high_start = MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START, 348c2ecf20Sopenharmony_ci .high_step = MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP, 358c2ecf20Sopenharmony_ci .max = MAX77836_CHARGER_CURRENT_LIMIT_MAX, 368c2ecf20Sopenharmony_ci }, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(maxim_charger_currents); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * maxim_charger_calc_reg_current - Calculate register value for current 428c2ecf20Sopenharmony_ci * @limits: constraints for charger, matching the MBCICHWRC register 438c2ecf20Sopenharmony_ci * @min_ua: minimal requested current, micro Amps 448c2ecf20Sopenharmony_ci * @max_ua: maximum requested current, micro Amps 458c2ecf20Sopenharmony_ci * @dst: destination to store calculated register value 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Calculates the value of MBCICHWRC (Fast Battery Charge Current) register 488c2ecf20Sopenharmony_ci * for given current and stores it under pointed 'dst'. The stored value 498c2ecf20Sopenharmony_ci * combines low bit (MBCICHWRCL) and high bits (MBCICHWRCH). It is also 508c2ecf20Sopenharmony_ci * properly shifted. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * The calculated register value matches the current which: 538c2ecf20Sopenharmony_ci * - is always between <limits.min, limits.max>; 548c2ecf20Sopenharmony_ci * - is always less or equal to max_ua; 558c2ecf20Sopenharmony_ci * - is the highest possible value; 568c2ecf20Sopenharmony_ci * - may be lower than min_ua. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * On success returns 0. On error returns -EINVAL (requested min/max current 598c2ecf20Sopenharmony_ci * is outside of given charger limits) and 'dst' is not set. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciint maxim_charger_calc_reg_current(const struct maxim_charger_current *limits, 628c2ecf20Sopenharmony_ci unsigned int min_ua, unsigned int max_ua, u8 *dst) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned int current_bits; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (min_ua > max_ua) 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (min_ua > limits->max || max_ua < limits->min) 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (max_ua < limits->high_start) { 738c2ecf20Sopenharmony_ci /* 748c2ecf20Sopenharmony_ci * Less than high_start, so set the minimal current 758c2ecf20Sopenharmony_ci * (turn Low Bit off, 0 as high bits). 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci *dst = 0x0; 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* max_ua is in range: <high_start, infinite>, cut it to limits.max */ 828c2ecf20Sopenharmony_ci max_ua = min(limits->max, max_ua); 838c2ecf20Sopenharmony_ci max_ua -= limits->high_start; 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * There is no risk of overflow 'max_ua' here because: 868c2ecf20Sopenharmony_ci * - max_ua >= limits.high_start 878c2ecf20Sopenharmony_ci * - BUILD_BUG checks that 'limits' are: max >= high_start + high_step 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci current_bits = max_ua / limits->high_step; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Turn Low Bit on (use range <limits.high_start, limits.max>) ... */ 928c2ecf20Sopenharmony_ci *dst = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; 938c2ecf20Sopenharmony_ci /* and set proper High Bits */ 948c2ecf20Sopenharmony_ci *dst |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(maxim_charger_calc_reg_current); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const struct mfd_cell max14577_devs[] = { 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci .name = "max14577-muic", 1038c2ecf20Sopenharmony_ci .of_compatible = "maxim,max14577-muic", 1048c2ecf20Sopenharmony_ci }, 1058c2ecf20Sopenharmony_ci { 1068c2ecf20Sopenharmony_ci .name = "max14577-regulator", 1078c2ecf20Sopenharmony_ci .of_compatible = "maxim,max14577-regulator", 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci { 1108c2ecf20Sopenharmony_ci .name = "max14577-charger", 1118c2ecf20Sopenharmony_ci .of_compatible = "maxim,max14577-charger", 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic const struct mfd_cell max77836_devs[] = { 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci .name = "max77836-muic", 1188c2ecf20Sopenharmony_ci .of_compatible = "maxim,max77836-muic", 1198c2ecf20Sopenharmony_ci }, 1208c2ecf20Sopenharmony_ci { 1218c2ecf20Sopenharmony_ci .name = "max77836-regulator", 1228c2ecf20Sopenharmony_ci .of_compatible = "maxim,max77836-regulator", 1238c2ecf20Sopenharmony_ci }, 1248c2ecf20Sopenharmony_ci { 1258c2ecf20Sopenharmony_ci .name = "max77836-charger", 1268c2ecf20Sopenharmony_ci .of_compatible = "maxim,max77836-charger", 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci { 1298c2ecf20Sopenharmony_ci .name = "max77836-battery", 1308c2ecf20Sopenharmony_ci .of_compatible = "maxim,max77836-battery", 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct of_device_id max14577_dt_match[] = { 1358c2ecf20Sopenharmony_ci { 1368c2ecf20Sopenharmony_ci .compatible = "maxim,max14577", 1378c2ecf20Sopenharmony_ci .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci .compatible = "maxim,max77836", 1418c2ecf20Sopenharmony_ci .data = (void *)MAXIM_DEVICE_TYPE_MAX77836, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci {}, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci switch (reg) { 1498c2ecf20Sopenharmony_ci case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3: 1508c2ecf20Sopenharmony_ci return true; 1518c2ecf20Sopenharmony_ci default: 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci return false; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci /* Any max14577 volatile registers are also max77836 volatile. */ 1608c2ecf20Sopenharmony_ci if (max14577_muic_volatile_reg(dev, reg)) 1618c2ecf20Sopenharmony_ci return true; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci switch (reg) { 1648c2ecf20Sopenharmony_ci case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB: 1658c2ecf20Sopenharmony_ci case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB: 1668c2ecf20Sopenharmony_ci case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L: 1678c2ecf20Sopenharmony_ci case MAX77836_PMIC_REG_INTSRC: 1688c2ecf20Sopenharmony_ci case MAX77836_PMIC_REG_TOPSYS_INT: 1698c2ecf20Sopenharmony_ci case MAX77836_PMIC_REG_TOPSYS_STAT: 1708c2ecf20Sopenharmony_ci return true; 1718c2ecf20Sopenharmony_ci default: 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci return false; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct regmap_config max14577_muic_regmap_config = { 1788c2ecf20Sopenharmony_ci .reg_bits = 8, 1798c2ecf20Sopenharmony_ci .val_bits = 8, 1808c2ecf20Sopenharmony_ci .volatile_reg = max14577_muic_volatile_reg, 1818c2ecf20Sopenharmony_ci .max_register = MAX14577_REG_END, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic const struct regmap_config max77836_pmic_regmap_config = { 1858c2ecf20Sopenharmony_ci .reg_bits = 8, 1868c2ecf20Sopenharmony_ci .val_bits = 8, 1878c2ecf20Sopenharmony_ci .volatile_reg = max77836_muic_volatile_reg, 1888c2ecf20Sopenharmony_ci .max_register = MAX77836_PMIC_REG_END, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic const struct regmap_irq max14577_irqs[] = { 1928c2ecf20Sopenharmony_ci /* INT1 interrupts */ 1938c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, 1948c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, 1958c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, 1968c2ecf20Sopenharmony_ci /* INT2 interrupts */ 1978c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, 1988c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, 1998c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, 2008c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, 2018c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, 2028c2ecf20Sopenharmony_ci /* INT3 interrupts */ 2038c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, 2048c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, 2058c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, 2068c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic const struct regmap_irq_chip max14577_irq_chip = { 2108c2ecf20Sopenharmony_ci .name = "max14577", 2118c2ecf20Sopenharmony_ci .status_base = MAX14577_REG_INT1, 2128c2ecf20Sopenharmony_ci .mask_base = MAX14577_REG_INTMASK1, 2138c2ecf20Sopenharmony_ci .mask_invert = true, 2148c2ecf20Sopenharmony_ci .num_regs = 3, 2158c2ecf20Sopenharmony_ci .irqs = max14577_irqs, 2168c2ecf20Sopenharmony_ci .num_irqs = ARRAY_SIZE(max14577_irqs), 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic const struct regmap_irq max77836_muic_irqs[] = { 2208c2ecf20Sopenharmony_ci /* INT1 interrupts */ 2218c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, }, 2228c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, }, 2238c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, }, 2248c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, }, 2258c2ecf20Sopenharmony_ci /* INT2 interrupts */ 2268c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, }, 2278c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, }, 2288c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, }, 2298c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, }, 2308c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, }, 2318c2ecf20Sopenharmony_ci { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, }, 2328c2ecf20Sopenharmony_ci /* INT3 interrupts */ 2338c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, }, 2348c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, }, 2358c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, }, 2368c2ecf20Sopenharmony_ci { .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, }, 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic const struct regmap_irq_chip max77836_muic_irq_chip = { 2408c2ecf20Sopenharmony_ci .name = "max77836-muic", 2418c2ecf20Sopenharmony_ci .status_base = MAX14577_REG_INT1, 2428c2ecf20Sopenharmony_ci .mask_base = MAX14577_REG_INTMASK1, 2438c2ecf20Sopenharmony_ci .mask_invert = true, 2448c2ecf20Sopenharmony_ci .num_regs = 3, 2458c2ecf20Sopenharmony_ci .irqs = max77836_muic_irqs, 2468c2ecf20Sopenharmony_ci .num_irqs = ARRAY_SIZE(max77836_muic_irqs), 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic const struct regmap_irq max77836_pmic_irqs[] = { 2508c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, }, 2518c2ecf20Sopenharmony_ci { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, }, 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic const struct regmap_irq_chip max77836_pmic_irq_chip = { 2558c2ecf20Sopenharmony_ci .name = "max77836-pmic", 2568c2ecf20Sopenharmony_ci .status_base = MAX77836_PMIC_REG_TOPSYS_INT, 2578c2ecf20Sopenharmony_ci .mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK, 2588c2ecf20Sopenharmony_ci .mask_invert = false, 2598c2ecf20Sopenharmony_ci .num_regs = 1, 2608c2ecf20Sopenharmony_ci .irqs = max77836_pmic_irqs, 2618c2ecf20Sopenharmony_ci .num_irqs = ARRAY_SIZE(max77836_pmic_irqs), 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void max14577_print_dev_type(struct max14577 *max14577) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci u8 reg_data, vendor_id, device_id; 2678c2ecf20Sopenharmony_ci int ret; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, 2708c2ecf20Sopenharmony_ci ®_data); 2718c2ecf20Sopenharmony_ci if (ret) { 2728c2ecf20Sopenharmony_ci dev_err(max14577->dev, 2738c2ecf20Sopenharmony_ci "Failed to read DEVICEID register: %d\n", ret); 2748c2ecf20Sopenharmony_ci return; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> 2788c2ecf20Sopenharmony_ci DEVID_VENDORID_SHIFT); 2798c2ecf20Sopenharmony_ci device_id = ((reg_data & DEVID_DEVICEID_MASK) >> 2808c2ecf20Sopenharmony_ci DEVID_DEVICEID_SHIFT); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n", 2838c2ecf20Sopenharmony_ci max14577->dev_type, device_id, vendor_id); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * Max77836 specific initialization code for driver probe. 2888c2ecf20Sopenharmony_ci * Adds new I2C dummy device, regmap and regmap IRQ chip. 2898c2ecf20Sopenharmony_ci * Unmasks Interrupt Source register. 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * On success returns 0. 2928c2ecf20Sopenharmony_ci * On failure returns errno and reverts any changes done so far (e.g. remove 2938c2ecf20Sopenharmony_ci * I2C dummy device), except masking the INT SRC register. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_cistatic int max77836_init(struct max14577 *max14577) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int ret; 2988c2ecf20Sopenharmony_ci u8 intsrc_mask; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci max14577->i2c_pmic = i2c_new_dummy_device(max14577->i2c->adapter, 3018c2ecf20Sopenharmony_ci I2C_ADDR_PMIC); 3028c2ecf20Sopenharmony_ci if (IS_ERR(max14577->i2c_pmic)) { 3038c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to register PMIC I2C device\n"); 3048c2ecf20Sopenharmony_ci return PTR_ERR(max14577->i2c_pmic); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci i2c_set_clientdata(max14577->i2c_pmic, max14577); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic, 3098c2ecf20Sopenharmony_ci &max77836_pmic_regmap_config); 3108c2ecf20Sopenharmony_ci if (IS_ERR(max14577->regmap_pmic)) { 3118c2ecf20Sopenharmony_ci ret = PTR_ERR(max14577->regmap_pmic); 3128c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n", 3138c2ecf20Sopenharmony_ci ret); 3148c2ecf20Sopenharmony_ci goto err; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Un-mask MAX77836 Interrupt Source register */ 3188c2ecf20Sopenharmony_ci ret = max14577_read_reg(max14577->regmap_pmic, 3198c2ecf20Sopenharmony_ci MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask); 3208c2ecf20Sopenharmony_ci if (ret < 0) { 3218c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to read PMIC register\n"); 3228c2ecf20Sopenharmony_ci goto err; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK); 3268c2ecf20Sopenharmony_ci intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK); 3278c2ecf20Sopenharmony_ci ret = max14577_write_reg(max14577->regmap_pmic, 3288c2ecf20Sopenharmony_ci MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask); 3298c2ecf20Sopenharmony_ci if (ret < 0) { 3308c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to write PMIC register\n"); 3318c2ecf20Sopenharmony_ci goto err; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq, 3358c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED, 3368c2ecf20Sopenharmony_ci 0, &max77836_pmic_irq_chip, 3378c2ecf20Sopenharmony_ci &max14577->irq_data_pmic); 3388c2ecf20Sopenharmony_ci if (ret != 0) { 3398c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n", 3408c2ecf20Sopenharmony_ci max14577->irq, ret); 3418c2ecf20Sopenharmony_ci goto err; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cierr: 3478c2ecf20Sopenharmony_ci i2c_unregister_device(max14577->i2c_pmic); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Max77836 specific de-initialization code for driver remove. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cistatic void max77836_remove(struct max14577 *max14577) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic); 3588c2ecf20Sopenharmony_ci i2c_unregister_device(max14577->i2c_pmic); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int max14577_i2c_probe(struct i2c_client *i2c, 3628c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct max14577 *max14577; 3658c2ecf20Sopenharmony_ci struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev); 3668c2ecf20Sopenharmony_ci struct device_node *np = i2c->dev.of_node; 3678c2ecf20Sopenharmony_ci int ret = 0; 3688c2ecf20Sopenharmony_ci const struct regmap_irq_chip *irq_chip; 3698c2ecf20Sopenharmony_ci const struct mfd_cell *mfd_devs; 3708c2ecf20Sopenharmony_ci unsigned int mfd_devs_size; 3718c2ecf20Sopenharmony_ci int irq_flags; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (np) { 3748c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); 3758c2ecf20Sopenharmony_ci if (!pdata) 3768c2ecf20Sopenharmony_ci return -ENOMEM; 3778c2ecf20Sopenharmony_ci i2c->dev.platform_data = pdata; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!pdata) { 3818c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "No platform data found.\n"); 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL); 3868c2ecf20Sopenharmony_ci if (!max14577) 3878c2ecf20Sopenharmony_ci return -ENOMEM; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, max14577); 3908c2ecf20Sopenharmony_ci max14577->dev = &i2c->dev; 3918c2ecf20Sopenharmony_ci max14577->i2c = i2c; 3928c2ecf20Sopenharmony_ci max14577->irq = i2c->irq; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci max14577->regmap = devm_regmap_init_i2c(i2c, 3958c2ecf20Sopenharmony_ci &max14577_muic_regmap_config); 3968c2ecf20Sopenharmony_ci if (IS_ERR(max14577->regmap)) { 3978c2ecf20Sopenharmony_ci ret = PTR_ERR(max14577->regmap); 3988c2ecf20Sopenharmony_ci dev_err(max14577->dev, "Failed to allocate register map: %d\n", 3998c2ecf20Sopenharmony_ci ret); 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (np) { 4048c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci of_id = of_match_device(max14577_dt_match, &i2c->dev); 4078c2ecf20Sopenharmony_ci if (of_id) 4088c2ecf20Sopenharmony_ci max14577->dev_type = 4098c2ecf20Sopenharmony_ci (enum maxim_device_type)of_id->data; 4108c2ecf20Sopenharmony_ci } else { 4118c2ecf20Sopenharmony_ci max14577->dev_type = id->driver_data; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci max14577_print_dev_type(max14577); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (max14577->dev_type) { 4178c2ecf20Sopenharmony_ci case MAXIM_DEVICE_TYPE_MAX77836: 4188c2ecf20Sopenharmony_ci irq_chip = &max77836_muic_irq_chip; 4198c2ecf20Sopenharmony_ci mfd_devs = max77836_devs; 4208c2ecf20Sopenharmony_ci mfd_devs_size = ARRAY_SIZE(max77836_devs); 4218c2ecf20Sopenharmony_ci irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED; 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci case MAXIM_DEVICE_TYPE_MAX14577: 4248c2ecf20Sopenharmony_ci default: 4258c2ecf20Sopenharmony_ci irq_chip = &max14577_irq_chip; 4268c2ecf20Sopenharmony_ci mfd_devs = max14577_devs; 4278c2ecf20Sopenharmony_ci mfd_devs_size = ARRAY_SIZE(max14577_devs); 4288c2ecf20Sopenharmony_ci irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, 4338c2ecf20Sopenharmony_ci irq_flags, 0, irq_chip, 4348c2ecf20Sopenharmony_ci &max14577->irq_data); 4358c2ecf20Sopenharmony_ci if (ret != 0) { 4368c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", 4378c2ecf20Sopenharmony_ci max14577->irq, ret); 4388c2ecf20Sopenharmony_ci return ret; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Max77836 specific initialization code (additional regmap) */ 4428c2ecf20Sopenharmony_ci if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) { 4438c2ecf20Sopenharmony_ci ret = max77836_init(max14577); 4448c2ecf20Sopenharmony_ci if (ret < 0) 4458c2ecf20Sopenharmony_ci goto err_max77836; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = mfd_add_devices(max14577->dev, -1, mfd_devs, 4498c2ecf20Sopenharmony_ci mfd_devs_size, NULL, 0, NULL); 4508c2ecf20Sopenharmony_ci if (ret < 0) 4518c2ecf20Sopenharmony_ci goto err_mfd; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci device_init_wakeup(max14577->dev, 1); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cierr_mfd: 4588c2ecf20Sopenharmony_ci if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) 4598c2ecf20Sopenharmony_ci max77836_remove(max14577); 4608c2ecf20Sopenharmony_cierr_max77836: 4618c2ecf20Sopenharmony_ci regmap_del_irq_chip(max14577->irq, max14577->irq_data); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return ret; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int max14577_i2c_remove(struct i2c_client *i2c) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct max14577 *max14577 = i2c_get_clientdata(i2c); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci mfd_remove_devices(max14577->dev); 4718c2ecf20Sopenharmony_ci regmap_del_irq_chip(max14577->irq, max14577->irq_data); 4728c2ecf20Sopenharmony_ci if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) 4738c2ecf20Sopenharmony_ci max77836_remove(max14577); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic const struct i2c_device_id max14577_i2c_id[] = { 4798c2ecf20Sopenharmony_ci { "max14577", MAXIM_DEVICE_TYPE_MAX14577, }, 4808c2ecf20Sopenharmony_ci { "max77836", MAXIM_DEVICE_TYPE_MAX77836, }, 4818c2ecf20Sopenharmony_ci { } 4828c2ecf20Sopenharmony_ci}; 4838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max14577_i2c_id); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4868c2ecf20Sopenharmony_cistatic int max14577_suspend(struct device *dev) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 4898c2ecf20Sopenharmony_ci struct max14577 *max14577 = i2c_get_clientdata(i2c); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 4928c2ecf20Sopenharmony_ci enable_irq_wake(max14577->irq); 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * MUIC IRQ must be disabled during suspend because if it happens 4958c2ecf20Sopenharmony_ci * while suspended it will be handled before resuming I2C. 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * When device is woken up from suspend (e.g. by ADC change), 4988c2ecf20Sopenharmony_ci * an interrupt occurs before resuming I2C bus controller. 4998c2ecf20Sopenharmony_ci * Interrupt handler tries to read registers but this read 5008c2ecf20Sopenharmony_ci * will fail because I2C is still suspended. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci disable_irq(max14577->irq); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int max14577_resume(struct device *dev) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 5108c2ecf20Sopenharmony_ci struct max14577 *max14577 = i2c_get_clientdata(i2c); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 5138c2ecf20Sopenharmony_ci disable_irq_wake(max14577->irq); 5148c2ecf20Sopenharmony_ci enable_irq(max14577->irq); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic struct i2c_driver max14577_i2c_driver = { 5238c2ecf20Sopenharmony_ci .driver = { 5248c2ecf20Sopenharmony_ci .name = "max14577", 5258c2ecf20Sopenharmony_ci .pm = &max14577_pm, 5268c2ecf20Sopenharmony_ci .of_match_table = max14577_dt_match, 5278c2ecf20Sopenharmony_ci }, 5288c2ecf20Sopenharmony_ci .probe = max14577_i2c_probe, 5298c2ecf20Sopenharmony_ci .remove = max14577_i2c_remove, 5308c2ecf20Sopenharmony_ci .id_table = max14577_i2c_id, 5318c2ecf20Sopenharmony_ci}; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic int __init max14577_i2c_init(void) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM); 5368c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Valid charger current values must be provided for each chipset */ 5398c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Check for valid values for charger */ 5428c2ecf20Sopenharmony_ci BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START + 5438c2ecf20Sopenharmony_ci MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf != 5448c2ecf20Sopenharmony_ci MAX14577_CHARGER_CURRENT_LIMIT_MAX); 5458c2ecf20Sopenharmony_ci BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START + 5488c2ecf20Sopenharmony_ci MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf != 5498c2ecf20Sopenharmony_ci MAX77836_CHARGER_CURRENT_LIMIT_MAX); 5508c2ecf20Sopenharmony_ci BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return i2c_add_driver(&max14577_i2c_driver); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_cimodule_init(max14577_i2c_init); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void __exit max14577_i2c_exit(void) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci i2c_del_driver(&max14577_i2c_driver); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_cimodule_exit(max14577_i2c_exit); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>"); 5638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver"); 5648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 565