18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Maxim MAX77620 MFD Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: 88c2ecf20Sopenharmony_ci * Laxman Dewangan <ldewangan@nvidia.com> 98c2ecf20Sopenharmony_ci * Chaitanya Bandi <bandik@nvidia.com> 108c2ecf20Sopenharmony_ci * Mallikarjun Kasoju <mkasoju@nvidia.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/****************** Teminology used in driver ******************** 148c2ecf20Sopenharmony_ci * Here are some terminology used from datasheet for quick reference: 158c2ecf20Sopenharmony_ci * Flexible Power Sequence (FPS): 168c2ecf20Sopenharmony_ci * The Flexible Power Sequencer (FPS) allows each regulator to power up under 178c2ecf20Sopenharmony_ci * hardware or software control. Additionally, each regulator can power on 188c2ecf20Sopenharmony_ci * independently or among a group of other regulators with an adjustable 198c2ecf20Sopenharmony_ci * power-up and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can 208c2ecf20Sopenharmony_ci * be programmed to be part of a sequence allowing external regulators to be 218c2ecf20Sopenharmony_ci * sequenced along with internal regulators. 32KHz clock can be programmed to 228c2ecf20Sopenharmony_ci * be part of a sequence. 238c2ecf20Sopenharmony_ci * There is 3 FPS confguration registers and all resources are configured to 248c2ecf20Sopenharmony_ci * any of these FPS or no FPS. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/i2c.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 308c2ecf20Sopenharmony_ci#include <linux/mfd/max77620.h> 318c2ecf20Sopenharmony_ci#include <linux/init.h> 328c2ecf20Sopenharmony_ci#include <linux/of.h> 338c2ecf20Sopenharmony_ci#include <linux/of_device.h> 348c2ecf20Sopenharmony_ci#include <linux/regmap.h> 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct max77620_chip *max77620_scratch; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct resource gpio_resources[] = { 408c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const struct resource power_resources[] = { 448c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(MAX77620_IRQ_LBT_MBATLOW), 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic const struct resource rtc_resources[] = { 488c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(MAX77620_IRQ_TOP_RTC), 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const struct resource thermal_resources[] = { 528c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM1), 538c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2), 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const struct regmap_irq max77620_top_irqs[] = { 578c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK), 588c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK), 598c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_LDO, 0, MAX77620_IRQ_TOP_LDO_MASK), 608c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GPIO, 0, MAX77620_IRQ_TOP_GPIO_MASK), 618c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_RTC, 0, MAX77620_IRQ_TOP_RTC_MASK), 628c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_32K, 0, MAX77620_IRQ_TOP_32K_MASK), 638c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_TOP_ONOFF, 0, MAX77620_IRQ_TOP_ONOFF_MASK), 648c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK), 658c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK), 668c2ecf20Sopenharmony_ci REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK), 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const struct mfd_cell max77620_children[] = { 708c2ecf20Sopenharmony_ci { .name = "max77620-pinctrl", }, 718c2ecf20Sopenharmony_ci { .name = "max77620-clock", }, 728c2ecf20Sopenharmony_ci { .name = "max77620-pmic", }, 738c2ecf20Sopenharmony_ci { .name = "max77620-watchdog", }, 748c2ecf20Sopenharmony_ci { 758c2ecf20Sopenharmony_ci .name = "max77620-gpio", 768c2ecf20Sopenharmony_ci .resources = gpio_resources, 778c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(gpio_resources), 788c2ecf20Sopenharmony_ci }, { 798c2ecf20Sopenharmony_ci .name = "max77620-rtc", 808c2ecf20Sopenharmony_ci .resources = rtc_resources, 818c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(rtc_resources), 828c2ecf20Sopenharmony_ci }, { 838c2ecf20Sopenharmony_ci .name = "max77620-power", 848c2ecf20Sopenharmony_ci .resources = power_resources, 858c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(power_resources), 868c2ecf20Sopenharmony_ci }, { 878c2ecf20Sopenharmony_ci .name = "max77620-thermal", 888c2ecf20Sopenharmony_ci .resources = thermal_resources, 898c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(thermal_resources), 908c2ecf20Sopenharmony_ci }, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic const struct mfd_cell max20024_children[] = { 948c2ecf20Sopenharmony_ci { .name = "max20024-pinctrl", }, 958c2ecf20Sopenharmony_ci { .name = "max77620-clock", }, 968c2ecf20Sopenharmony_ci { .name = "max20024-pmic", }, 978c2ecf20Sopenharmony_ci { .name = "max77620-watchdog", }, 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci .name = "max77620-gpio", 1008c2ecf20Sopenharmony_ci .resources = gpio_resources, 1018c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(gpio_resources), 1028c2ecf20Sopenharmony_ci }, { 1038c2ecf20Sopenharmony_ci .name = "max77620-rtc", 1048c2ecf20Sopenharmony_ci .resources = rtc_resources, 1058c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(rtc_resources), 1068c2ecf20Sopenharmony_ci }, { 1078c2ecf20Sopenharmony_ci .name = "max20024-power", 1088c2ecf20Sopenharmony_ci .resources = power_resources, 1098c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(power_resources), 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic const struct mfd_cell max77663_children[] = { 1148c2ecf20Sopenharmony_ci { .name = "max77620-pinctrl", }, 1158c2ecf20Sopenharmony_ci { .name = "max77620-clock", }, 1168c2ecf20Sopenharmony_ci { .name = "max77663-pmic", }, 1178c2ecf20Sopenharmony_ci { .name = "max77620-watchdog", }, 1188c2ecf20Sopenharmony_ci { 1198c2ecf20Sopenharmony_ci .name = "max77620-gpio", 1208c2ecf20Sopenharmony_ci .resources = gpio_resources, 1218c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(gpio_resources), 1228c2ecf20Sopenharmony_ci }, { 1238c2ecf20Sopenharmony_ci .name = "max77620-rtc", 1248c2ecf20Sopenharmony_ci .resources = rtc_resources, 1258c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(rtc_resources), 1268c2ecf20Sopenharmony_ci }, { 1278c2ecf20Sopenharmony_ci .name = "max77663-power", 1288c2ecf20Sopenharmony_ci .resources = power_resources, 1298c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(power_resources), 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic const struct regmap_range max77620_readable_ranges[] = { 1348c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct regmap_access_table max77620_readable_table = { 1388c2ecf20Sopenharmony_ci .yes_ranges = max77620_readable_ranges, 1398c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(max77620_readable_ranges), 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic const struct regmap_range max20024_readable_ranges[] = { 1438c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), 1448c2ecf20Sopenharmony_ci regmap_reg_range(MAX20024_REG_MAX_ADD, MAX20024_REG_MAX_ADD), 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic const struct regmap_access_table max20024_readable_table = { 1488c2ecf20Sopenharmony_ci .yes_ranges = max20024_readable_ranges, 1498c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(max20024_readable_ranges), 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct regmap_range max77620_writable_ranges[] = { 1538c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct regmap_access_table max77620_writable_table = { 1578c2ecf20Sopenharmony_ci .yes_ranges = max77620_writable_ranges, 1588c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(max77620_writable_ranges), 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const struct regmap_range max77620_cacheable_ranges[] = { 1628c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_SD0_CFG, MAX77620_REG_LDO_CFG3), 1638c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_FPS_CFG0, MAX77620_REG_FPS_SD3), 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic const struct regmap_access_table max77620_volatile_table = { 1678c2ecf20Sopenharmony_ci .no_ranges = max77620_cacheable_ranges, 1688c2ecf20Sopenharmony_ci .n_no_ranges = ARRAY_SIZE(max77620_cacheable_ranges), 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic const struct regmap_config max77620_regmap_config = { 1728c2ecf20Sopenharmony_ci .name = "power-slave", 1738c2ecf20Sopenharmony_ci .reg_bits = 8, 1748c2ecf20Sopenharmony_ci .val_bits = 8, 1758c2ecf20Sopenharmony_ci .max_register = MAX77620_REG_DVSSD4 + 1, 1768c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1778c2ecf20Sopenharmony_ci .rd_table = &max77620_readable_table, 1788c2ecf20Sopenharmony_ci .wr_table = &max77620_writable_table, 1798c2ecf20Sopenharmony_ci .volatile_table = &max77620_volatile_table, 1808c2ecf20Sopenharmony_ci .use_single_write = true, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct regmap_config max20024_regmap_config = { 1848c2ecf20Sopenharmony_ci .name = "power-slave", 1858c2ecf20Sopenharmony_ci .reg_bits = 8, 1868c2ecf20Sopenharmony_ci .val_bits = 8, 1878c2ecf20Sopenharmony_ci .max_register = MAX20024_REG_MAX_ADD + 1, 1888c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1898c2ecf20Sopenharmony_ci .rd_table = &max20024_readable_table, 1908c2ecf20Sopenharmony_ci .wr_table = &max77620_writable_table, 1918c2ecf20Sopenharmony_ci .volatile_table = &max77620_volatile_table, 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct regmap_range max77663_readable_ranges[] = { 1958c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic const struct regmap_access_table max77663_readable_table = { 1998c2ecf20Sopenharmony_ci .yes_ranges = max77663_readable_ranges, 2008c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(max77663_readable_ranges), 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const struct regmap_range max77663_writable_ranges[] = { 2048c2ecf20Sopenharmony_ci regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic const struct regmap_access_table max77663_writable_table = { 2088c2ecf20Sopenharmony_ci .yes_ranges = max77663_writable_ranges, 2098c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(max77663_writable_ranges), 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct regmap_config max77663_regmap_config = { 2138c2ecf20Sopenharmony_ci .name = "power-slave", 2148c2ecf20Sopenharmony_ci .reg_bits = 8, 2158c2ecf20Sopenharmony_ci .val_bits = 8, 2168c2ecf20Sopenharmony_ci .max_register = MAX77620_REG_CID5 + 1, 2178c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 2188c2ecf20Sopenharmony_ci .rd_table = &max77663_readable_table, 2198c2ecf20Sopenharmony_ci .wr_table = &max77663_writable_table, 2208c2ecf20Sopenharmony_ci .volatile_table = &max77620_volatile_table, 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * MAX77620 and MAX20024 has the following steps of the interrupt handling 2258c2ecf20Sopenharmony_ci * for TOP interrupts: 2268c2ecf20Sopenharmony_ci * 1. When interrupt occurs from PMIC, mask the PMIC interrupt by setting GLBLM. 2278c2ecf20Sopenharmony_ci * 2. Read IRQTOP and service the interrupt. 2288c2ecf20Sopenharmony_ci * 3. Once all interrupts has been checked and serviced, the interrupt service 2298c2ecf20Sopenharmony_ci * routine un-masks the hardware interrupt line by clearing GLBLM. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistatic int max77620_irq_global_mask(void *irq_drv_data) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct max77620_chip *chip = irq_drv_data; 2348c2ecf20Sopenharmony_ci int ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, 2378c2ecf20Sopenharmony_ci MAX77620_GLBLM_MASK, MAX77620_GLBLM_MASK); 2388c2ecf20Sopenharmony_ci if (ret < 0) 2398c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to set GLBLM: %d\n", ret); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int max77620_irq_global_unmask(void *irq_drv_data) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct max77620_chip *chip = irq_drv_data; 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, 2508c2ecf20Sopenharmony_ci MAX77620_GLBLM_MASK, 0); 2518c2ecf20Sopenharmony_ci if (ret < 0) 2528c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to reset GLBLM: %d\n", ret); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct regmap_irq_chip max77620_top_irq_chip = { 2588c2ecf20Sopenharmony_ci .name = "max77620-top", 2598c2ecf20Sopenharmony_ci .irqs = max77620_top_irqs, 2608c2ecf20Sopenharmony_ci .num_irqs = ARRAY_SIZE(max77620_top_irqs), 2618c2ecf20Sopenharmony_ci .num_regs = 2, 2628c2ecf20Sopenharmony_ci .status_base = MAX77620_REG_IRQTOP, 2638c2ecf20Sopenharmony_ci .mask_base = MAX77620_REG_IRQTOPM, 2648c2ecf20Sopenharmony_ci .handle_pre_irq = max77620_irq_global_mask, 2658c2ecf20Sopenharmony_ci .handle_post_irq = max77620_irq_global_unmask, 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* max77620_get_fps_period_reg_value: Get FPS bit field value from 2698c2ecf20Sopenharmony_ci * requested periods. 2708c2ecf20Sopenharmony_ci * MAX77620 supports the FPS period of 40, 80, 160, 320, 540, 1280, 2560 2718c2ecf20Sopenharmony_ci * and 5120 microseconds. MAX20024 supports the FPS period of 20, 40, 80, 2728c2ecf20Sopenharmony_ci * 160, 320, 540, 1280 and 2560 microseconds. 2738c2ecf20Sopenharmony_ci * The FPS register has 3 bits field to set the FPS period as 2748c2ecf20Sopenharmony_ci * bits max77620 max20024 2758c2ecf20Sopenharmony_ci * 000 40 20 2768c2ecf20Sopenharmony_ci * 001 80 40 2778c2ecf20Sopenharmony_ci * ::: 2788c2ecf20Sopenharmony_ci*/ 2798c2ecf20Sopenharmony_cistatic int max77620_get_fps_period_reg_value(struct max77620_chip *chip, 2808c2ecf20Sopenharmony_ci int tperiod) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci int fps_min_period; 2838c2ecf20Sopenharmony_ci int i; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci switch (chip->chip_id) { 2868c2ecf20Sopenharmony_ci case MAX20024: 2878c2ecf20Sopenharmony_ci fps_min_period = MAX20024_FPS_PERIOD_MIN_US; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case MAX77620: 2908c2ecf20Sopenharmony_ci fps_min_period = MAX77620_FPS_PERIOD_MIN_US; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci case MAX77663: 2938c2ecf20Sopenharmony_ci fps_min_period = MAX20024_FPS_PERIOD_MIN_US; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci default: 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 3008c2ecf20Sopenharmony_ci if (fps_min_period >= tperiod) 3018c2ecf20Sopenharmony_ci return i; 3028c2ecf20Sopenharmony_ci fps_min_period *= 2; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return i; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* max77620_config_fps: Configure FPS configuration registers 3098c2ecf20Sopenharmony_ci * based on platform specific information. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic int max77620_config_fps(struct max77620_chip *chip, 3128c2ecf20Sopenharmony_ci struct device_node *fps_np) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct device *dev = chip->dev; 3158c2ecf20Sopenharmony_ci unsigned int mask = 0, config = 0; 3168c2ecf20Sopenharmony_ci u32 fps_max_period; 3178c2ecf20Sopenharmony_ci u32 param_val; 3188c2ecf20Sopenharmony_ci int tperiod, fps_id; 3198c2ecf20Sopenharmony_ci int ret; 3208c2ecf20Sopenharmony_ci char fps_name[10]; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci switch (chip->chip_id) { 3238c2ecf20Sopenharmony_ci case MAX20024: 3248c2ecf20Sopenharmony_ci fps_max_period = MAX20024_FPS_PERIOD_MAX_US; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case MAX77620: 3278c2ecf20Sopenharmony_ci fps_max_period = MAX77620_FPS_PERIOD_MAX_US; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case MAX77663: 3308c2ecf20Sopenharmony_ci fps_max_period = MAX20024_FPS_PERIOD_MAX_US; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci default: 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { 3378c2ecf20Sopenharmony_ci sprintf(fps_name, "fps%d", fps_id); 3388c2ecf20Sopenharmony_ci if (of_node_name_eq(fps_np, fps_name)) 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (fps_id == MAX77620_FPS_COUNT) { 3438c2ecf20Sopenharmony_ci dev_err(dev, "FPS node name %pOFn is not valid\n", fps_np); 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = of_property_read_u32(fps_np, "maxim,shutdown-fps-time-period-us", 3488c2ecf20Sopenharmony_ci ¶m_val); 3498c2ecf20Sopenharmony_ci if (!ret) { 3508c2ecf20Sopenharmony_ci mask |= MAX77620_FPS_TIME_PERIOD_MASK; 3518c2ecf20Sopenharmony_ci chip->shutdown_fps_period[fps_id] = min(param_val, 3528c2ecf20Sopenharmony_ci fps_max_period); 3538c2ecf20Sopenharmony_ci tperiod = max77620_get_fps_period_reg_value(chip, 3548c2ecf20Sopenharmony_ci chip->shutdown_fps_period[fps_id]); 3558c2ecf20Sopenharmony_ci config |= tperiod << MAX77620_FPS_TIME_PERIOD_SHIFT; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = of_property_read_u32(fps_np, "maxim,suspend-fps-time-period-us", 3598c2ecf20Sopenharmony_ci ¶m_val); 3608c2ecf20Sopenharmony_ci if (!ret) 3618c2ecf20Sopenharmony_ci chip->suspend_fps_period[fps_id] = min(param_val, 3628c2ecf20Sopenharmony_ci fps_max_period); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = of_property_read_u32(fps_np, "maxim,fps-event-source", 3658c2ecf20Sopenharmony_ci ¶m_val); 3668c2ecf20Sopenharmony_ci if (!ret) { 3678c2ecf20Sopenharmony_ci if (param_val > 2) { 3688c2ecf20Sopenharmony_ci dev_err(dev, "FPS%d event-source invalid\n", fps_id); 3698c2ecf20Sopenharmony_ci return -EINVAL; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci mask |= MAX77620_FPS_EN_SRC_MASK; 3728c2ecf20Sopenharmony_ci config |= param_val << MAX77620_FPS_EN_SRC_SHIFT; 3738c2ecf20Sopenharmony_ci if (param_val == 2) { 3748c2ecf20Sopenharmony_ci mask |= MAX77620_FPS_ENFPS_SW_MASK; 3758c2ecf20Sopenharmony_ci config |= MAX77620_FPS_ENFPS_SW; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!chip->sleep_enable && !chip->enable_global_lpm) { 3808c2ecf20Sopenharmony_ci ret = of_property_read_u32(fps_np, 3818c2ecf20Sopenharmony_ci "maxim,device-state-on-disabled-event", 3828c2ecf20Sopenharmony_ci ¶m_val); 3838c2ecf20Sopenharmony_ci if (!ret) { 3848c2ecf20Sopenharmony_ci if (param_val == 0) 3858c2ecf20Sopenharmony_ci chip->sleep_enable = true; 3868c2ecf20Sopenharmony_ci else if (param_val == 1) 3878c2ecf20Sopenharmony_ci chip->enable_global_lpm = true; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, 3928c2ecf20Sopenharmony_ci mask, config); 3938c2ecf20Sopenharmony_ci if (ret < 0) { 3948c2ecf20Sopenharmony_ci dev_err(dev, "Failed to update FPS CFG: %d\n", ret); 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int max77620_initialise_fps(struct max77620_chip *chip) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct device *dev = chip->dev; 4048c2ecf20Sopenharmony_ci struct device_node *fps_np, *fps_child; 4058c2ecf20Sopenharmony_ci u8 config; 4068c2ecf20Sopenharmony_ci int fps_id; 4078c2ecf20Sopenharmony_ci int ret; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { 4108c2ecf20Sopenharmony_ci chip->shutdown_fps_period[fps_id] = -1; 4118c2ecf20Sopenharmony_ci chip->suspend_fps_period[fps_id] = -1; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci fps_np = of_get_child_by_name(dev->of_node, "fps"); 4158c2ecf20Sopenharmony_ci if (!fps_np) 4168c2ecf20Sopenharmony_ci goto skip_fps; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci for_each_child_of_node(fps_np, fps_child) { 4198c2ecf20Sopenharmony_ci ret = max77620_config_fps(chip, fps_child); 4208c2ecf20Sopenharmony_ci if (ret < 0) { 4218c2ecf20Sopenharmony_ci of_node_put(fps_child); 4228c2ecf20Sopenharmony_ci of_node_put(fps_np); 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci of_node_put(fps_np); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0; 4298c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, 4308c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_SLP_LPM_MSK, config); 4318c2ecf20Sopenharmony_ci if (ret < 0) { 4328c2ecf20Sopenharmony_ci dev_err(dev, "Failed to update SLP_LPM: %d\n", ret); 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciskip_fps: 4378c2ecf20Sopenharmony_ci if (chip->chip_id == MAX77663) 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Enable wake on EN0 pin */ 4418c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, 4428c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_WK_EN0, 4438c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_WK_EN0); 4448c2ecf20Sopenharmony_ci if (ret < 0) { 4458c2ecf20Sopenharmony_ci dev_err(dev, "Failed to update WK_EN0: %d\n", ret); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* For MAX20024, SLPEN will be POR reset if CLRSE is b11 */ 4508c2ecf20Sopenharmony_ci if ((chip->chip_id == MAX20024) && chip->sleep_enable) { 4518c2ecf20Sopenharmony_ci config = MAX77620_ONOFFCNFG1_SLPEN | MAX20024_ONOFFCNFG1_CLRSE; 4528c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, 4538c2ecf20Sopenharmony_ci config, config); 4548c2ecf20Sopenharmony_ci if (ret < 0) { 4558c2ecf20Sopenharmony_ci dev_err(dev, "Failed to update SLPEN: %d\n", ret); 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int max77620_read_es_version(struct max77620_chip *chip) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci unsigned int val; 4668c2ecf20Sopenharmony_ci u8 cid_val[6]; 4678c2ecf20Sopenharmony_ci int i; 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci for (i = MAX77620_REG_CID0; i <= MAX77620_REG_CID5; i++) { 4718c2ecf20Sopenharmony_ci ret = regmap_read(chip->rmap, i, &val); 4728c2ecf20Sopenharmony_ci if (ret < 0) { 4738c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to read CID: %d\n", ret); 4748c2ecf20Sopenharmony_ci return ret; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "CID%d: 0x%02x\n", 4778c2ecf20Sopenharmony_ci i - MAX77620_REG_CID0, val); 4788c2ecf20Sopenharmony_ci cid_val[i - MAX77620_REG_CID0] = val; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* CID4 is OTP Version and CID5 is ES version */ 4828c2ecf20Sopenharmony_ci dev_info(chip->dev, "PMIC Version OTP:0x%02X and ES:0x%X\n", 4838c2ecf20Sopenharmony_ci cid_val[4], MAX77620_CID5_DIDM(cid_val[5])); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void max77620_pm_power_off(void) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct max77620_chip *chip = max77620_scratch; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, 4938c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG1_SFT_RST, 4948c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG1_SFT_RST); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int max77620_probe(struct i2c_client *client, 4988c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci const struct regmap_config *rmap_config; 5018c2ecf20Sopenharmony_ci struct max77620_chip *chip; 5028c2ecf20Sopenharmony_ci const struct mfd_cell *mfd_cells; 5038c2ecf20Sopenharmony_ci int n_mfd_cells; 5048c2ecf20Sopenharmony_ci bool pm_off; 5058c2ecf20Sopenharmony_ci int ret; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 5088c2ecf20Sopenharmony_ci if (!chip) 5098c2ecf20Sopenharmony_ci return -ENOMEM; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci i2c_set_clientdata(client, chip); 5128c2ecf20Sopenharmony_ci chip->dev = &client->dev; 5138c2ecf20Sopenharmony_ci chip->chip_irq = client->irq; 5148c2ecf20Sopenharmony_ci chip->chip_id = (enum max77620_chip_id)id->driver_data; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci switch (chip->chip_id) { 5178c2ecf20Sopenharmony_ci case MAX77620: 5188c2ecf20Sopenharmony_ci mfd_cells = max77620_children; 5198c2ecf20Sopenharmony_ci n_mfd_cells = ARRAY_SIZE(max77620_children); 5208c2ecf20Sopenharmony_ci rmap_config = &max77620_regmap_config; 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case MAX20024: 5238c2ecf20Sopenharmony_ci mfd_cells = max20024_children; 5248c2ecf20Sopenharmony_ci n_mfd_cells = ARRAY_SIZE(max20024_children); 5258c2ecf20Sopenharmony_ci rmap_config = &max20024_regmap_config; 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci case MAX77663: 5288c2ecf20Sopenharmony_ci mfd_cells = max77663_children; 5298c2ecf20Sopenharmony_ci n_mfd_cells = ARRAY_SIZE(max77663_children); 5308c2ecf20Sopenharmony_ci rmap_config = &max77663_regmap_config; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci default: 5338c2ecf20Sopenharmony_ci dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id); 5348c2ecf20Sopenharmony_ci return -EINVAL; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci chip->rmap = devm_regmap_init_i2c(client, rmap_config); 5388c2ecf20Sopenharmony_ci if (IS_ERR(chip->rmap)) { 5398c2ecf20Sopenharmony_ci ret = PTR_ERR(chip->rmap); 5408c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to initialise regmap: %d\n", ret); 5418c2ecf20Sopenharmony_ci return ret; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ret = max77620_read_es_version(chip); 5458c2ecf20Sopenharmony_ci if (ret < 0) 5468c2ecf20Sopenharmony_ci return ret; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci max77620_top_irq_chip.irq_drv_data = chip; 5498c2ecf20Sopenharmony_ci ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, 5508c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 0, 5518c2ecf20Sopenharmony_ci &max77620_top_irq_chip, 5528c2ecf20Sopenharmony_ci &chip->top_irq_data); 5538c2ecf20Sopenharmony_ci if (ret < 0) { 5548c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = max77620_initialise_fps(chip); 5598c2ecf20Sopenharmony_ci if (ret < 0) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci ret = devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, 5638c2ecf20Sopenharmony_ci mfd_cells, n_mfd_cells, NULL, 0, 5648c2ecf20Sopenharmony_ci regmap_irq_get_domain(chip->top_irq_data)); 5658c2ecf20Sopenharmony_ci if (ret < 0) { 5668c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to add MFD children: %d\n", ret); 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci pm_off = of_device_is_system_power_controller(client->dev.of_node); 5718c2ecf20Sopenharmony_ci if (pm_off && !pm_power_off) { 5728c2ecf20Sopenharmony_ci max77620_scratch = chip; 5738c2ecf20Sopenharmony_ci pm_power_off = max77620_pm_power_off; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 5808c2ecf20Sopenharmony_cistatic int max77620_set_fps_period(struct max77620_chip *chip, 5818c2ecf20Sopenharmony_ci int fps_id, int time_period) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci int period = max77620_get_fps_period_reg_value(chip, time_period); 5848c2ecf20Sopenharmony_ci int ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, 5878c2ecf20Sopenharmony_ci MAX77620_FPS_TIME_PERIOD_MASK, 5888c2ecf20Sopenharmony_ci period << MAX77620_FPS_TIME_PERIOD_SHIFT); 5898c2ecf20Sopenharmony_ci if (ret < 0) { 5908c2ecf20Sopenharmony_ci dev_err(chip->dev, "Failed to update FPS period: %d\n", ret); 5918c2ecf20Sopenharmony_ci return ret; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int max77620_i2c_suspend(struct device *dev) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct max77620_chip *chip = dev_get_drvdata(dev); 6008c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 6018c2ecf20Sopenharmony_ci unsigned int config; 6028c2ecf20Sopenharmony_ci int fps; 6038c2ecf20Sopenharmony_ci int ret; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { 6068c2ecf20Sopenharmony_ci if (chip->suspend_fps_period[fps] < 0) 6078c2ecf20Sopenharmony_ci continue; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci ret = max77620_set_fps_period(chip, fps, 6108c2ecf20Sopenharmony_ci chip->suspend_fps_period[fps]); 6118c2ecf20Sopenharmony_ci if (ret < 0) 6128c2ecf20Sopenharmony_ci return ret; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * For MAX20024: No need to configure SLPEN on suspend as 6178c2ecf20Sopenharmony_ci * it will be configured on Init. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci if (chip->chip_id == MAX20024) 6208c2ecf20Sopenharmony_ci goto out; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci config = (chip->sleep_enable) ? MAX77620_ONOFFCNFG1_SLPEN : 0; 6238c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, 6248c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG1_SLPEN, 6258c2ecf20Sopenharmony_ci config); 6268c2ecf20Sopenharmony_ci if (ret < 0) { 6278c2ecf20Sopenharmony_ci dev_err(dev, "Failed to configure sleep in suspend: %d\n", ret); 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (chip->chip_id == MAX77663) 6328c2ecf20Sopenharmony_ci goto out; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Disable WK_EN0 */ 6358c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, 6368c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_WK_EN0, 0); 6378c2ecf20Sopenharmony_ci if (ret < 0) { 6388c2ecf20Sopenharmony_ci dev_err(dev, "Failed to configure WK_EN in suspend: %d\n", ret); 6398c2ecf20Sopenharmony_ci return ret; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ciout: 6438c2ecf20Sopenharmony_ci disable_irq(client->irq); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int max77620_i2c_resume(struct device *dev) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct max77620_chip *chip = dev_get_drvdata(dev); 6518c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 6528c2ecf20Sopenharmony_ci int ret; 6538c2ecf20Sopenharmony_ci int fps; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { 6568c2ecf20Sopenharmony_ci if (chip->shutdown_fps_period[fps] < 0) 6578c2ecf20Sopenharmony_ci continue; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci ret = max77620_set_fps_period(chip, fps, 6608c2ecf20Sopenharmony_ci chip->shutdown_fps_period[fps]); 6618c2ecf20Sopenharmony_ci if (ret < 0) 6628c2ecf20Sopenharmony_ci return ret; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* 6668c2ecf20Sopenharmony_ci * For MAX20024: No need to configure WKEN0 on resume as 6678c2ecf20Sopenharmony_ci * it is configured on Init. 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci if (chip->chip_id == MAX20024 || chip->chip_id == MAX77663) 6708c2ecf20Sopenharmony_ci goto out; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Enable WK_EN0 */ 6738c2ecf20Sopenharmony_ci ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, 6748c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_WK_EN0, 6758c2ecf20Sopenharmony_ci MAX77620_ONOFFCNFG2_WK_EN0); 6768c2ecf20Sopenharmony_ci if (ret < 0) { 6778c2ecf20Sopenharmony_ci dev_err(dev, "Failed to configure WK_EN0 n resume: %d\n", ret); 6788c2ecf20Sopenharmony_ci return ret; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ciout: 6828c2ecf20Sopenharmony_ci enable_irq(client->irq); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci#endif 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic const struct i2c_device_id max77620_id[] = { 6898c2ecf20Sopenharmony_ci {"max77620", MAX77620}, 6908c2ecf20Sopenharmony_ci {"max20024", MAX20024}, 6918c2ecf20Sopenharmony_ci {"max77663", MAX77663}, 6928c2ecf20Sopenharmony_ci {}, 6938c2ecf20Sopenharmony_ci}; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic const struct dev_pm_ops max77620_pm_ops = { 6968c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(max77620_i2c_suspend, max77620_i2c_resume) 6978c2ecf20Sopenharmony_ci}; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic struct i2c_driver max77620_driver = { 7008c2ecf20Sopenharmony_ci .driver = { 7018c2ecf20Sopenharmony_ci .name = "max77620", 7028c2ecf20Sopenharmony_ci .pm = &max77620_pm_ops, 7038c2ecf20Sopenharmony_ci }, 7048c2ecf20Sopenharmony_ci .probe = max77620_probe, 7058c2ecf20Sopenharmony_ci .id_table = max77620_id, 7068c2ecf20Sopenharmony_ci}; 7078c2ecf20Sopenharmony_cibuiltin_i2c_driver(max77620_driver); 708