18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Maxim MAX77620 Regulator driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Mallikarjun Kasoju <mkasoju@nvidia.com> 88c2ecf20Sopenharmony_ci * Laxman Dewangan <ldewangan@nvidia.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/max77620.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/regmap.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define max77620_rails(_name) "max77620-"#_name 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Power Mode */ 248c2ecf20Sopenharmony_ci#define MAX77620_POWER_MODE_NORMAL 3 258c2ecf20Sopenharmony_ci#define MAX77620_POWER_MODE_LPM 2 268c2ecf20Sopenharmony_ci#define MAX77620_POWER_MODE_GLPM 1 278c2ecf20Sopenharmony_ci#define MAX77620_POWER_MODE_DISABLE 0 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* SD Slew Rate */ 308c2ecf20Sopenharmony_ci#define MAX77620_SD_SR_13_75 0 318c2ecf20Sopenharmony_ci#define MAX77620_SD_SR_27_5 1 328c2ecf20Sopenharmony_ci#define MAX77620_SD_SR_55 2 338c2ecf20Sopenharmony_ci#define MAX77620_SD_SR_100 3 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cienum max77620_regulators { 368c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_SD0, 378c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_SD1, 388c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_SD2, 398c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_SD3, 408c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_SD4, 418c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO0, 428c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO1, 438c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO2, 448c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO3, 458c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO4, 468c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO5, 478c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO6, 488c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO7, 498c2ecf20Sopenharmony_ci MAX77620_REGULATOR_ID_LDO8, 508c2ecf20Sopenharmony_ci MAX77620_NUM_REGS, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Regulator types */ 548c2ecf20Sopenharmony_cienum max77620_regulator_type { 558c2ecf20Sopenharmony_ci MAX77620_REGULATOR_TYPE_SD, 568c2ecf20Sopenharmony_ci MAX77620_REGULATOR_TYPE_LDO_N, 578c2ecf20Sopenharmony_ci MAX77620_REGULATOR_TYPE_LDO_P, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct max77620_regulator_info { 618c2ecf20Sopenharmony_ci u8 type; 628c2ecf20Sopenharmony_ci u8 fps_addr; 638c2ecf20Sopenharmony_ci u8 volt_addr; 648c2ecf20Sopenharmony_ci u8 cfg_addr; 658c2ecf20Sopenharmony_ci u8 power_mode_mask; 668c2ecf20Sopenharmony_ci u8 power_mode_shift; 678c2ecf20Sopenharmony_ci u8 remote_sense_addr; 688c2ecf20Sopenharmony_ci u8 remote_sense_mask; 698c2ecf20Sopenharmony_ci struct regulator_desc desc; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct max77620_regulator_pdata { 738c2ecf20Sopenharmony_ci int active_fps_src; 748c2ecf20Sopenharmony_ci int active_fps_pd_slot; 758c2ecf20Sopenharmony_ci int active_fps_pu_slot; 768c2ecf20Sopenharmony_ci int suspend_fps_src; 778c2ecf20Sopenharmony_ci int suspend_fps_pd_slot; 788c2ecf20Sopenharmony_ci int suspend_fps_pu_slot; 798c2ecf20Sopenharmony_ci int current_mode; 808c2ecf20Sopenharmony_ci int power_ok; 818c2ecf20Sopenharmony_ci int ramp_rate_setting; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct max77620_regulator { 858c2ecf20Sopenharmony_ci struct device *dev; 868c2ecf20Sopenharmony_ci struct regmap *rmap; 878c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo[MAX77620_NUM_REGS]; 888c2ecf20Sopenharmony_ci struct max77620_regulator_pdata reg_pdata[MAX77620_NUM_REGS]; 898c2ecf20Sopenharmony_ci int enable_power_mode[MAX77620_NUM_REGS]; 908c2ecf20Sopenharmony_ci int current_power_mode[MAX77620_NUM_REGS]; 918c2ecf20Sopenharmony_ci int active_fps_src[MAX77620_NUM_REGS]; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define fps_src_name(fps_src) \ 958c2ecf20Sopenharmony_ci (fps_src == MAX77620_FPS_SRC_0 ? "FPS_SRC_0" : \ 968c2ecf20Sopenharmony_ci fps_src == MAX77620_FPS_SRC_1 ? "FPS_SRC_1" : \ 978c2ecf20Sopenharmony_ci fps_src == MAX77620_FPS_SRC_2 ? "FPS_SRC_2" : "FPS_SRC_NONE") 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int max77620_regulator_get_fps_src(struct max77620_regulator *pmic, 1008c2ecf20Sopenharmony_ci int id) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 1038c2ecf20Sopenharmony_ci unsigned int val; 1048c2ecf20Sopenharmony_ci int ret; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); 1078c2ecf20Sopenharmony_ci if (ret < 0) { 1088c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", 1098c2ecf20Sopenharmony_ci rinfo->fps_addr, ret); 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int max77620_regulator_set_fps_src(struct max77620_regulator *pmic, 1178c2ecf20Sopenharmony_ci int fps_src, int id) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 1208c2ecf20Sopenharmony_ci unsigned int val; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!rinfo) 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci switch (fps_src) { 1278c2ecf20Sopenharmony_ci case MAX77620_FPS_SRC_0: 1288c2ecf20Sopenharmony_ci case MAX77620_FPS_SRC_1: 1298c2ecf20Sopenharmony_ci case MAX77620_FPS_SRC_2: 1308c2ecf20Sopenharmony_ci case MAX77620_FPS_SRC_NONE: 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci case MAX77620_FPS_SRC_DEF: 1348c2ecf20Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->fps_addr, &val); 1358c2ecf20Sopenharmony_ci if (ret < 0) { 1368c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", 1378c2ecf20Sopenharmony_ci rinfo->fps_addr, ret); 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci ret = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 1418c2ecf20Sopenharmony_ci pmic->active_fps_src[id] = ret; 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci default: 1458c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Invalid FPS %d for regulator %d\n", 1468c2ecf20Sopenharmony_ci fps_src, id); 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, 1518c2ecf20Sopenharmony_ci MAX77620_FPS_SRC_MASK, 1528c2ecf20Sopenharmony_ci fps_src << MAX77620_FPS_SRC_SHIFT); 1538c2ecf20Sopenharmony_ci if (ret < 0) { 1548c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed %d\n", 1558c2ecf20Sopenharmony_ci rinfo->fps_addr, ret); 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci pmic->active_fps_src[id] = fps_src; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic, 1648c2ecf20Sopenharmony_ci int id, bool is_suspend) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 1678c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 1688c2ecf20Sopenharmony_ci unsigned int val = 0; 1698c2ecf20Sopenharmony_ci unsigned int mask = 0; 1708c2ecf20Sopenharmony_ci int pu = rpdata->active_fps_pu_slot; 1718c2ecf20Sopenharmony_ci int pd = rpdata->active_fps_pd_slot; 1728c2ecf20Sopenharmony_ci int ret = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!rinfo) 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (is_suspend) { 1788c2ecf20Sopenharmony_ci pu = rpdata->suspend_fps_pu_slot; 1798c2ecf20Sopenharmony_ci pd = rpdata->suspend_fps_pd_slot; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* FPS power up period setting */ 1838c2ecf20Sopenharmony_ci if (pu >= 0) { 1848c2ecf20Sopenharmony_ci val |= (pu << MAX77620_FPS_PU_PERIOD_SHIFT); 1858c2ecf20Sopenharmony_ci mask |= MAX77620_FPS_PU_PERIOD_MASK; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* FPS power down period setting */ 1898c2ecf20Sopenharmony_ci if (pd >= 0) { 1908c2ecf20Sopenharmony_ci val |= (pd << MAX77620_FPS_PD_PERIOD_SHIFT); 1918c2ecf20Sopenharmony_ci mask |= MAX77620_FPS_PD_PERIOD_MASK; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (mask) { 1958c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->fps_addr, 1968c2ecf20Sopenharmony_ci mask, val); 1978c2ecf20Sopenharmony_ci if (ret < 0) { 1988c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", 1998c2ecf20Sopenharmony_ci rinfo->fps_addr, ret); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int max77620_regulator_set_power_mode(struct max77620_regulator *pmic, 2088c2ecf20Sopenharmony_ci int power_mode, int id) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 2118c2ecf20Sopenharmony_ci u8 mask = rinfo->power_mode_mask; 2128c2ecf20Sopenharmony_ci u8 shift = rinfo->power_mode_shift; 2138c2ecf20Sopenharmony_ci u8 addr; 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (rinfo->type) { 2178c2ecf20Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 2188c2ecf20Sopenharmony_ci addr = rinfo->cfg_addr; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci default: 2218c2ecf20Sopenharmony_ci addr = rinfo->volt_addr; 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, addr, mask, power_mode << shift); 2268c2ecf20Sopenharmony_ci if (ret < 0) { 2278c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Regulator %d mode set failed: %d\n", 2288c2ecf20Sopenharmony_ci id, ret); 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci pmic->current_power_mode[id] = power_mode; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int max77620_regulator_get_power_mode(struct max77620_regulator *pmic, 2378c2ecf20Sopenharmony_ci int id) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 2408c2ecf20Sopenharmony_ci unsigned int val, addr; 2418c2ecf20Sopenharmony_ci u8 mask = rinfo->power_mode_mask; 2428c2ecf20Sopenharmony_ci u8 shift = rinfo->power_mode_shift; 2438c2ecf20Sopenharmony_ci int ret; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci switch (rinfo->type) { 2468c2ecf20Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 2478c2ecf20Sopenharmony_ci addr = rinfo->cfg_addr; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci addr = rinfo->volt_addr; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ret = regmap_read(pmic->rmap, addr, &val); 2558c2ecf20Sopenharmony_ci if (ret < 0) { 2568c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n", 2578c2ecf20Sopenharmony_ci id, addr, ret); 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return (val & mask) >> shift; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int max77620_read_slew_rate(struct max77620_regulator *pmic, int id) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 2678c2ecf20Sopenharmony_ci unsigned int rval; 2688c2ecf20Sopenharmony_ci int slew_rate; 2698c2ecf20Sopenharmony_ci int ret; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &rval); 2728c2ecf20Sopenharmony_ci if (ret < 0) { 2738c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Register 0x%02x read failed: %d\n", 2748c2ecf20Sopenharmony_ci rinfo->cfg_addr, ret); 2758c2ecf20Sopenharmony_ci return ret; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci switch (rinfo->type) { 2798c2ecf20Sopenharmony_ci case MAX77620_REGULATOR_TYPE_SD: 2808c2ecf20Sopenharmony_ci slew_rate = (rval >> MAX77620_SD_SR_SHIFT) & 0x3; 2818c2ecf20Sopenharmony_ci switch (slew_rate) { 2828c2ecf20Sopenharmony_ci case 0: 2838c2ecf20Sopenharmony_ci slew_rate = 13750; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case 1: 2868c2ecf20Sopenharmony_ci slew_rate = 27500; 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case 2: 2898c2ecf20Sopenharmony_ci slew_rate = 55000; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci case 3: 2928c2ecf20Sopenharmony_ci slew_rate = 100000; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci rinfo->desc.ramp_delay = slew_rate; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci default: 2988c2ecf20Sopenharmony_ci slew_rate = rval & 0x1; 2998c2ecf20Sopenharmony_ci switch (slew_rate) { 3008c2ecf20Sopenharmony_ci case 0: 3018c2ecf20Sopenharmony_ci slew_rate = 100000; 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci case 1: 3048c2ecf20Sopenharmony_ci slew_rate = 5000; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci rinfo->desc.ramp_delay = slew_rate; 3088c2ecf20Sopenharmony_ci break; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int max77620_set_slew_rate(struct max77620_regulator *pmic, int id, 3158c2ecf20Sopenharmony_ci int slew_rate) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 3188c2ecf20Sopenharmony_ci unsigned int val; 3198c2ecf20Sopenharmony_ci int ret; 3208c2ecf20Sopenharmony_ci u8 mask; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { 3238c2ecf20Sopenharmony_ci if (slew_rate <= 13750) 3248c2ecf20Sopenharmony_ci val = 0; 3258c2ecf20Sopenharmony_ci else if (slew_rate <= 27500) 3268c2ecf20Sopenharmony_ci val = 1; 3278c2ecf20Sopenharmony_ci else if (slew_rate <= 55000) 3288c2ecf20Sopenharmony_ci val = 2; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci val = 3; 3318c2ecf20Sopenharmony_ci val <<= MAX77620_SD_SR_SHIFT; 3328c2ecf20Sopenharmony_ci mask = MAX77620_SD_SR_MASK; 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci if (slew_rate <= 5000) 3358c2ecf20Sopenharmony_ci val = 1; 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci val = 0; 3388c2ecf20Sopenharmony_ci mask = MAX77620_LDO_SLEW_RATE_MASK; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val); 3428c2ecf20Sopenharmony_ci if (ret < 0) { 3438c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Regulator %d slew rate set failed: %d\n", 3448c2ecf20Sopenharmony_ci id, ret); 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int max77620_config_power_ok(struct max77620_regulator *pmic, int id) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 3548c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 3558c2ecf20Sopenharmony_ci struct max77620_chip *chip = dev_get_drvdata(pmic->dev->parent); 3568c2ecf20Sopenharmony_ci u8 val, mask; 3578c2ecf20Sopenharmony_ci int ret; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci switch (chip->chip_id) { 3608c2ecf20Sopenharmony_ci case MAX20024: 3618c2ecf20Sopenharmony_ci if (rpdata->power_ok >= 0) { 3628c2ecf20Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) 3638c2ecf20Sopenharmony_ci mask = MAX20024_SD_CFG1_MPOK_MASK; 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci mask = MAX20024_LDO_CFG2_MPOK_MASK; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci val = rpdata->power_ok ? mask : 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, 3708c2ecf20Sopenharmony_ci mask, val); 3718c2ecf20Sopenharmony_ci if (ret < 0) { 3728c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed %d\n", 3738c2ecf20Sopenharmony_ci rinfo->cfg_addr, ret); 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci default: 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int max77620_init_pmic(struct max77620_regulator *pmic, int id) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 3898c2ecf20Sopenharmony_ci int ret; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci max77620_config_power_ok(pmic, id); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Update power mode */ 3948c2ecf20Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 3958c2ecf20Sopenharmony_ci if (ret < 0) 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci pmic->current_power_mode[id] = ret; 3998c2ecf20Sopenharmony_ci pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (rpdata->active_fps_src == MAX77620_FPS_SRC_DEF) { 4028c2ecf20Sopenharmony_ci ret = max77620_regulator_get_fps_src(pmic, id); 4038c2ecf20Sopenharmony_ci if (ret < 0) 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci rpdata->active_fps_src = ret; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* If rails are externally control of FPS then enable it always. */ 4098c2ecf20Sopenharmony_ci if (rpdata->active_fps_src == MAX77620_FPS_SRC_NONE) { 4108c2ecf20Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, 4118c2ecf20Sopenharmony_ci pmic->enable_power_mode[id], id); 4128c2ecf20Sopenharmony_ci if (ret < 0) 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci } else { 4158c2ecf20Sopenharmony_ci if (pmic->current_power_mode[id] != 4168c2ecf20Sopenharmony_ci pmic->enable_power_mode[id]) { 4178c2ecf20Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, 4188c2ecf20Sopenharmony_ci pmic->enable_power_mode[id], id); 4198c2ecf20Sopenharmony_ci if (ret < 0) 4208c2ecf20Sopenharmony_ci return ret; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ret = max77620_regulator_set_fps_src(pmic, rpdata->active_fps_src, id); 4258c2ecf20Sopenharmony_ci if (ret < 0) 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ret = max77620_regulator_set_fps_slots(pmic, id, false); 4298c2ecf20Sopenharmony_ci if (ret < 0) 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (rpdata->ramp_rate_setting) { 4338c2ecf20Sopenharmony_ci ret = max77620_set_slew_rate(pmic, id, 4348c2ecf20Sopenharmony_ci rpdata->ramp_rate_setting); 4358c2ecf20Sopenharmony_ci if (ret < 0) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int max77620_regulator_enable(struct regulator_dev *rdev) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 4458c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return max77620_regulator_set_power_mode(pmic, 4518c2ecf20Sopenharmony_ci pmic->enable_power_mode[id], id); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int max77620_regulator_disable(struct regulator_dev *rdev) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 4578c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return max77620_regulator_set_power_mode(pmic, 4638c2ecf20Sopenharmony_ci MAX77620_POWER_MODE_DISABLE, id); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int max77620_regulator_is_enabled(struct regulator_dev *rdev) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 4698c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) 4738c2ecf20Sopenharmony_ci return 1; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 4768c2ecf20Sopenharmony_ci if (ret < 0) 4778c2ecf20Sopenharmony_ci return ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (ret != MAX77620_POWER_MODE_DISABLE) 4808c2ecf20Sopenharmony_ci return 1; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int max77620_regulator_set_mode(struct regulator_dev *rdev, 4868c2ecf20Sopenharmony_ci unsigned int mode) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 4898c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 4908c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 4918c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 4928c2ecf20Sopenharmony_ci bool fpwm = false; 4938c2ecf20Sopenharmony_ci int power_mode; 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci u8 val; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci switch (mode) { 4988c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 4998c2ecf20Sopenharmony_ci fpwm = true; 5008c2ecf20Sopenharmony_ci power_mode = MAX77620_POWER_MODE_NORMAL; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 5048c2ecf20Sopenharmony_ci power_mode = MAX77620_POWER_MODE_NORMAL; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: 5088c2ecf20Sopenharmony_ci power_mode = MAX77620_POWER_MODE_LPM; 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci default: 5128c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Regulator %d mode %d is invalid\n", 5138c2ecf20Sopenharmony_ci id, mode); 5148c2ecf20Sopenharmony_ci return -EINVAL; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (rinfo->type != MAX77620_REGULATOR_TYPE_SD) 5188c2ecf20Sopenharmony_ci goto skip_fpwm; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci val = (fpwm) ? MAX77620_SD_FPWM_MASK : 0; 5218c2ecf20Sopenharmony_ci ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, 5228c2ecf20Sopenharmony_ci MAX77620_SD_FPWM_MASK, val); 5238c2ecf20Sopenharmony_ci if (ret < 0) { 5248c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n", 5258c2ecf20Sopenharmony_ci rinfo->cfg_addr, ret); 5268c2ecf20Sopenharmony_ci return ret; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci rpdata->current_mode = mode; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciskip_fpwm: 5318c2ecf20Sopenharmony_ci ret = max77620_regulator_set_power_mode(pmic, power_mode, id); 5328c2ecf20Sopenharmony_ci if (ret < 0) 5338c2ecf20Sopenharmony_ci return ret; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci pmic->enable_power_mode[id] = power_mode; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic unsigned int max77620_regulator_get_mode(struct regulator_dev *rdev) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 5438c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 5448c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo = pmic->rinfo[id]; 5458c2ecf20Sopenharmony_ci int fpwm = 0; 5468c2ecf20Sopenharmony_ci int ret; 5478c2ecf20Sopenharmony_ci int pm_mode, reg_mode; 5488c2ecf20Sopenharmony_ci unsigned int val; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci ret = max77620_regulator_get_power_mode(pmic, id); 5518c2ecf20Sopenharmony_ci if (ret < 0) 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci pm_mode = ret; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) { 5578c2ecf20Sopenharmony_ci ret = regmap_read(pmic->rmap, rinfo->cfg_addr, &val); 5588c2ecf20Sopenharmony_ci if (ret < 0) { 5598c2ecf20Sopenharmony_ci dev_err(pmic->dev, "Reg 0x%02x read failed: %d\n", 5608c2ecf20Sopenharmony_ci rinfo->cfg_addr, ret); 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci fpwm = !!(val & MAX77620_SD_FPWM_MASK); 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci switch (pm_mode) { 5678c2ecf20Sopenharmony_ci case MAX77620_POWER_MODE_NORMAL: 5688c2ecf20Sopenharmony_ci case MAX77620_POWER_MODE_DISABLE: 5698c2ecf20Sopenharmony_ci if (fpwm) 5708c2ecf20Sopenharmony_ci reg_mode = REGULATOR_MODE_FAST; 5718c2ecf20Sopenharmony_ci else 5728c2ecf20Sopenharmony_ci reg_mode = REGULATOR_MODE_NORMAL; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case MAX77620_POWER_MODE_LPM: 5758c2ecf20Sopenharmony_ci case MAX77620_POWER_MODE_GLPM: 5768c2ecf20Sopenharmony_ci reg_mode = REGULATOR_MODE_IDLE; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return reg_mode; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev, 5868c2ecf20Sopenharmony_ci int ramp_delay) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = rdev_get_drvdata(rdev); 5898c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 5908c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id]; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Device specific ramp rate setting tells that platform has 5938c2ecf20Sopenharmony_ci * different ramp rate from advertised value. In this case, 5948c2ecf20Sopenharmony_ci * do not configure anything and just return success. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci if (rpdata->ramp_rate_setting) 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return max77620_set_slew_rate(pmic, id, ramp_delay); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int max77620_of_parse_cb(struct device_node *np, 6038c2ecf20Sopenharmony_ci const struct regulator_desc *desc, 6048c2ecf20Sopenharmony_ci struct regulator_config *config) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = config->driver_data; 6078c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[desc->id]; 6088c2ecf20Sopenharmony_ci u32 pval; 6098c2ecf20Sopenharmony_ci int ret; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "maxim,active-fps-source", &pval); 6128c2ecf20Sopenharmony_ci rpdata->active_fps_src = (!ret) ? pval : MAX77620_FPS_SRC_DEF; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "maxim,active-fps-power-up-slot", &pval); 6158c2ecf20Sopenharmony_ci rpdata->active_fps_pu_slot = (!ret) ? pval : -1; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci ret = of_property_read_u32( 6188c2ecf20Sopenharmony_ci np, "maxim,active-fps-power-down-slot", &pval); 6198c2ecf20Sopenharmony_ci rpdata->active_fps_pd_slot = (!ret) ? pval : -1; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "maxim,suspend-fps-source", &pval); 6228c2ecf20Sopenharmony_ci rpdata->suspend_fps_src = (!ret) ? pval : -1; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = of_property_read_u32( 6258c2ecf20Sopenharmony_ci np, "maxim,suspend-fps-power-up-slot", &pval); 6268c2ecf20Sopenharmony_ci rpdata->suspend_fps_pu_slot = (!ret) ? pval : -1; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci ret = of_property_read_u32( 6298c2ecf20Sopenharmony_ci np, "maxim,suspend-fps-power-down-slot", &pval); 6308c2ecf20Sopenharmony_ci rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "maxim,power-ok-control", &pval); 6338c2ecf20Sopenharmony_ci if (!ret) 6348c2ecf20Sopenharmony_ci rpdata->power_ok = pval; 6358c2ecf20Sopenharmony_ci else 6368c2ecf20Sopenharmony_ci rpdata->power_ok = -1; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval); 6398c2ecf20Sopenharmony_ci rpdata->ramp_rate_setting = (!ret) ? pval : 0; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return max77620_init_pmic(pmic, desc->id); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic const struct regulator_ops max77620_regulator_ops = { 6458c2ecf20Sopenharmony_ci .is_enabled = max77620_regulator_is_enabled, 6468c2ecf20Sopenharmony_ci .enable = max77620_regulator_enable, 6478c2ecf20Sopenharmony_ci .disable = max77620_regulator_disable, 6488c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 6498c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 6508c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 6518c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 6528c2ecf20Sopenharmony_ci .set_mode = max77620_regulator_set_mode, 6538c2ecf20Sopenharmony_ci .get_mode = max77620_regulator_get_mode, 6548c2ecf20Sopenharmony_ci .set_ramp_delay = max77620_regulator_set_ramp_delay, 6558c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 6568c2ecf20Sopenharmony_ci .set_active_discharge = regulator_set_active_discharge_regmap, 6578c2ecf20Sopenharmony_ci}; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci#define MAX77620_SD_CNF2_ROVS_EN_NONE 0 6608c2ecf20Sopenharmony_ci#define RAIL_SD(_id, _name, _sname, _volt_mask, _min_uV, _max_uV, \ 6618c2ecf20Sopenharmony_ci _step_uV, _rs_add, _rs_mask) \ 6628c2ecf20Sopenharmony_ci [MAX77620_REGULATOR_ID_##_id] = { \ 6638c2ecf20Sopenharmony_ci .type = MAX77620_REGULATOR_TYPE_SD, \ 6648c2ecf20Sopenharmony_ci .volt_addr = MAX77620_REG_##_id, \ 6658c2ecf20Sopenharmony_ci .cfg_addr = MAX77620_REG_##_id##_CFG, \ 6668c2ecf20Sopenharmony_ci .fps_addr = MAX77620_REG_FPS_##_id, \ 6678c2ecf20Sopenharmony_ci .remote_sense_addr = _rs_add, \ 6688c2ecf20Sopenharmony_ci .remote_sense_mask = MAX77620_SD_CNF2_ROVS_EN_##_rs_mask, \ 6698c2ecf20Sopenharmony_ci .power_mode_mask = MAX77620_SD_POWER_MODE_MASK, \ 6708c2ecf20Sopenharmony_ci .power_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, \ 6718c2ecf20Sopenharmony_ci .desc = { \ 6728c2ecf20Sopenharmony_ci .name = max77620_rails(_name), \ 6738c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_name), \ 6748c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 6758c2ecf20Sopenharmony_ci .of_parse_cb = max77620_of_parse_cb, \ 6768c2ecf20Sopenharmony_ci .supply_name = _sname, \ 6778c2ecf20Sopenharmony_ci .id = MAX77620_REGULATOR_ID_##_id, \ 6788c2ecf20Sopenharmony_ci .ops = &max77620_regulator_ops, \ 6798c2ecf20Sopenharmony_ci .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ 6808c2ecf20Sopenharmony_ci .min_uV = _min_uV, \ 6818c2ecf20Sopenharmony_ci .uV_step = _step_uV, \ 6828c2ecf20Sopenharmony_ci .enable_time = 500, \ 6838c2ecf20Sopenharmony_ci .vsel_mask = MAX77620_##_volt_mask##_VOLT_MASK, \ 6848c2ecf20Sopenharmony_ci .vsel_reg = MAX77620_REG_##_id, \ 6858c2ecf20Sopenharmony_ci .active_discharge_off = 0, \ 6868c2ecf20Sopenharmony_ci .active_discharge_on = MAX77620_SD_CFG1_ADE_ENABLE, \ 6878c2ecf20Sopenharmony_ci .active_discharge_mask = MAX77620_SD_CFG1_ADE_MASK, \ 6888c2ecf20Sopenharmony_ci .active_discharge_reg = MAX77620_REG_##_id##_CFG, \ 6898c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 6908c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 6918c2ecf20Sopenharmony_ci }, \ 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci#define RAIL_LDO(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \ 6958c2ecf20Sopenharmony_ci [MAX77620_REGULATOR_ID_##_id] = { \ 6968c2ecf20Sopenharmony_ci .type = MAX77620_REGULATOR_TYPE_LDO_##_type, \ 6978c2ecf20Sopenharmony_ci .volt_addr = MAX77620_REG_##_id##_CFG, \ 6988c2ecf20Sopenharmony_ci .cfg_addr = MAX77620_REG_##_id##_CFG2, \ 6998c2ecf20Sopenharmony_ci .fps_addr = MAX77620_REG_FPS_##_id, \ 7008c2ecf20Sopenharmony_ci .remote_sense_addr = 0xFF, \ 7018c2ecf20Sopenharmony_ci .power_mode_mask = MAX77620_LDO_POWER_MODE_MASK, \ 7028c2ecf20Sopenharmony_ci .power_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, \ 7038c2ecf20Sopenharmony_ci .desc = { \ 7048c2ecf20Sopenharmony_ci .name = max77620_rails(_name), \ 7058c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_name), \ 7068c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 7078c2ecf20Sopenharmony_ci .of_parse_cb = max77620_of_parse_cb, \ 7088c2ecf20Sopenharmony_ci .supply_name = _sname, \ 7098c2ecf20Sopenharmony_ci .id = MAX77620_REGULATOR_ID_##_id, \ 7108c2ecf20Sopenharmony_ci .ops = &max77620_regulator_ops, \ 7118c2ecf20Sopenharmony_ci .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ 7128c2ecf20Sopenharmony_ci .min_uV = _min_uV, \ 7138c2ecf20Sopenharmony_ci .uV_step = _step_uV, \ 7148c2ecf20Sopenharmony_ci .enable_time = 500, \ 7158c2ecf20Sopenharmony_ci .vsel_mask = MAX77620_LDO_VOLT_MASK, \ 7168c2ecf20Sopenharmony_ci .vsel_reg = MAX77620_REG_##_id##_CFG, \ 7178c2ecf20Sopenharmony_ci .active_discharge_off = 0, \ 7188c2ecf20Sopenharmony_ci .active_discharge_on = MAX77620_LDO_CFG2_ADE_ENABLE, \ 7198c2ecf20Sopenharmony_ci .active_discharge_mask = MAX77620_LDO_CFG2_ADE_MASK, \ 7208c2ecf20Sopenharmony_ci .active_discharge_reg = MAX77620_REG_##_id##_CFG2, \ 7218c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 7228c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 7238c2ecf20Sopenharmony_ci }, \ 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = { 7278c2ecf20Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 1400000, 12500, 0x22, SD0), 7288c2ecf20Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1), 7298c2ecf20Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7308c2ecf20Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 7338c2ecf20Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 7348c2ecf20Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 7358c2ecf20Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 7368c2ecf20Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 7378c2ecf20Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 7388c2ecf20Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 7398c2ecf20Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 7408c2ecf20Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 7418c2ecf20Sopenharmony_ci}; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = { 7448c2ecf20Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 800000, 1587500, 12500, 0x22, SD0), 7458c2ecf20Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 3387500, 12500, 0x22, SD1), 7468c2ecf20Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7478c2ecf20Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7488c2ecf20Sopenharmony_ci RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 7518c2ecf20Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 7528c2ecf20Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 7538c2ecf20Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 7548c2ecf20Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 7558c2ecf20Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 7568c2ecf20Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 7578c2ecf20Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 7588c2ecf20Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 7598c2ecf20Sopenharmony_ci}; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic struct max77620_regulator_info max77663_regs_info[MAX77620_NUM_REGS] = { 7628c2ecf20Sopenharmony_ci RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 3387500, 12500, 0xFF, NONE), 7638c2ecf20Sopenharmony_ci RAIL_SD(SD1, sd1, "in-sd1", SD1, 800000, 1587500, 12500, 0xFF, NONE), 7648c2ecf20Sopenharmony_ci RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7658c2ecf20Sopenharmony_ci RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7668c2ecf20Sopenharmony_ci RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), 7698c2ecf20Sopenharmony_ci RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), 7708c2ecf20Sopenharmony_ci RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), 7718c2ecf20Sopenharmony_ci RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), 7728c2ecf20Sopenharmony_ci RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), 7738c2ecf20Sopenharmony_ci RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), 7748c2ecf20Sopenharmony_ci RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), 7758c2ecf20Sopenharmony_ci RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), 7768c2ecf20Sopenharmony_ci RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), 7778c2ecf20Sopenharmony_ci}; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic int max77620_regulator_probe(struct platform_device *pdev) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent); 7828c2ecf20Sopenharmony_ci struct max77620_regulator_info *rinfo; 7838c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 7848c2ecf20Sopenharmony_ci struct regulator_config config = { }; 7858c2ecf20Sopenharmony_ci struct max77620_regulator *pmic; 7868c2ecf20Sopenharmony_ci int ret = 0; 7878c2ecf20Sopenharmony_ci int id; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 7908c2ecf20Sopenharmony_ci if (!pmic) 7918c2ecf20Sopenharmony_ci return -ENOMEM; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pmic); 7948c2ecf20Sopenharmony_ci pmic->dev = dev; 7958c2ecf20Sopenharmony_ci pmic->rmap = max77620_chip->rmap; 7968c2ecf20Sopenharmony_ci if (!dev->of_node) 7978c2ecf20Sopenharmony_ci dev->of_node = pdev->dev.parent->of_node; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci switch (max77620_chip->chip_id) { 8008c2ecf20Sopenharmony_ci case MAX77620: 8018c2ecf20Sopenharmony_ci rinfo = max77620_regs_info; 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci case MAX20024: 8048c2ecf20Sopenharmony_ci rinfo = max20024_regs_info; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci case MAX77663: 8078c2ecf20Sopenharmony_ci rinfo = max77663_regs_info; 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci default: 8108c2ecf20Sopenharmony_ci return -EINVAL; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci config.regmap = pmic->rmap; 8148c2ecf20Sopenharmony_ci config.dev = dev; 8158c2ecf20Sopenharmony_ci config.driver_data = pmic; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* 8188c2ecf20Sopenharmony_ci * Set of_node_reuse flag to prevent driver core from attempting to 8198c2ecf20Sopenharmony_ci * claim any pinmux resources already claimed by the parent device. 8208c2ecf20Sopenharmony_ci * Otherwise PMIC driver will fail to re-probe. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_ci device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 8258c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 8268c2ecf20Sopenharmony_ci struct regulator_desc *rdesc; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if ((max77620_chip->chip_id == MAX77620) && 8298c2ecf20Sopenharmony_ci (id == MAX77620_REGULATOR_ID_SD4)) 8308c2ecf20Sopenharmony_ci continue; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci rdesc = &rinfo[id].desc; 8338c2ecf20Sopenharmony_ci pmic->rinfo[id] = &rinfo[id]; 8348c2ecf20Sopenharmony_ci pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; 8358c2ecf20Sopenharmony_ci pmic->reg_pdata[id].active_fps_src = -1; 8368c2ecf20Sopenharmony_ci pmic->reg_pdata[id].active_fps_pd_slot = -1; 8378c2ecf20Sopenharmony_ci pmic->reg_pdata[id].active_fps_pu_slot = -1; 8388c2ecf20Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_src = -1; 8398c2ecf20Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_pd_slot = -1; 8408c2ecf20Sopenharmony_ci pmic->reg_pdata[id].suspend_fps_pu_slot = -1; 8418c2ecf20Sopenharmony_ci pmic->reg_pdata[id].power_ok = -1; 8428c2ecf20Sopenharmony_ci pmic->reg_pdata[id].ramp_rate_setting = -1; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ret = max77620_read_slew_rate(pmic, id); 8458c2ecf20Sopenharmony_ci if (ret < 0) 8468c2ecf20Sopenharmony_ci return ret; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci rdev = devm_regulator_register(dev, rdesc, &config); 8498c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 8508c2ecf20Sopenharmony_ci ret = PTR_ERR(rdev); 8518c2ecf20Sopenharmony_ci dev_err(dev, "Regulator registration %s failed: %d\n", 8528c2ecf20Sopenharmony_ci rdesc->name, ret); 8538c2ecf20Sopenharmony_ci return ret; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8618c2ecf20Sopenharmony_cistatic int max77620_regulator_suspend(struct device *dev) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = dev_get_drvdata(dev); 8648c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *reg_pdata; 8658c2ecf20Sopenharmony_ci int id; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 8688c2ecf20Sopenharmony_ci reg_pdata = &pmic->reg_pdata[id]; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci max77620_regulator_set_fps_slots(pmic, id, true); 8718c2ecf20Sopenharmony_ci if (reg_pdata->suspend_fps_src < 0) 8728c2ecf20Sopenharmony_ci continue; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci max77620_regulator_set_fps_src(pmic, reg_pdata->suspend_fps_src, 8758c2ecf20Sopenharmony_ci id); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int max77620_regulator_resume(struct device *dev) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct max77620_regulator *pmic = dev_get_drvdata(dev); 8848c2ecf20Sopenharmony_ci struct max77620_regulator_pdata *reg_pdata; 8858c2ecf20Sopenharmony_ci int id; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci for (id = 0; id < MAX77620_NUM_REGS; id++) { 8888c2ecf20Sopenharmony_ci reg_pdata = &pmic->reg_pdata[id]; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci max77620_config_power_ok(pmic, id); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci max77620_regulator_set_fps_slots(pmic, id, false); 8938c2ecf20Sopenharmony_ci if (reg_pdata->active_fps_src < 0) 8948c2ecf20Sopenharmony_ci continue; 8958c2ecf20Sopenharmony_ci max77620_regulator_set_fps_src(pmic, reg_pdata->active_fps_src, 8968c2ecf20Sopenharmony_ci id); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return 0; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci#endif 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic const struct dev_pm_ops max77620_regulator_pm_ops = { 9048c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(max77620_regulator_suspend, 9058c2ecf20Sopenharmony_ci max77620_regulator_resume) 9068c2ecf20Sopenharmony_ci}; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic const struct platform_device_id max77620_regulator_devtype[] = { 9098c2ecf20Sopenharmony_ci { .name = "max77620-pmic", }, 9108c2ecf20Sopenharmony_ci { .name = "max20024-pmic", }, 9118c2ecf20Sopenharmony_ci { .name = "max77663-pmic", }, 9128c2ecf20Sopenharmony_ci {}, 9138c2ecf20Sopenharmony_ci}; 9148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic struct platform_driver max77620_regulator_driver = { 9178c2ecf20Sopenharmony_ci .probe = max77620_regulator_probe, 9188c2ecf20Sopenharmony_ci .id_table = max77620_regulator_devtype, 9198c2ecf20Sopenharmony_ci .driver = { 9208c2ecf20Sopenharmony_ci .name = "max77620-pmic", 9218c2ecf20Sopenharmony_ci .pm = &max77620_regulator_pm_ops, 9228c2ecf20Sopenharmony_ci }, 9238c2ecf20Sopenharmony_ci}; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cimodule_platform_driver(max77620_regulator_driver); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAX77620/MAX20024 regulator driver"); 9288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>"); 9298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 9308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 931