18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// max8997.c - Regulator driver for the Maxim 8997/8966 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2011 Samsung Electronics 68c2ecf20Sopenharmony_ci// MyungJoo Ham <myungjoo.ham@samsung.com> 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// This driver is based on max8998.c 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/bug.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio.h> 138c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 198c2ecf20Sopenharmony_ci#include <linux/mfd/max8997.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/max8997-private.h> 218c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct max8997_data { 248c2ecf20Sopenharmony_ci struct device *dev; 258c2ecf20Sopenharmony_ci struct max8997_dev *iodev; 268c2ecf20Sopenharmony_ci int num_regulators; 278c2ecf20Sopenharmony_ci int ramp_delay; /* in mV/us */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci bool buck1_gpiodvs; 308c2ecf20Sopenharmony_ci bool buck2_gpiodvs; 318c2ecf20Sopenharmony_ci bool buck5_gpiodvs; 328c2ecf20Sopenharmony_ci u8 buck1_vol[8]; 338c2ecf20Sopenharmony_ci u8 buck2_vol[8]; 348c2ecf20Sopenharmony_ci u8 buck5_vol[8]; 358c2ecf20Sopenharmony_ci int buck125_gpios[3]; 368c2ecf20Sopenharmony_ci int buck125_gpioindex; 378c2ecf20Sopenharmony_ci bool ignore_gpiodvs_side_effect; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci u8 saved_states[MAX8997_REG_MAX]; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const unsigned int safeoutvolt[] = { 438c2ecf20Sopenharmony_ci 4850000, 448c2ecf20Sopenharmony_ci 4900000, 458c2ecf20Sopenharmony_ci 4950000, 468c2ecf20Sopenharmony_ci 3300000, 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic inline void max8997_set_gpio(struct max8997_data *max8997) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int set3 = (max8997->buck125_gpioindex) & 0x1; 528c2ecf20Sopenharmony_ci int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; 538c2ecf20Sopenharmony_ci int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci gpio_set_value(max8997->buck125_gpios[0], set1); 568c2ecf20Sopenharmony_ci gpio_set_value(max8997->buck125_gpios[1], set2); 578c2ecf20Sopenharmony_ci gpio_set_value(max8997->buck125_gpios[2], set3); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct voltage_map_desc { 618c2ecf20Sopenharmony_ci int min; 628c2ecf20Sopenharmony_ci int max; 638c2ecf20Sopenharmony_ci int step; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Voltage maps in uV */ 678c2ecf20Sopenharmony_cistatic const struct voltage_map_desc ldo_voltage_map_desc = { 688c2ecf20Sopenharmony_ci .min = 800000, .max = 3950000, .step = 50000, 698c2ecf20Sopenharmony_ci}; /* LDO1 ~ 18, 21 all */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic const struct voltage_map_desc buck1245_voltage_map_desc = { 728c2ecf20Sopenharmony_ci .min = 650000, .max = 2225000, .step = 25000, 738c2ecf20Sopenharmony_ci}; /* Buck1, 2, 4, 5 */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct voltage_map_desc buck37_voltage_map_desc = { 768c2ecf20Sopenharmony_ci .min = 750000, .max = 3900000, .step = 50000, 778c2ecf20Sopenharmony_ci}; /* Buck3, 7 */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* current map in uA */ 808c2ecf20Sopenharmony_cistatic const struct voltage_map_desc charger_current_map_desc = { 818c2ecf20Sopenharmony_ci .min = 200000, .max = 950000, .step = 50000, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct voltage_map_desc topoff_current_map_desc = { 858c2ecf20Sopenharmony_ci .min = 50000, .max = 200000, .step = 10000, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const struct voltage_map_desc *reg_voltage_map[] = { 898c2ecf20Sopenharmony_ci [MAX8997_LDO1] = &ldo_voltage_map_desc, 908c2ecf20Sopenharmony_ci [MAX8997_LDO2] = &ldo_voltage_map_desc, 918c2ecf20Sopenharmony_ci [MAX8997_LDO3] = &ldo_voltage_map_desc, 928c2ecf20Sopenharmony_ci [MAX8997_LDO4] = &ldo_voltage_map_desc, 938c2ecf20Sopenharmony_ci [MAX8997_LDO5] = &ldo_voltage_map_desc, 948c2ecf20Sopenharmony_ci [MAX8997_LDO6] = &ldo_voltage_map_desc, 958c2ecf20Sopenharmony_ci [MAX8997_LDO7] = &ldo_voltage_map_desc, 968c2ecf20Sopenharmony_ci [MAX8997_LDO8] = &ldo_voltage_map_desc, 978c2ecf20Sopenharmony_ci [MAX8997_LDO9] = &ldo_voltage_map_desc, 988c2ecf20Sopenharmony_ci [MAX8997_LDO10] = &ldo_voltage_map_desc, 998c2ecf20Sopenharmony_ci [MAX8997_LDO11] = &ldo_voltage_map_desc, 1008c2ecf20Sopenharmony_ci [MAX8997_LDO12] = &ldo_voltage_map_desc, 1018c2ecf20Sopenharmony_ci [MAX8997_LDO13] = &ldo_voltage_map_desc, 1028c2ecf20Sopenharmony_ci [MAX8997_LDO14] = &ldo_voltage_map_desc, 1038c2ecf20Sopenharmony_ci [MAX8997_LDO15] = &ldo_voltage_map_desc, 1048c2ecf20Sopenharmony_ci [MAX8997_LDO16] = &ldo_voltage_map_desc, 1058c2ecf20Sopenharmony_ci [MAX8997_LDO17] = &ldo_voltage_map_desc, 1068c2ecf20Sopenharmony_ci [MAX8997_LDO18] = &ldo_voltage_map_desc, 1078c2ecf20Sopenharmony_ci [MAX8997_LDO21] = &ldo_voltage_map_desc, 1088c2ecf20Sopenharmony_ci [MAX8997_BUCK1] = &buck1245_voltage_map_desc, 1098c2ecf20Sopenharmony_ci [MAX8997_BUCK2] = &buck1245_voltage_map_desc, 1108c2ecf20Sopenharmony_ci [MAX8997_BUCK3] = &buck37_voltage_map_desc, 1118c2ecf20Sopenharmony_ci [MAX8997_BUCK4] = &buck1245_voltage_map_desc, 1128c2ecf20Sopenharmony_ci [MAX8997_BUCK5] = &buck1245_voltage_map_desc, 1138c2ecf20Sopenharmony_ci [MAX8997_BUCK6] = NULL, 1148c2ecf20Sopenharmony_ci [MAX8997_BUCK7] = &buck37_voltage_map_desc, 1158c2ecf20Sopenharmony_ci [MAX8997_EN32KHZ_AP] = NULL, 1168c2ecf20Sopenharmony_ci [MAX8997_EN32KHZ_CP] = NULL, 1178c2ecf20Sopenharmony_ci [MAX8997_ENVICHG] = NULL, 1188c2ecf20Sopenharmony_ci [MAX8997_ESAFEOUT1] = NULL, 1198c2ecf20Sopenharmony_ci [MAX8997_ESAFEOUT2] = NULL, 1208c2ecf20Sopenharmony_ci [MAX8997_CHARGER_CV] = NULL, 1218c2ecf20Sopenharmony_ci [MAX8997_CHARGER] = &charger_current_map_desc, 1228c2ecf20Sopenharmony_ci [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, 1268c2ecf20Sopenharmony_ci unsigned int selector) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (rid != MAX8997_CHARGER_CV) 1318c2ecf20Sopenharmony_ci goto err; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci switch (selector) { 1348c2ecf20Sopenharmony_ci case 0x00: 1358c2ecf20Sopenharmony_ci return 4200000; 1368c2ecf20Sopenharmony_ci case 0x01 ... 0x0E: 1378c2ecf20Sopenharmony_ci return 4000000 + 20000 * (selector - 0x01); 1388c2ecf20Sopenharmony_ci case 0x0F: 1398c2ecf20Sopenharmony_ci return 4350000; 1408c2ecf20Sopenharmony_ci default: 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_cierr: 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int max8997_list_voltage(struct regulator_dev *rdev, 1488c2ecf20Sopenharmony_ci unsigned int selector) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc; 1518c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 1528c2ecf20Sopenharmony_ci int val; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (rid < 0 || rid >= ARRAY_SIZE(reg_voltage_map)) 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci desc = reg_voltage_map[rid]; 1588c2ecf20Sopenharmony_ci if (desc == NULL) 1598c2ecf20Sopenharmony_ci return -EINVAL; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci val = desc->min + desc->step * selector; 1628c2ecf20Sopenharmony_ci if (val > desc->max) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return val; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int max8997_get_enable_register(struct regulator_dev *rdev, 1698c2ecf20Sopenharmony_ci int *reg, int *mask, int *pattern) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci switch (rid) { 1748c2ecf20Sopenharmony_ci case MAX8997_LDO1 ... MAX8997_LDO21: 1758c2ecf20Sopenharmony_ci *reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); 1768c2ecf20Sopenharmony_ci *mask = 0xC0; 1778c2ecf20Sopenharmony_ci *pattern = 0xC0; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 1808c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK1CTRL; 1818c2ecf20Sopenharmony_ci *mask = 0x01; 1828c2ecf20Sopenharmony_ci *pattern = 0x01; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 1858c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK2CTRL; 1868c2ecf20Sopenharmony_ci *mask = 0x01; 1878c2ecf20Sopenharmony_ci *pattern = 0x01; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case MAX8997_BUCK3: 1908c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK3CTRL; 1918c2ecf20Sopenharmony_ci *mask = 0x01; 1928c2ecf20Sopenharmony_ci *pattern = 0x01; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci case MAX8997_BUCK4: 1958c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK4CTRL; 1968c2ecf20Sopenharmony_ci *mask = 0x01; 1978c2ecf20Sopenharmony_ci *pattern = 0x01; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 2008c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK5CTRL; 2018c2ecf20Sopenharmony_ci *mask = 0x01; 2028c2ecf20Sopenharmony_ci *pattern = 0x01; 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case MAX8997_BUCK6: 2058c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK6CTRL; 2068c2ecf20Sopenharmony_ci *mask = 0x01; 2078c2ecf20Sopenharmony_ci *pattern = 0x01; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case MAX8997_BUCK7: 2108c2ecf20Sopenharmony_ci *reg = MAX8997_REG_BUCK7CTRL; 2118c2ecf20Sopenharmony_ci *mask = 0x01; 2128c2ecf20Sopenharmony_ci *pattern = 0x01; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP: 2158c2ecf20Sopenharmony_ci *reg = MAX8997_REG_MAINCON1; 2168c2ecf20Sopenharmony_ci *mask = 0x01 << (rid - MAX8997_EN32KHZ_AP); 2178c2ecf20Sopenharmony_ci *pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case MAX8997_ENVICHG: 2208c2ecf20Sopenharmony_ci *reg = MAX8997_REG_MBCCTRL1; 2218c2ecf20Sopenharmony_ci *mask = 0x80; 2228c2ecf20Sopenharmony_ci *pattern = 0x80; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: 2258c2ecf20Sopenharmony_ci *reg = MAX8997_REG_SAFEOUTCTRL; 2268c2ecf20Sopenharmony_ci *mask = 0x40 << (rid - MAX8997_ESAFEOUT1); 2278c2ecf20Sopenharmony_ci *pattern = 0x40 << (rid - MAX8997_ESAFEOUT1); 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case MAX8997_CHARGER: 2308c2ecf20Sopenharmony_ci *reg = MAX8997_REG_MBCCTRL2; 2318c2ecf20Sopenharmony_ci *mask = 0x40; 2328c2ecf20Sopenharmony_ci *pattern = 0x40; 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci default: 2358c2ecf20Sopenharmony_ci /* Not controllable or not exists */ 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int max8997_reg_is_enabled(struct regulator_dev *rdev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 2458c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 2468c2ecf20Sopenharmony_ci int ret, reg, mask, pattern; 2478c2ecf20Sopenharmony_ci u8 val; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); 2508c2ecf20Sopenharmony_ci if (ret) 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = max8997_read_reg(i2c, reg, &val); 2548c2ecf20Sopenharmony_ci if (ret) 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return (val & mask) == pattern; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int max8997_reg_enable(struct regulator_dev *rdev) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 2638c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 2648c2ecf20Sopenharmony_ci int ret, reg, mask, pattern; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); 2678c2ecf20Sopenharmony_ci if (ret) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return max8997_update_reg(i2c, reg, pattern, mask); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int max8997_reg_disable(struct regulator_dev *rdev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 2768c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 2778c2ecf20Sopenharmony_ci int ret, reg, mask, pattern; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); 2808c2ecf20Sopenharmony_ci if (ret) 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return max8997_update_reg(i2c, reg, ~pattern, mask); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int max8997_get_voltage_register(struct regulator_dev *rdev, 2878c2ecf20Sopenharmony_ci int *_reg, int *_shift, int *_mask) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 2908c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 2918c2ecf20Sopenharmony_ci int reg, shift = 0, mask = 0x3f; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci switch (rid) { 2948c2ecf20Sopenharmony_ci case MAX8997_LDO1 ... MAX8997_LDO21: 2958c2ecf20Sopenharmony_ci reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 2988c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK1DVS1; 2998c2ecf20Sopenharmony_ci if (max8997->buck1_gpiodvs) 3008c2ecf20Sopenharmony_ci reg += max8997->buck125_gpioindex; 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 3038c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK2DVS1; 3048c2ecf20Sopenharmony_ci if (max8997->buck2_gpiodvs) 3058c2ecf20Sopenharmony_ci reg += max8997->buck125_gpioindex; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case MAX8997_BUCK3: 3088c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK3DVS; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case MAX8997_BUCK4: 3118c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK4DVS; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 3148c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK5DVS1; 3158c2ecf20Sopenharmony_ci if (max8997->buck5_gpiodvs) 3168c2ecf20Sopenharmony_ci reg += max8997->buck125_gpioindex; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case MAX8997_BUCK7: 3198c2ecf20Sopenharmony_ci reg = MAX8997_REG_BUCK7DVS; 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: 3228c2ecf20Sopenharmony_ci reg = MAX8997_REG_SAFEOUTCTRL; 3238c2ecf20Sopenharmony_ci shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0; 3248c2ecf20Sopenharmony_ci mask = 0x3; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case MAX8997_CHARGER_CV: 3278c2ecf20Sopenharmony_ci reg = MAX8997_REG_MBCCTRL3; 3288c2ecf20Sopenharmony_ci shift = 0; 3298c2ecf20Sopenharmony_ci mask = 0xf; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci case MAX8997_CHARGER: 3328c2ecf20Sopenharmony_ci reg = MAX8997_REG_MBCCTRL4; 3338c2ecf20Sopenharmony_ci shift = 0; 3348c2ecf20Sopenharmony_ci mask = 0xf; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case MAX8997_CHARGER_TOPOFF: 3378c2ecf20Sopenharmony_ci reg = MAX8997_REG_MBCCTRL5; 3388c2ecf20Sopenharmony_ci shift = 0; 3398c2ecf20Sopenharmony_ci mask = 0xf; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci default: 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci *_reg = reg; 3468c2ecf20Sopenharmony_ci *_shift = shift; 3478c2ecf20Sopenharmony_ci *_mask = mask; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int max8997_get_voltage_sel(struct regulator_dev *rdev) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 3558c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 3568c2ecf20Sopenharmony_ci int reg, shift, mask, ret; 3578c2ecf20Sopenharmony_ci u8 val; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); 3608c2ecf20Sopenharmony_ci if (ret) 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ret = max8997_read_reg(i2c, reg, &val); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci val >>= shift; 3688c2ecf20Sopenharmony_ci val &= mask; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return val; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic inline int max8997_get_voltage_proper_val( 3748c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc, 3758c2ecf20Sopenharmony_ci int min_vol, int max_vol) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci int i; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (desc == NULL) 3808c2ecf20Sopenharmony_ci return -EINVAL; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (max_vol < desc->min || min_vol > desc->max) 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (min_vol < desc->min) 3868c2ecf20Sopenharmony_ci min_vol = desc->min; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci i = DIV_ROUND_UP(min_vol - desc->min, desc->step); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (desc->min + desc->step * i > max_vol) 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return i; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int max8997_set_voltage_charger_cv(struct regulator_dev *rdev, 3978c2ecf20Sopenharmony_ci int min_uV, int max_uV, unsigned *selector) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 4008c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 4018c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 4028c2ecf20Sopenharmony_ci int lb, ub; 4038c2ecf20Sopenharmony_ci int reg, shift = 0, mask, ret = 0; 4048c2ecf20Sopenharmony_ci u8 val = 0x0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (rid != MAX8997_CHARGER_CV) 4078c2ecf20Sopenharmony_ci return -EINVAL; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (max_uV < 4000000 || min_uV > 4350000) 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (min_uV <= 4000000) 4178c2ecf20Sopenharmony_ci val = 0x1; 4188c2ecf20Sopenharmony_ci else if (min_uV <= 4200000 && max_uV >= 4200000) 4198c2ecf20Sopenharmony_ci val = 0x0; 4208c2ecf20Sopenharmony_ci else { 4218c2ecf20Sopenharmony_ci lb = (min_uV - 4000001) / 20000 + 2; 4228c2ecf20Sopenharmony_ci ub = (max_uV - 4000000) / 20000 + 1; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (lb > ub) 4258c2ecf20Sopenharmony_ci return -EINVAL; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (lb < 0xf) 4288c2ecf20Sopenharmony_ci val = lb; 4298c2ecf20Sopenharmony_ci else { 4308c2ecf20Sopenharmony_ci if (ub >= 0xf) 4318c2ecf20Sopenharmony_ci val = 0xf; 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci *selector = val; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci ret = max8997_update_reg(i2c, reg, val << shift, mask); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* 4458c2ecf20Sopenharmony_ci * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF 4468c2ecf20Sopenharmony_ci * BUCK1, 2, and 5 are available if they are not controlled by gpio 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistatic int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, 4498c2ecf20Sopenharmony_ci int min_uV, int max_uV, unsigned *selector) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 4528c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 4538c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc; 4548c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 4558c2ecf20Sopenharmony_ci int i, reg, shift, mask, ret; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci switch (rid) { 4588c2ecf20Sopenharmony_ci case MAX8997_LDO1 ... MAX8997_LDO21: 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci case MAX8997_BUCK1 ... MAX8997_BUCK5: 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci case MAX8997_BUCK6: 4638c2ecf20Sopenharmony_ci return -EINVAL; 4648c2ecf20Sopenharmony_ci case MAX8997_BUCK7: 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci case MAX8997_CHARGER: 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case MAX8997_CHARGER_TOPOFF: 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci default: 4718c2ecf20Sopenharmony_ci return -EINVAL; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci desc = reg_voltage_map[rid]; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); 4778c2ecf20Sopenharmony_ci if (i < 0) 4788c2ecf20Sopenharmony_ci return i; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); 4818c2ecf20Sopenharmony_ci if (ret) 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ret = max8997_update_reg(i2c, reg, i << shift, mask << shift); 4858c2ecf20Sopenharmony_ci *selector = i; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return ret; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev, 4918c2ecf20Sopenharmony_ci unsigned int old_selector, 4928c2ecf20Sopenharmony_ci unsigned int new_selector) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 4958c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 4968c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc = reg_voltage_map[rid]; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* Delay is required only if the voltage is increasing */ 4998c2ecf20Sopenharmony_ci if (old_selector >= new_selector) 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* No need to delay if gpio_dvs_mode */ 5038c2ecf20Sopenharmony_ci switch (rid) { 5048c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 5058c2ecf20Sopenharmony_ci if (max8997->buck1_gpiodvs) 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 5098c2ecf20Sopenharmony_ci if (max8997->buck2_gpiodvs) 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 5138c2ecf20Sopenharmony_ci if (max8997->buck5_gpiodvs) 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci switch (rid) { 5198c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 5208c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 5218c2ecf20Sopenharmony_ci case MAX8997_BUCK4: 5228c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 5238c2ecf20Sopenharmony_ci return DIV_ROUND_UP(desc->step * (new_selector - old_selector), 5248c2ecf20Sopenharmony_ci max8997->ramp_delay * 1000); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/* 5318c2ecf20Sopenharmony_ci * Assess the damage on the voltage setting of BUCK1,2,5 by the change. 5328c2ecf20Sopenharmony_ci * 5338c2ecf20Sopenharmony_ci * When GPIO-DVS mode is used for multiple bucks, changing the voltage value 5348c2ecf20Sopenharmony_ci * of one of the bucks may affect that of another buck, which is the side 5358c2ecf20Sopenharmony_ci * effect of the change (set_voltage). This function examines the GPIO-DVS 5368c2ecf20Sopenharmony_ci * configurations and checks whether such side-effect exists. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_cistatic int max8997_assess_side_effect(struct regulator_dev *rdev, 5398c2ecf20Sopenharmony_ci u8 new_val, int *best) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 5428c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 5438c2ecf20Sopenharmony_ci u8 *buckx_val[3]; 5448c2ecf20Sopenharmony_ci bool buckx_gpiodvs[3]; 5458c2ecf20Sopenharmony_ci int side_effect[8]; 5468c2ecf20Sopenharmony_ci int min_side_effect = INT_MAX; 5478c2ecf20Sopenharmony_ci int i; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci *best = -1; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci switch (rid) { 5528c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 5538c2ecf20Sopenharmony_ci rid = 0; 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 5568c2ecf20Sopenharmony_ci rid = 1; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 5598c2ecf20Sopenharmony_ci rid = 2; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci default: 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci buckx_val[0] = max8997->buck1_vol; 5668c2ecf20Sopenharmony_ci buckx_val[1] = max8997->buck2_vol; 5678c2ecf20Sopenharmony_ci buckx_val[2] = max8997->buck5_vol; 5688c2ecf20Sopenharmony_ci buckx_gpiodvs[0] = max8997->buck1_gpiodvs; 5698c2ecf20Sopenharmony_ci buckx_gpiodvs[1] = max8997->buck2_gpiodvs; 5708c2ecf20Sopenharmony_ci buckx_gpiodvs[2] = max8997->buck5_gpiodvs; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 5738c2ecf20Sopenharmony_ci int others; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (new_val != (buckx_val[rid])[i]) { 5768c2ecf20Sopenharmony_ci side_effect[i] = -1; 5778c2ecf20Sopenharmony_ci continue; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci side_effect[i] = 0; 5818c2ecf20Sopenharmony_ci for (others = 0; others < 3; others++) { 5828c2ecf20Sopenharmony_ci int diff; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (others == rid) 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci if (buckx_gpiodvs[others] == false) 5878c2ecf20Sopenharmony_ci continue; /* Not affected */ 5888c2ecf20Sopenharmony_ci diff = (buckx_val[others])[i] - 5898c2ecf20Sopenharmony_ci (buckx_val[others])[max8997->buck125_gpioindex]; 5908c2ecf20Sopenharmony_ci if (diff > 0) 5918c2ecf20Sopenharmony_ci side_effect[i] += diff; 5928c2ecf20Sopenharmony_ci else if (diff < 0) 5938c2ecf20Sopenharmony_ci side_effect[i] -= diff; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci if (side_effect[i] == 0) { 5968c2ecf20Sopenharmony_ci *best = i; 5978c2ecf20Sopenharmony_ci return 0; /* NO SIDE EFFECT! Use This! */ 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci if (side_effect[i] < min_side_effect) { 6008c2ecf20Sopenharmony_ci min_side_effect = side_effect[i]; 6018c2ecf20Sopenharmony_ci *best = i; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (*best == -1) 6068c2ecf20Sopenharmony_ci return -EINVAL; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return side_effect[*best]; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* 6128c2ecf20Sopenharmony_ci * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls 6138c2ecf20Sopenharmony_ci * max8997_set_voltage_ldobuck to do the job. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_cistatic int max8997_set_voltage_buck(struct regulator_dev *rdev, 6168c2ecf20Sopenharmony_ci int min_uV, int max_uV, unsigned *selector) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 6198c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 6208c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc; 6218c2ecf20Sopenharmony_ci int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; 6228c2ecf20Sopenharmony_ci bool gpio_dvs_mode = false; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci switch (rid) { 6288c2ecf20Sopenharmony_ci case MAX8997_BUCK1: 6298c2ecf20Sopenharmony_ci if (max8997->buck1_gpiodvs) 6308c2ecf20Sopenharmony_ci gpio_dvs_mode = true; 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci case MAX8997_BUCK2: 6338c2ecf20Sopenharmony_ci if (max8997->buck2_gpiodvs) 6348c2ecf20Sopenharmony_ci gpio_dvs_mode = true; 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci case MAX8997_BUCK5: 6378c2ecf20Sopenharmony_ci if (max8997->buck5_gpiodvs) 6388c2ecf20Sopenharmony_ci gpio_dvs_mode = true; 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!gpio_dvs_mode) 6438c2ecf20Sopenharmony_ci return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, 6448c2ecf20Sopenharmony_ci selector); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci desc = reg_voltage_map[rid]; 6478c2ecf20Sopenharmony_ci new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); 6488c2ecf20Sopenharmony_ci if (new_val < 0) 6498c2ecf20Sopenharmony_ci return new_val; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci tmp_dmg = INT_MAX; 6528c2ecf20Sopenharmony_ci tmp_idx = -1; 6538c2ecf20Sopenharmony_ci tmp_val = -1; 6548c2ecf20Sopenharmony_ci do { 6558c2ecf20Sopenharmony_ci damage = max8997_assess_side_effect(rdev, new_val, &new_idx); 6568c2ecf20Sopenharmony_ci if (damage == 0) 6578c2ecf20Sopenharmony_ci goto out; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (tmp_dmg > damage) { 6608c2ecf20Sopenharmony_ci tmp_idx = new_idx; 6618c2ecf20Sopenharmony_ci tmp_val = new_val; 6628c2ecf20Sopenharmony_ci tmp_dmg = damage; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci new_val++; 6668c2ecf20Sopenharmony_ci } while (desc->min + desc->step * new_val <= desc->max); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci new_idx = tmp_idx; 6698c2ecf20Sopenharmony_ci new_val = tmp_val; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (max8997->ignore_gpiodvs_side_effect == false) 6728c2ecf20Sopenharmony_ci return -EINVAL; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dev_warn(&rdev->dev, 6758c2ecf20Sopenharmony_ci "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET: %d -> %d\n", 6768c2ecf20Sopenharmony_ci max8997->buck125_gpioindex, tmp_idx); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciout: 6798c2ecf20Sopenharmony_ci if (new_idx < 0 || new_val < 0) 6808c2ecf20Sopenharmony_ci return -EINVAL; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci max8997->buck125_gpioindex = new_idx; 6838c2ecf20Sopenharmony_ci max8997_set_gpio(max8997); 6848c2ecf20Sopenharmony_ci *selector = new_val; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/* For SAFEOUT1 and SAFEOUT2 */ 6908c2ecf20Sopenharmony_cistatic int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev, 6918c2ecf20Sopenharmony_ci unsigned selector) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 6948c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 6958c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 6968c2ecf20Sopenharmony_ci int reg, shift = 0, mask, ret; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2) 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); 7028c2ecf20Sopenharmony_ci if (ret) 7038c2ecf20Sopenharmony_ci return ret; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return max8997_update_reg(i2c, reg, selector << shift, mask << shift); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int max8997_reg_disable_suspend(struct regulator_dev *rdev) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct max8997_data *max8997 = rdev_get_drvdata(rdev); 7118c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8997->iodev->i2c; 7128c2ecf20Sopenharmony_ci int ret, reg, mask, pattern; 7138c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); 7168c2ecf20Sopenharmony_ci if (ret) 7178c2ecf20Sopenharmony_ci return ret; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci max8997_read_reg(i2c, reg, &max8997->saved_states[rid]); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (rid == MAX8997_LDO1 || 7228c2ecf20Sopenharmony_ci rid == MAX8997_LDO10 || 7238c2ecf20Sopenharmony_ci rid == MAX8997_LDO21) { 7248c2ecf20Sopenharmony_ci dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n", 7258c2ecf20Sopenharmony_ci rdev->desc->name); 7268c2ecf20Sopenharmony_ci return max8997_update_reg(i2c, reg, 0x40, mask); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n", 7308c2ecf20Sopenharmony_ci rdev->desc->name, max8997->saved_states[rid] & mask, 7318c2ecf20Sopenharmony_ci (~pattern) & mask); 7328c2ecf20Sopenharmony_ci return max8997_update_reg(i2c, reg, ~pattern, mask); 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_ldo_ops = { 7368c2ecf20Sopenharmony_ci .list_voltage = max8997_list_voltage, 7378c2ecf20Sopenharmony_ci .is_enabled = max8997_reg_is_enabled, 7388c2ecf20Sopenharmony_ci .enable = max8997_reg_enable, 7398c2ecf20Sopenharmony_ci .disable = max8997_reg_disable, 7408c2ecf20Sopenharmony_ci .get_voltage_sel = max8997_get_voltage_sel, 7418c2ecf20Sopenharmony_ci .set_voltage = max8997_set_voltage_ldobuck, 7428c2ecf20Sopenharmony_ci .set_suspend_disable = max8997_reg_disable_suspend, 7438c2ecf20Sopenharmony_ci}; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_buck_ops = { 7468c2ecf20Sopenharmony_ci .list_voltage = max8997_list_voltage, 7478c2ecf20Sopenharmony_ci .is_enabled = max8997_reg_is_enabled, 7488c2ecf20Sopenharmony_ci .enable = max8997_reg_enable, 7498c2ecf20Sopenharmony_ci .disable = max8997_reg_disable, 7508c2ecf20Sopenharmony_ci .get_voltage_sel = max8997_get_voltage_sel, 7518c2ecf20Sopenharmony_ci .set_voltage = max8997_set_voltage_buck, 7528c2ecf20Sopenharmony_ci .set_voltage_time_sel = max8997_set_voltage_buck_time_sel, 7538c2ecf20Sopenharmony_ci .set_suspend_disable = max8997_reg_disable_suspend, 7548c2ecf20Sopenharmony_ci}; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_fixedvolt_ops = { 7578c2ecf20Sopenharmony_ci .list_voltage = max8997_list_voltage, 7588c2ecf20Sopenharmony_ci .is_enabled = max8997_reg_is_enabled, 7598c2ecf20Sopenharmony_ci .enable = max8997_reg_enable, 7608c2ecf20Sopenharmony_ci .disable = max8997_reg_disable, 7618c2ecf20Sopenharmony_ci .set_suspend_disable = max8997_reg_disable_suspend, 7628c2ecf20Sopenharmony_ci}; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_safeout_ops = { 7658c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 7668c2ecf20Sopenharmony_ci .is_enabled = max8997_reg_is_enabled, 7678c2ecf20Sopenharmony_ci .enable = max8997_reg_enable, 7688c2ecf20Sopenharmony_ci .disable = max8997_reg_disable, 7698c2ecf20Sopenharmony_ci .get_voltage_sel = max8997_get_voltage_sel, 7708c2ecf20Sopenharmony_ci .set_voltage_sel = max8997_set_voltage_safeout_sel, 7718c2ecf20Sopenharmony_ci .set_suspend_disable = max8997_reg_disable_suspend, 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_fixedstate_ops = { 7758c2ecf20Sopenharmony_ci .list_voltage = max8997_list_voltage_charger_cv, 7768c2ecf20Sopenharmony_ci .get_voltage_sel = max8997_get_voltage_sel, 7778c2ecf20Sopenharmony_ci .set_voltage = max8997_set_voltage_charger_cv, 7788c2ecf20Sopenharmony_ci}; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic int max8997_set_current_limit(struct regulator_dev *rdev, 7818c2ecf20Sopenharmony_ci int min_uA, int max_uA) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci unsigned dummy; 7848c2ecf20Sopenharmony_ci int rid = rdev_get_id(rdev); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) 7878c2ecf20Sopenharmony_ci return -EINVAL; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* Reuse max8997_set_voltage_ldobuck to set current_limit. */ 7908c2ecf20Sopenharmony_ci return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int max8997_get_current_limit(struct regulator_dev *rdev) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci int sel, rid = rdev_get_id(rdev); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) 7988c2ecf20Sopenharmony_ci return -EINVAL; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci sel = max8997_get_voltage_sel(rdev); 8018c2ecf20Sopenharmony_ci if (sel < 0) 8028c2ecf20Sopenharmony_ci return sel; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Reuse max8997_list_voltage to get current_limit. */ 8058c2ecf20Sopenharmony_ci return max8997_list_voltage(rdev, sel); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_charger_ops = { 8098c2ecf20Sopenharmony_ci .is_enabled = max8997_reg_is_enabled, 8108c2ecf20Sopenharmony_ci .enable = max8997_reg_enable, 8118c2ecf20Sopenharmony_ci .disable = max8997_reg_disable, 8128c2ecf20Sopenharmony_ci .get_current_limit = max8997_get_current_limit, 8138c2ecf20Sopenharmony_ci .set_current_limit = max8997_set_current_limit, 8148c2ecf20Sopenharmony_ci}; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic const struct regulator_ops max8997_charger_fixedstate_ops = { 8178c2ecf20Sopenharmony_ci .get_current_limit = max8997_get_current_limit, 8188c2ecf20Sopenharmony_ci .set_current_limit = max8997_set_current_limit, 8198c2ecf20Sopenharmony_ci}; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\ 8228c2ecf20Sopenharmony_ci .name = #_name, \ 8238c2ecf20Sopenharmony_ci .id = MAX8997_##_name, \ 8248c2ecf20Sopenharmony_ci .ops = &_ops, \ 8258c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 8268c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\ 8308c2ecf20Sopenharmony_ci .name = #_name, \ 8318c2ecf20Sopenharmony_ci .id = MAX8997_##_name, \ 8328c2ecf20Sopenharmony_ci .ops = &_ops, \ 8338c2ecf20Sopenharmony_ci .type = REGULATOR_CURRENT, \ 8348c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic struct regulator_desc regulators[] = { 8388c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops), 8398c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops), 8408c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops), 8418c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops), 8428c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops), 8438c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops), 8448c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops), 8458c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops), 8468c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops), 8478c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops), 8488c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops), 8498c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops), 8508c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops), 8518c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops), 8528c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops), 8538c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops), 8548c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops), 8558c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops), 8568c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops), 8578c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops), 8588c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops), 8598c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops), 8608c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops), 8618c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops), 8628c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops), 8638c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops), 8648c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops), 8658c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops), 8668c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops), 8678c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops), 8688c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops), 8698c2ecf20Sopenharmony_ci MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops), 8708c2ecf20Sopenharmony_ci MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops), 8718c2ecf20Sopenharmony_ci MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF, 8728c2ecf20Sopenharmony_ci max8997_charger_fixedstate_ops), 8738c2ecf20Sopenharmony_ci}; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 8768c2ecf20Sopenharmony_cistatic int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, 8778c2ecf20Sopenharmony_ci struct max8997_platform_data *pdata, 8788c2ecf20Sopenharmony_ci struct device_node *pmic_np) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int i, gpio; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 8838c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(pmic_np, 8848c2ecf20Sopenharmony_ci "max8997,pmic-buck125-dvs-gpios", i); 8858c2ecf20Sopenharmony_ci if (!gpio_is_valid(gpio)) { 8868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); 8878c2ecf20Sopenharmony_ci return -EINVAL; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci pdata->buck125_gpios[i] = gpio; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, 8958c2ecf20Sopenharmony_ci struct max8997_platform_data *pdata) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); 8988c2ecf20Sopenharmony_ci struct device_node *pmic_np, *regulators_np, *reg_np; 8998c2ecf20Sopenharmony_ci struct max8997_regulator_data *rdata; 9008c2ecf20Sopenharmony_ci unsigned int i, dvs_voltage_nr = 1, ret; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci pmic_np = iodev->dev->of_node; 9038c2ecf20Sopenharmony_ci if (!pmic_np) { 9048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not find pmic sub-node\n"); 9058c2ecf20Sopenharmony_ci return -ENODEV; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci regulators_np = of_get_child_by_name(pmic_np, "regulators"); 9098c2ecf20Sopenharmony_ci if (!regulators_np) { 9108c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not find regulators sub-node\n"); 9118c2ecf20Sopenharmony_ci return -EINVAL; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* count the number of regulators to be supported in pmic */ 9158c2ecf20Sopenharmony_ci pdata->num_regulators = of_get_child_count(regulators_np); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci rdata = devm_kcalloc(&pdev->dev, 9188c2ecf20Sopenharmony_ci pdata->num_regulators, sizeof(*rdata), 9198c2ecf20Sopenharmony_ci GFP_KERNEL); 9208c2ecf20Sopenharmony_ci if (!rdata) { 9218c2ecf20Sopenharmony_ci of_node_put(regulators_np); 9228c2ecf20Sopenharmony_ci return -ENOMEM; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci pdata->regulators = rdata; 9268c2ecf20Sopenharmony_ci for_each_child_of_node(regulators_np, reg_np) { 9278c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulators); i++) 9288c2ecf20Sopenharmony_ci if (of_node_name_eq(reg_np, regulators[i].name)) 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(regulators)) { 9328c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n", 9338c2ecf20Sopenharmony_ci reg_np); 9348c2ecf20Sopenharmony_ci continue; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci rdata->id = i; 9388c2ecf20Sopenharmony_ci rdata->initdata = of_get_regulator_init_data(&pdev->dev, 9398c2ecf20Sopenharmony_ci reg_np, 9408c2ecf20Sopenharmony_ci ®ulators[i]); 9418c2ecf20Sopenharmony_ci rdata->reg_node = reg_np; 9428c2ecf20Sopenharmony_ci rdata++; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci of_node_put(regulators_np); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL)) 9478c2ecf20Sopenharmony_ci pdata->buck1_gpiodvs = true; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL)) 9508c2ecf20Sopenharmony_ci pdata->buck2_gpiodvs = true; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL)) 9538c2ecf20Sopenharmony_ci pdata->buck5_gpiodvs = true; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || 9568c2ecf20Sopenharmony_ci pdata->buck5_gpiodvs) { 9578c2ecf20Sopenharmony_ci ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); 9588c2ecf20Sopenharmony_ci if (ret) 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (of_property_read_u32(pmic_np, 9628c2ecf20Sopenharmony_ci "max8997,pmic-buck125-default-dvs-idx", 9638c2ecf20Sopenharmony_ci &pdata->buck125_default_idx)) { 9648c2ecf20Sopenharmony_ci pdata->buck125_default_idx = 0; 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci if (pdata->buck125_default_idx >= 8) { 9678c2ecf20Sopenharmony_ci pdata->buck125_default_idx = 0; 9688c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n"); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (of_get_property(pmic_np, 9738c2ecf20Sopenharmony_ci "max8997,pmic-ignore-gpiodvs-side-effect", NULL)) 9748c2ecf20Sopenharmony_ci pdata->ignore_gpiodvs_side_effect = true; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci dvs_voltage_nr = 8; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (of_property_read_u32_array(pmic_np, 9808c2ecf20Sopenharmony_ci "max8997,pmic-buck1-dvs-voltage", 9818c2ecf20Sopenharmony_ci pdata->buck1_voltage, dvs_voltage_nr)) { 9828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "buck1 voltages not specified\n"); 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (of_property_read_u32_array(pmic_np, 9878c2ecf20Sopenharmony_ci "max8997,pmic-buck2-dvs-voltage", 9888c2ecf20Sopenharmony_ci pdata->buck2_voltage, dvs_voltage_nr)) { 9898c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "buck2 voltages not specified\n"); 9908c2ecf20Sopenharmony_ci return -EINVAL; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (of_property_read_u32_array(pmic_np, 9948c2ecf20Sopenharmony_ci "max8997,pmic-buck5-dvs-voltage", 9958c2ecf20Sopenharmony_ci pdata->buck5_voltage, dvs_voltage_nr)) { 9968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "buck5 voltages not specified\n"); 9978c2ecf20Sopenharmony_ci return -EINVAL; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci#else 10038c2ecf20Sopenharmony_cistatic int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, 10048c2ecf20Sopenharmony_ci struct max8997_platform_data *pdata) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */ 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic int max8997_pmic_probe(struct platform_device *pdev) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); 10138c2ecf20Sopenharmony_ci struct max8997_platform_data *pdata = iodev->pdata; 10148c2ecf20Sopenharmony_ci struct regulator_config config = { }; 10158c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 10168c2ecf20Sopenharmony_ci struct max8997_data *max8997; 10178c2ecf20Sopenharmony_ci struct i2c_client *i2c; 10188c2ecf20Sopenharmony_ci int i, ret, nr_dvs; 10198c2ecf20Sopenharmony_ci u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (!pdata) { 10228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No platform init data supplied.\n"); 10238c2ecf20Sopenharmony_ci return -ENODEV; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (iodev->dev->of_node) { 10278c2ecf20Sopenharmony_ci ret = max8997_pmic_dt_parse_pdata(pdev, pdata); 10288c2ecf20Sopenharmony_ci if (ret) 10298c2ecf20Sopenharmony_ci return ret; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data), 10338c2ecf20Sopenharmony_ci GFP_KERNEL); 10348c2ecf20Sopenharmony_ci if (!max8997) 10358c2ecf20Sopenharmony_ci return -ENOMEM; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci max8997->dev = &pdev->dev; 10388c2ecf20Sopenharmony_ci max8997->iodev = iodev; 10398c2ecf20Sopenharmony_ci max8997->num_regulators = pdata->num_regulators; 10408c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, max8997); 10418c2ecf20Sopenharmony_ci i2c = max8997->iodev->i2c; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci max8997->buck125_gpioindex = pdata->buck125_default_idx; 10448c2ecf20Sopenharmony_ci max8997->buck1_gpiodvs = pdata->buck1_gpiodvs; 10458c2ecf20Sopenharmony_ci max8997->buck2_gpiodvs = pdata->buck2_gpiodvs; 10468c2ecf20Sopenharmony_ci max8997->buck5_gpiodvs = pdata->buck5_gpiodvs; 10478c2ecf20Sopenharmony_ci memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); 10488c2ecf20Sopenharmony_ci max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || 10518c2ecf20Sopenharmony_ci pdata->buck5_gpiodvs) ? 8 : 1; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci for (i = 0; i < nr_dvs; i++) { 10548c2ecf20Sopenharmony_ci max8997->buck1_vol[i] = ret = 10558c2ecf20Sopenharmony_ci max8997_get_voltage_proper_val( 10568c2ecf20Sopenharmony_ci &buck1245_voltage_map_desc, 10578c2ecf20Sopenharmony_ci pdata->buck1_voltage[i], 10588c2ecf20Sopenharmony_ci pdata->buck1_voltage[i] + 10598c2ecf20Sopenharmony_ci buck1245_voltage_map_desc.step); 10608c2ecf20Sopenharmony_ci if (ret < 0) 10618c2ecf20Sopenharmony_ci return ret; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci max8997->buck2_vol[i] = ret = 10648c2ecf20Sopenharmony_ci max8997_get_voltage_proper_val( 10658c2ecf20Sopenharmony_ci &buck1245_voltage_map_desc, 10668c2ecf20Sopenharmony_ci pdata->buck2_voltage[i], 10678c2ecf20Sopenharmony_ci pdata->buck2_voltage[i] + 10688c2ecf20Sopenharmony_ci buck1245_voltage_map_desc.step); 10698c2ecf20Sopenharmony_ci if (ret < 0) 10708c2ecf20Sopenharmony_ci return ret; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci max8997->buck5_vol[i] = ret = 10738c2ecf20Sopenharmony_ci max8997_get_voltage_proper_val( 10748c2ecf20Sopenharmony_ci &buck1245_voltage_map_desc, 10758c2ecf20Sopenharmony_ci pdata->buck5_voltage[i], 10768c2ecf20Sopenharmony_ci pdata->buck5_voltage[i] + 10778c2ecf20Sopenharmony_ci buck1245_voltage_map_desc.step); 10788c2ecf20Sopenharmony_ci if (ret < 0) 10798c2ecf20Sopenharmony_ci return ret; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (max_buck1 < max8997->buck1_vol[i]) 10828c2ecf20Sopenharmony_ci max_buck1 = max8997->buck1_vol[i]; 10838c2ecf20Sopenharmony_ci if (max_buck2 < max8997->buck2_vol[i]) 10848c2ecf20Sopenharmony_ci max_buck2 = max8997->buck2_vol[i]; 10858c2ecf20Sopenharmony_ci if (max_buck5 < max8997->buck5_vol[i]) 10868c2ecf20Sopenharmony_ci max_buck5 = max8997->buck5_vol[i]; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* For the safety, set max voltage before setting up */ 10908c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 10918c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, 10928c2ecf20Sopenharmony_ci max_buck1, 0x3f); 10938c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, 10948c2ecf20Sopenharmony_ci max_buck2, 0x3f); 10958c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, 10968c2ecf20Sopenharmony_ci max_buck5, 0x3f); 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci /* Initialize all the DVS related BUCK registers */ 11008c2ecf20Sopenharmony_ci for (i = 0; i < nr_dvs; i++) { 11018c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, 11028c2ecf20Sopenharmony_ci max8997->buck1_vol[i], 11038c2ecf20Sopenharmony_ci 0x3f); 11048c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, 11058c2ecf20Sopenharmony_ci max8997->buck2_vol[i], 11068c2ecf20Sopenharmony_ci 0x3f); 11078c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, 11088c2ecf20Sopenharmony_ci max8997->buck5_vol[i], 11098c2ecf20Sopenharmony_ci 0x3f); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* 11138c2ecf20Sopenharmony_ci * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. 11148c2ecf20Sopenharmony_ci * If at least one of them cares, set gpios. 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_ci if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || 11178c2ecf20Sopenharmony_ci pdata->buck5_gpiodvs) { 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (!gpio_is_valid(pdata->buck125_gpios[0]) || 11208c2ecf20Sopenharmony_ci !gpio_is_valid(pdata->buck125_gpios[1]) || 11218c2ecf20Sopenharmony_ci !gpio_is_valid(pdata->buck125_gpios[2])) { 11228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "GPIO NOT VALID\n"); 11238c2ecf20Sopenharmony_ci return -EINVAL; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], 11278c2ecf20Sopenharmony_ci "MAX8997 SET1"); 11288c2ecf20Sopenharmony_ci if (ret) 11298c2ecf20Sopenharmony_ci return ret; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], 11328c2ecf20Sopenharmony_ci "MAX8997 SET2"); 11338c2ecf20Sopenharmony_ci if (ret) 11348c2ecf20Sopenharmony_ci return ret; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], 11378c2ecf20Sopenharmony_ci "MAX8997 SET3"); 11388c2ecf20Sopenharmony_ci if (ret) 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck125_gpios[0], 11428c2ecf20Sopenharmony_ci (max8997->buck125_gpioindex >> 2) 11438c2ecf20Sopenharmony_ci & 0x1); /* SET1 */ 11448c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck125_gpios[1], 11458c2ecf20Sopenharmony_ci (max8997->buck125_gpioindex >> 1) 11468c2ecf20Sopenharmony_ci & 0x1); /* SET2 */ 11478c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck125_gpios[2], 11488c2ecf20Sopenharmony_ci (max8997->buck125_gpioindex >> 0) 11498c2ecf20Sopenharmony_ci & 0x1); /* SET3 */ 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* DVS-GPIO disabled */ 11538c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ? 11548c2ecf20Sopenharmony_ci (1 << 1) : (0 << 1), 1 << 1); 11558c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ? 11568c2ecf20Sopenharmony_ci (1 << 1) : (0 << 1), 1 << 1); 11578c2ecf20Sopenharmony_ci max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ? 11588c2ecf20Sopenharmony_ci (1 << 1) : (0 << 1), 1 << 1); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* Misc Settings */ 11618c2ecf20Sopenharmony_ci max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ 11628c2ecf20Sopenharmony_ci max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_regulators; i++) { 11658c2ecf20Sopenharmony_ci const struct voltage_map_desc *desc; 11668c2ecf20Sopenharmony_ci int id = pdata->regulators[i].id; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci desc = reg_voltage_map[id]; 11698c2ecf20Sopenharmony_ci if (desc) { 11708c2ecf20Sopenharmony_ci regulators[id].n_voltages = 11718c2ecf20Sopenharmony_ci (desc->max - desc->min) / desc->step + 1; 11728c2ecf20Sopenharmony_ci } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) { 11738c2ecf20Sopenharmony_ci regulators[id].volt_table = safeoutvolt; 11748c2ecf20Sopenharmony_ci regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt); 11758c2ecf20Sopenharmony_ci } else if (id == MAX8997_CHARGER_CV) { 11768c2ecf20Sopenharmony_ci regulators[id].n_voltages = 16; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci config.dev = max8997->dev; 11808c2ecf20Sopenharmony_ci config.init_data = pdata->regulators[i].initdata; 11818c2ecf20Sopenharmony_ci config.driver_data = max8997; 11828c2ecf20Sopenharmony_ci config.of_node = pdata->regulators[i].reg_node; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, ®ulators[id], 11858c2ecf20Sopenharmony_ci &config); 11868c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 11878c2ecf20Sopenharmony_ci dev_err(max8997->dev, "regulator init failed for %d\n", 11888c2ecf20Sopenharmony_ci id); 11898c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic const struct platform_device_id max8997_pmic_id[] = { 11978c2ecf20Sopenharmony_ci { "max8997-pmic", 0}, 11988c2ecf20Sopenharmony_ci { }, 11998c2ecf20Sopenharmony_ci}; 12008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max8997_pmic_id); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic struct platform_driver max8997_pmic_driver = { 12038c2ecf20Sopenharmony_ci .driver = { 12048c2ecf20Sopenharmony_ci .name = "max8997-pmic", 12058c2ecf20Sopenharmony_ci }, 12068c2ecf20Sopenharmony_ci .probe = max8997_pmic_probe, 12078c2ecf20Sopenharmony_ci .id_table = max8997_pmic_id, 12088c2ecf20Sopenharmony_ci}; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic int __init max8997_pmic_init(void) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci return platform_driver_register(&max8997_pmic_driver); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_cisubsys_initcall(max8997_pmic_init); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void __exit max8997_pmic_cleanup(void) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci platform_driver_unregister(&max8997_pmic_driver); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_cimodule_exit(max8997_pmic_cleanup); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver"); 12238c2ecf20Sopenharmony_ciMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 12248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1225