18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// max8998.c - Voltage regulator driver for the Maxim 8998 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2009-2010 Samsung Electronics 68c2ecf20Sopenharmony_ci// Kyungmin Park <kyungmin.park@samsung.com> 78c2ecf20Sopenharmony_ci// Marek Szyprowski <m.szyprowski@samsung.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 218c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/max8998.h> 238c2ecf20Sopenharmony_ci#include <linux/mfd/max8998-private.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct max8998_data { 268c2ecf20Sopenharmony_ci struct device *dev; 278c2ecf20Sopenharmony_ci struct max8998_dev *iodev; 288c2ecf20Sopenharmony_ci int num_regulators; 298c2ecf20Sopenharmony_ci u8 buck1_vol[4]; /* voltages for selection */ 308c2ecf20Sopenharmony_ci u8 buck2_vol[2]; 318c2ecf20Sopenharmony_ci unsigned int buck1_idx; /* index to last changed voltage */ 328c2ecf20Sopenharmony_ci /* value in a set */ 338c2ecf20Sopenharmony_ci unsigned int buck2_idx; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const unsigned int charger_current_table[] = { 378c2ecf20Sopenharmony_ci 90000, 380000, 475000, 550000, 570000, 600000, 700000, 800000, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int max8998_get_enable_register(struct regulator_dev *rdev, 418c2ecf20Sopenharmony_ci int *reg, int *shift) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int ldo = rdev_get_id(rdev); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci switch (ldo) { 468c2ecf20Sopenharmony_ci case MAX8998_LDO2 ... MAX8998_LDO5: 478c2ecf20Sopenharmony_ci *reg = MAX8998_REG_ONOFF1; 488c2ecf20Sopenharmony_ci *shift = 3 - (ldo - MAX8998_LDO2); 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci case MAX8998_LDO6 ... MAX8998_LDO13: 518c2ecf20Sopenharmony_ci *reg = MAX8998_REG_ONOFF2; 528c2ecf20Sopenharmony_ci *shift = 7 - (ldo - MAX8998_LDO6); 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci case MAX8998_LDO14 ... MAX8998_LDO17: 558c2ecf20Sopenharmony_ci *reg = MAX8998_REG_ONOFF3; 568c2ecf20Sopenharmony_ci *shift = 7 - (ldo - MAX8998_LDO14); 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci case MAX8998_BUCK1 ... MAX8998_BUCK4: 598c2ecf20Sopenharmony_ci *reg = MAX8998_REG_ONOFF1; 608c2ecf20Sopenharmony_ci *shift = 7 - (ldo - MAX8998_BUCK1); 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case MAX8998_EN32KHZ_AP ... MAX8998_ENVICHG: 638c2ecf20Sopenharmony_ci *reg = MAX8998_REG_ONOFF4; 648c2ecf20Sopenharmony_ci *shift = 7 - (ldo - MAX8998_EN32KHZ_AP); 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci case MAX8998_ESAFEOUT1 ... MAX8998_ESAFEOUT2: 678c2ecf20Sopenharmony_ci *reg = MAX8998_REG_CHGR2; 688c2ecf20Sopenharmony_ci *shift = 7 - (ldo - MAX8998_ESAFEOUT1); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case MAX8998_CHARGER: 718c2ecf20Sopenharmony_ci *reg = MAX8998_REG_CHGR2; 728c2ecf20Sopenharmony_ci *shift = 0; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci default: 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int max8998_ldo_is_enabled(struct regulator_dev *rdev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 848c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 858c2ecf20Sopenharmony_ci int ret, reg, shift = 8; 868c2ecf20Sopenharmony_ci u8 val; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ret = max8998_get_enable_register(rdev, ®, &shift); 898c2ecf20Sopenharmony_ci if (ret) 908c2ecf20Sopenharmony_ci return ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = max8998_read_reg(i2c, reg, &val); 938c2ecf20Sopenharmony_ci if (ret) 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return val & (1 << shift); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int max8998_ldo_is_enabled_inverted(struct regulator_dev *rdev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return (!max8998_ldo_is_enabled(rdev)); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int max8998_ldo_enable(struct regulator_dev *rdev) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 1078c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 1088c2ecf20Sopenharmony_ci int reg, shift = 8, ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ret = max8998_get_enable_register(rdev, ®, &shift); 1118c2ecf20Sopenharmony_ci if (ret) 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int max8998_ldo_disable(struct regulator_dev *rdev) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 1208c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 1218c2ecf20Sopenharmony_ci int reg, shift = 8, ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci ret = max8998_get_enable_register(rdev, ®, &shift); 1248c2ecf20Sopenharmony_ci if (ret) 1258c2ecf20Sopenharmony_ci return ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return max8998_update_reg(i2c, reg, 0, 1<<shift); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int max8998_get_voltage_register(struct regulator_dev *rdev, 1318c2ecf20Sopenharmony_ci int *_reg, int *_shift, int *_mask) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int ldo = rdev_get_id(rdev); 1348c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 1358c2ecf20Sopenharmony_ci int reg, shift = 0, mask = 0xff; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci switch (ldo) { 1388c2ecf20Sopenharmony_ci case MAX8998_LDO2 ... MAX8998_LDO3: 1398c2ecf20Sopenharmony_ci reg = MAX8998_REG_LDO2_LDO3; 1408c2ecf20Sopenharmony_ci mask = 0xf; 1418c2ecf20Sopenharmony_ci if (ldo == MAX8998_LDO2) 1428c2ecf20Sopenharmony_ci shift = 4; 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci shift = 0; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case MAX8998_LDO4 ... MAX8998_LDO7: 1478c2ecf20Sopenharmony_ci reg = MAX8998_REG_LDO4 + (ldo - MAX8998_LDO4); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case MAX8998_LDO8 ... MAX8998_LDO9: 1508c2ecf20Sopenharmony_ci reg = MAX8998_REG_LDO8_LDO9; 1518c2ecf20Sopenharmony_ci mask = 0xf; 1528c2ecf20Sopenharmony_ci if (ldo == MAX8998_LDO8) 1538c2ecf20Sopenharmony_ci shift = 4; 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci shift = 0; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case MAX8998_LDO10 ... MAX8998_LDO11: 1588c2ecf20Sopenharmony_ci reg = MAX8998_REG_LDO10_LDO11; 1598c2ecf20Sopenharmony_ci if (ldo == MAX8998_LDO10) { 1608c2ecf20Sopenharmony_ci shift = 5; 1618c2ecf20Sopenharmony_ci mask = 0x7; 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci shift = 0; 1648c2ecf20Sopenharmony_ci mask = 0x1f; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case MAX8998_LDO12 ... MAX8998_LDO17: 1688c2ecf20Sopenharmony_ci reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12); 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case MAX8998_BUCK1: 1718c2ecf20Sopenharmony_ci reg = MAX8998_REG_BUCK1_VOLTAGE1 + max8998->buck1_idx; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case MAX8998_BUCK2: 1748c2ecf20Sopenharmony_ci reg = MAX8998_REG_BUCK2_VOLTAGE1 + max8998->buck2_idx; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci case MAX8998_BUCK3: 1778c2ecf20Sopenharmony_ci reg = MAX8998_REG_BUCK3; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case MAX8998_BUCK4: 1808c2ecf20Sopenharmony_ci reg = MAX8998_REG_BUCK4; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci default: 1838c2ecf20Sopenharmony_ci return -EINVAL; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci *_reg = reg; 1878c2ecf20Sopenharmony_ci *_shift = shift; 1888c2ecf20Sopenharmony_ci *_mask = mask; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int max8998_get_voltage_sel(struct regulator_dev *rdev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 1968c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 1978c2ecf20Sopenharmony_ci int reg, shift = 0, mask, ret; 1988c2ecf20Sopenharmony_ci u8 val; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); 2018c2ecf20Sopenharmony_ci if (ret) 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ret = max8998_read_reg(i2c, reg, &val); 2058c2ecf20Sopenharmony_ci if (ret) 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci val >>= shift; 2098c2ecf20Sopenharmony_ci val &= mask; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return val; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev, 2158c2ecf20Sopenharmony_ci unsigned selector) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 2188c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 2198c2ecf20Sopenharmony_ci int reg, shift = 0, mask, ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); 2228c2ecf20Sopenharmony_ci if (ret) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = max8998_update_reg(i2c, reg, selector<<shift, mask<<shift); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic inline void buck1_gpio_set(int gpio1, int gpio2, int v) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci gpio_set_value(gpio1, v & 0x1); 2338c2ecf20Sopenharmony_ci gpio_set_value(gpio2, (v >> 1) & 0x1); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic inline void buck2_gpio_set(int gpio, int v) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci gpio_set_value(gpio, v & 0x1); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, 2428c2ecf20Sopenharmony_ci unsigned selector) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 2458c2ecf20Sopenharmony_ci struct max8998_platform_data *pdata = max8998->iodev->pdata; 2468c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 2478c2ecf20Sopenharmony_ci int buck = rdev_get_id(rdev); 2488c2ecf20Sopenharmony_ci int reg, shift = 0, mask, ret, j; 2498c2ecf20Sopenharmony_ci static u8 buck1_last_val; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); 2528c2ecf20Sopenharmony_ci if (ret) 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci switch (buck) { 2568c2ecf20Sopenharmony_ci case MAX8998_BUCK1: 2578c2ecf20Sopenharmony_ci dev_dbg(max8998->dev, 2588c2ecf20Sopenharmony_ci "BUCK1, selector:%d, buck1_vol1:%d, buck1_vol2:%d\n" 2598c2ecf20Sopenharmony_ci "buck1_vol3:%d, buck1_vol4:%d\n", 2608c2ecf20Sopenharmony_ci selector, max8998->buck1_vol[0], max8998->buck1_vol[1], 2618c2ecf20Sopenharmony_ci max8998->buck1_vol[2], max8998->buck1_vol[3]); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (gpio_is_valid(pdata->buck1_set1) && 2648c2ecf20Sopenharmony_ci gpio_is_valid(pdata->buck1_set2)) { 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* check if requested voltage */ 2678c2ecf20Sopenharmony_ci /* value is already defined */ 2688c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) { 2698c2ecf20Sopenharmony_ci if (max8998->buck1_vol[j] == selector) { 2708c2ecf20Sopenharmony_ci max8998->buck1_idx = j; 2718c2ecf20Sopenharmony_ci buck1_gpio_set(pdata->buck1_set1, 2728c2ecf20Sopenharmony_ci pdata->buck1_set2, j); 2738c2ecf20Sopenharmony_ci goto buck1_exit; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (pdata->buck_voltage_lock) 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* no predefine regulator found */ 2818c2ecf20Sopenharmony_ci max8998->buck1_idx = (buck1_last_val % 2) + 2; 2828c2ecf20Sopenharmony_ci dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n", 2838c2ecf20Sopenharmony_ci max8998->buck1_idx); 2848c2ecf20Sopenharmony_ci max8998->buck1_vol[max8998->buck1_idx] = selector; 2858c2ecf20Sopenharmony_ci ret = max8998_get_voltage_register(rdev, ®, 2868c2ecf20Sopenharmony_ci &shift, 2878c2ecf20Sopenharmony_ci &mask); 2888c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, reg, selector); 2898c2ecf20Sopenharmony_ci buck1_gpio_set(pdata->buck1_set1, 2908c2ecf20Sopenharmony_ci pdata->buck1_set2, max8998->buck1_idx); 2918c2ecf20Sopenharmony_ci buck1_last_val++; 2928c2ecf20Sopenharmony_cibuck1_exit: 2938c2ecf20Sopenharmony_ci dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n", 2948c2ecf20Sopenharmony_ci i2c->name, gpio_get_value(pdata->buck1_set1), 2958c2ecf20Sopenharmony_ci gpio_get_value(pdata->buck1_set2)); 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci } else { 2988c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, reg, selector); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci case MAX8998_BUCK2: 3038c2ecf20Sopenharmony_ci dev_dbg(max8998->dev, 3048c2ecf20Sopenharmony_ci "BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n", 3058c2ecf20Sopenharmony_ci selector, max8998->buck2_vol[0], max8998->buck2_vol[1]); 3068c2ecf20Sopenharmony_ci if (gpio_is_valid(pdata->buck2_set3)) { 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* check if requested voltage */ 3098c2ecf20Sopenharmony_ci /* value is already defined */ 3108c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) { 3118c2ecf20Sopenharmony_ci if (max8998->buck2_vol[j] == selector) { 3128c2ecf20Sopenharmony_ci max8998->buck2_idx = j; 3138c2ecf20Sopenharmony_ci buck2_gpio_set(pdata->buck2_set3, j); 3148c2ecf20Sopenharmony_ci goto buck2_exit; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (pdata->buck_voltage_lock) 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci max8998_get_voltage_register(rdev, 3228c2ecf20Sopenharmony_ci ®, &shift, &mask); 3238c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, reg, selector); 3248c2ecf20Sopenharmony_ci max8998->buck2_vol[max8998->buck2_idx] = selector; 3258c2ecf20Sopenharmony_ci buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx); 3268c2ecf20Sopenharmony_cibuck2_exit: 3278c2ecf20Sopenharmony_ci dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, 3288c2ecf20Sopenharmony_ci gpio_get_value(pdata->buck2_set3)); 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, reg, selector); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci case MAX8998_BUCK3: 3358c2ecf20Sopenharmony_ci case MAX8998_BUCK4: 3368c2ecf20Sopenharmony_ci ret = max8998_update_reg(i2c, reg, selector<<shift, 3378c2ecf20Sopenharmony_ci mask<<shift); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, 3458c2ecf20Sopenharmony_ci unsigned int old_selector, 3468c2ecf20Sopenharmony_ci unsigned int new_selector) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 3498c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 3508c2ecf20Sopenharmony_ci int buck = rdev_get_id(rdev); 3518c2ecf20Sopenharmony_ci u8 val = 0; 3528c2ecf20Sopenharmony_ci int difference, ret; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (buck < MAX8998_BUCK1 || buck > MAX8998_BUCK4) 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Voltage stabilization */ 3588c2ecf20Sopenharmony_ci ret = max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val); 3598c2ecf20Sopenharmony_ci if (ret) 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */ 3638c2ecf20Sopenharmony_ci /* MAX8998 has ENRAMP bit implemented, so test it*/ 3648c2ecf20Sopenharmony_ci if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci difference = (new_selector - old_selector) * rdev->desc->uV_step / 1000; 3688c2ecf20Sopenharmony_ci if (difference > 0) 3698c2ecf20Sopenharmony_ci return DIV_ROUND_UP(difference, (val & 0x0f) + 1); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int max8998_set_current_limit(struct regulator_dev *rdev, 3758c2ecf20Sopenharmony_ci int min_uA, int max_uA) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 3788c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 3798c2ecf20Sopenharmony_ci unsigned int n_currents = rdev->desc->n_current_limits; 3808c2ecf20Sopenharmony_ci int i, sel = -1; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (n_currents == 0) 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (rdev->desc->curr_table) { 3868c2ecf20Sopenharmony_ci const unsigned int *curr_table = rdev->desc->curr_table; 3878c2ecf20Sopenharmony_ci bool ascend = curr_table[n_currents - 1] > curr_table[0]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* search for closest to maximum */ 3908c2ecf20Sopenharmony_ci if (ascend) { 3918c2ecf20Sopenharmony_ci for (i = n_currents - 1; i >= 0; i--) { 3928c2ecf20Sopenharmony_ci if (min_uA <= curr_table[i] && 3938c2ecf20Sopenharmony_ci curr_table[i] <= max_uA) { 3948c2ecf20Sopenharmony_ci sel = i; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci for (i = 0; i < n_currents; i++) { 4008c2ecf20Sopenharmony_ci if (min_uA <= curr_table[i] && 4018c2ecf20Sopenharmony_ci curr_table[i] <= max_uA) { 4028c2ecf20Sopenharmony_ci sel = i; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (sel < 0) 4108c2ecf20Sopenharmony_ci return -EINVAL; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci sel <<= ffs(rdev->desc->csel_mask) - 1; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return max8998_update_reg(i2c, rdev->desc->csel_reg, 4158c2ecf20Sopenharmony_ci sel, rdev->desc->csel_mask); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int max8998_get_current_limit(struct regulator_dev *rdev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct max8998_data *max8998 = rdev_get_drvdata(rdev); 4218c2ecf20Sopenharmony_ci struct i2c_client *i2c = max8998->iodev->i2c; 4228c2ecf20Sopenharmony_ci u8 val; 4238c2ecf20Sopenharmony_ci int ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = max8998_read_reg(i2c, rdev->desc->csel_reg, &val); 4268c2ecf20Sopenharmony_ci if (ret != 0) 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci val &= rdev->desc->csel_mask; 4308c2ecf20Sopenharmony_ci val >>= ffs(rdev->desc->csel_mask) - 1; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (rdev->desc->curr_table) { 4338c2ecf20Sopenharmony_ci if (val >= rdev->desc->n_current_limits) 4348c2ecf20Sopenharmony_ci return -EINVAL; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return rdev->desc->curr_table[val]; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return -EINVAL; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic const struct regulator_ops max8998_ldo_ops = { 4438c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 4448c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 4458c2ecf20Sopenharmony_ci .is_enabled = max8998_ldo_is_enabled, 4468c2ecf20Sopenharmony_ci .enable = max8998_ldo_enable, 4478c2ecf20Sopenharmony_ci .disable = max8998_ldo_disable, 4488c2ecf20Sopenharmony_ci .get_voltage_sel = max8998_get_voltage_sel, 4498c2ecf20Sopenharmony_ci .set_voltage_sel = max8998_set_voltage_ldo_sel, 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic const struct regulator_ops max8998_buck_ops = { 4538c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 4548c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 4558c2ecf20Sopenharmony_ci .is_enabled = max8998_ldo_is_enabled, 4568c2ecf20Sopenharmony_ci .enable = max8998_ldo_enable, 4578c2ecf20Sopenharmony_ci .disable = max8998_ldo_disable, 4588c2ecf20Sopenharmony_ci .get_voltage_sel = max8998_get_voltage_sel, 4598c2ecf20Sopenharmony_ci .set_voltage_sel = max8998_set_voltage_buck_sel, 4608c2ecf20Sopenharmony_ci .set_voltage_time_sel = max8998_set_voltage_buck_time_sel, 4618c2ecf20Sopenharmony_ci}; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic const struct regulator_ops max8998_charger_ops = { 4648c2ecf20Sopenharmony_ci .set_current_limit = max8998_set_current_limit, 4658c2ecf20Sopenharmony_ci .get_current_limit = max8998_get_current_limit, 4668c2ecf20Sopenharmony_ci .is_enabled = max8998_ldo_is_enabled_inverted, 4678c2ecf20Sopenharmony_ci /* Swapped as register is inverted */ 4688c2ecf20Sopenharmony_ci .enable = max8998_ldo_disable, 4698c2ecf20Sopenharmony_ci .disable = max8998_ldo_enable, 4708c2ecf20Sopenharmony_ci}; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic const struct regulator_ops max8998_others_ops = { 4738c2ecf20Sopenharmony_ci .is_enabled = max8998_ldo_is_enabled, 4748c2ecf20Sopenharmony_ci .enable = max8998_ldo_enable, 4758c2ecf20Sopenharmony_ci .disable = max8998_ldo_disable, 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#define MAX8998_LINEAR_REG(_name, _ops, _min, _step, _max) \ 4798c2ecf20Sopenharmony_ci { \ 4808c2ecf20Sopenharmony_ci .name = #_name, \ 4818c2ecf20Sopenharmony_ci .id = MAX8998_##_name, \ 4828c2ecf20Sopenharmony_ci .ops = _ops, \ 4838c2ecf20Sopenharmony_ci .min_uV = (_min), \ 4848c2ecf20Sopenharmony_ci .uV_step = (_step), \ 4858c2ecf20Sopenharmony_ci .n_voltages = ((_max) - (_min)) / (_step) + 1, \ 4868c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 4878c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci#define MAX8998_CURRENT_REG(_name, _ops, _table, _reg, _mask) \ 4918c2ecf20Sopenharmony_ci { \ 4928c2ecf20Sopenharmony_ci .name = #_name, \ 4938c2ecf20Sopenharmony_ci .id = MAX8998_##_name, \ 4948c2ecf20Sopenharmony_ci .ops = _ops, \ 4958c2ecf20Sopenharmony_ci .curr_table = _table, \ 4968c2ecf20Sopenharmony_ci .n_current_limits = ARRAY_SIZE(_table), \ 4978c2ecf20Sopenharmony_ci .csel_reg = _reg, \ 4988c2ecf20Sopenharmony_ci .csel_mask = _mask, \ 4998c2ecf20Sopenharmony_ci .type = REGULATOR_CURRENT, \ 5008c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci#define MAX8998_OTHERS_REG(_name, _id) \ 5048c2ecf20Sopenharmony_ci { \ 5058c2ecf20Sopenharmony_ci .name = #_name, \ 5068c2ecf20Sopenharmony_ci .id = _id, \ 5078c2ecf20Sopenharmony_ci .ops = &max8998_others_ops, \ 5088c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 5098c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic const struct regulator_desc regulators[] = { 5138c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO2, &max8998_ldo_ops, 800000, 50000, 1300000), 5148c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO3, &max8998_ldo_ops, 800000, 50000, 1300000), 5158c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO4, &max8998_ldo_ops, 1600000, 100000, 3600000), 5168c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO5, &max8998_ldo_ops, 1600000, 100000, 3600000), 5178c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO6, &max8998_ldo_ops, 1600000, 100000, 3600000), 5188c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO7, &max8998_ldo_ops, 1600000, 100000, 3600000), 5198c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO8, &max8998_ldo_ops, 3000000, 100000, 3600000), 5208c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO9, &max8998_ldo_ops, 2800000, 100000, 3100000), 5218c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO10, &max8998_ldo_ops, 950000, 50000, 1300000), 5228c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO11, &max8998_ldo_ops, 1600000, 100000, 3600000), 5238c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO12, &max8998_ldo_ops, 800000, 100000, 3300000), 5248c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO13, &max8998_ldo_ops, 800000, 100000, 3300000), 5258c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO14, &max8998_ldo_ops, 1200000, 100000, 3300000), 5268c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO15, &max8998_ldo_ops, 1200000, 100000, 3300000), 5278c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO16, &max8998_ldo_ops, 1600000, 100000, 3600000), 5288c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(LDO17, &max8998_ldo_ops, 1600000, 100000, 3600000), 5298c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(BUCK1, &max8998_buck_ops, 750000, 25000, 1525000), 5308c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(BUCK2, &max8998_buck_ops, 750000, 25000, 1525000), 5318c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(BUCK3, &max8998_buck_ops, 1600000, 100000, 3600000), 5328c2ecf20Sopenharmony_ci MAX8998_LINEAR_REG(BUCK4, &max8998_buck_ops, 800000, 100000, 2300000), 5338c2ecf20Sopenharmony_ci MAX8998_OTHERS_REG(EN32KHz-AP, MAX8998_EN32KHZ_AP), 5348c2ecf20Sopenharmony_ci MAX8998_OTHERS_REG(EN32KHz-CP, MAX8998_EN32KHZ_CP), 5358c2ecf20Sopenharmony_ci MAX8998_OTHERS_REG(ENVICHG, MAX8998_ENVICHG), 5368c2ecf20Sopenharmony_ci MAX8998_OTHERS_REG(ESAFEOUT1, MAX8998_ESAFEOUT1), 5378c2ecf20Sopenharmony_ci MAX8998_OTHERS_REG(ESAFEOUT2, MAX8998_ESAFEOUT2), 5388c2ecf20Sopenharmony_ci MAX8998_CURRENT_REG(CHARGER, &max8998_charger_ops, 5398c2ecf20Sopenharmony_ci charger_current_table, MAX8998_REG_CHGR1, 0x7), 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int max8998_pmic_dt_parse_dvs_gpio(struct max8998_dev *iodev, 5438c2ecf20Sopenharmony_ci struct max8998_platform_data *pdata, 5448c2ecf20Sopenharmony_ci struct device_node *pmic_np) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int gpio; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 0); 5498c2ecf20Sopenharmony_ci if (!gpio_is_valid(gpio)) { 5508c2ecf20Sopenharmony_ci dev_err(iodev->dev, "invalid buck1 gpio[0]: %d\n", gpio); 5518c2ecf20Sopenharmony_ci return -EINVAL; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci pdata->buck1_set1 = gpio; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 1); 5568c2ecf20Sopenharmony_ci if (!gpio_is_valid(gpio)) { 5578c2ecf20Sopenharmony_ci dev_err(iodev->dev, "invalid buck1 gpio[1]: %d\n", gpio); 5588c2ecf20Sopenharmony_ci return -EINVAL; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci pdata->buck1_set2 = gpio; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck2-dvs-gpio", 0); 5638c2ecf20Sopenharmony_ci if (!gpio_is_valid(gpio)) { 5648c2ecf20Sopenharmony_ci dev_err(iodev->dev, "invalid buck 2 gpio: %d\n", gpio); 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci pdata->buck2_set3 = gpio; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, 5738c2ecf20Sopenharmony_ci struct max8998_platform_data *pdata) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct device_node *pmic_np = iodev->dev->of_node; 5768c2ecf20Sopenharmony_ci struct device_node *regulators_np, *reg_np; 5778c2ecf20Sopenharmony_ci struct max8998_regulator_data *rdata; 5788c2ecf20Sopenharmony_ci unsigned int i; 5798c2ecf20Sopenharmony_ci int ret; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci regulators_np = of_get_child_by_name(pmic_np, "regulators"); 5828c2ecf20Sopenharmony_ci if (!regulators_np) { 5838c2ecf20Sopenharmony_ci dev_err(iodev->dev, "could not find regulators sub-node\n"); 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* count the number of regulators to be supported in pmic */ 5888c2ecf20Sopenharmony_ci pdata->num_regulators = of_get_child_count(regulators_np); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci rdata = devm_kcalloc(iodev->dev, 5918c2ecf20Sopenharmony_ci pdata->num_regulators, sizeof(*rdata), 5928c2ecf20Sopenharmony_ci GFP_KERNEL); 5938c2ecf20Sopenharmony_ci if (!rdata) { 5948c2ecf20Sopenharmony_ci of_node_put(regulators_np); 5958c2ecf20Sopenharmony_ci return -ENOMEM; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci pdata->regulators = rdata; 5998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulators); ++i) { 6008c2ecf20Sopenharmony_ci reg_np = of_get_child_by_name(regulators_np, 6018c2ecf20Sopenharmony_ci regulators[i].name); 6028c2ecf20Sopenharmony_ci if (!reg_np) 6038c2ecf20Sopenharmony_ci continue; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci rdata->id = regulators[i].id; 6068c2ecf20Sopenharmony_ci rdata->initdata = of_get_regulator_init_data(iodev->dev, 6078c2ecf20Sopenharmony_ci reg_np, 6088c2ecf20Sopenharmony_ci ®ulators[i]); 6098c2ecf20Sopenharmony_ci rdata->reg_node = reg_np; 6108c2ecf20Sopenharmony_ci ++rdata; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci pdata->num_regulators = rdata - pdata->regulators; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci of_node_put(reg_np); 6158c2ecf20Sopenharmony_ci of_node_put(regulators_np); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); 6188c2ecf20Sopenharmony_ci if (ret) 6198c2ecf20Sopenharmony_ci return -EINVAL; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (of_find_property(pmic_np, "max8998,pmic-buck-voltage-lock", NULL)) 6228c2ecf20Sopenharmony_ci pdata->buck_voltage_lock = true; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ret = of_property_read_u32(pmic_np, 6258c2ecf20Sopenharmony_ci "max8998,pmic-buck1-default-dvs-idx", 6268c2ecf20Sopenharmony_ci &pdata->buck1_default_idx); 6278c2ecf20Sopenharmony_ci if (!ret && pdata->buck1_default_idx >= 4) { 6288c2ecf20Sopenharmony_ci pdata->buck1_default_idx = 0; 6298c2ecf20Sopenharmony_ci dev_warn(iodev->dev, "invalid value for default dvs index, using 0 instead\n"); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = of_property_read_u32(pmic_np, 6338c2ecf20Sopenharmony_ci "max8998,pmic-buck2-default-dvs-idx", 6348c2ecf20Sopenharmony_ci &pdata->buck2_default_idx); 6358c2ecf20Sopenharmony_ci if (!ret && pdata->buck2_default_idx >= 2) { 6368c2ecf20Sopenharmony_ci pdata->buck2_default_idx = 0; 6378c2ecf20Sopenharmony_ci dev_warn(iodev->dev, "invalid value for default dvs index, using 0 instead\n"); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = of_property_read_u32_array(pmic_np, 6418c2ecf20Sopenharmony_ci "max8998,pmic-buck1-dvs-voltage", 6428c2ecf20Sopenharmony_ci pdata->buck1_voltage, 6438c2ecf20Sopenharmony_ci ARRAY_SIZE(pdata->buck1_voltage)); 6448c2ecf20Sopenharmony_ci if (ret) { 6458c2ecf20Sopenharmony_ci dev_err(iodev->dev, "buck1 voltages not specified\n"); 6468c2ecf20Sopenharmony_ci return -EINVAL; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci ret = of_property_read_u32_array(pmic_np, 6508c2ecf20Sopenharmony_ci "max8998,pmic-buck2-dvs-voltage", 6518c2ecf20Sopenharmony_ci pdata->buck2_voltage, 6528c2ecf20Sopenharmony_ci ARRAY_SIZE(pdata->buck2_voltage)); 6538c2ecf20Sopenharmony_ci if (ret) { 6548c2ecf20Sopenharmony_ci dev_err(iodev->dev, "buck2 voltages not specified\n"); 6558c2ecf20Sopenharmony_ci return -EINVAL; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int max8998_pmic_probe(struct platform_device *pdev) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); 6648c2ecf20Sopenharmony_ci struct max8998_platform_data *pdata = iodev->pdata; 6658c2ecf20Sopenharmony_ci struct regulator_config config = { }; 6668c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 6678c2ecf20Sopenharmony_ci struct max8998_data *max8998; 6688c2ecf20Sopenharmony_ci struct i2c_client *i2c; 6698c2ecf20Sopenharmony_ci int i, ret; 6708c2ecf20Sopenharmony_ci unsigned int v; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (!pdata) { 6738c2ecf20Sopenharmony_ci dev_err(pdev->dev.parent, "No platform init data supplied\n"); 6748c2ecf20Sopenharmony_ci return -ENODEV; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && iodev->dev->of_node) { 6788c2ecf20Sopenharmony_ci ret = max8998_pmic_dt_parse_pdata(iodev, pdata); 6798c2ecf20Sopenharmony_ci if (ret) 6808c2ecf20Sopenharmony_ci return ret; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_data), 6848c2ecf20Sopenharmony_ci GFP_KERNEL); 6858c2ecf20Sopenharmony_ci if (!max8998) 6868c2ecf20Sopenharmony_ci return -ENOMEM; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci max8998->dev = &pdev->dev; 6898c2ecf20Sopenharmony_ci max8998->iodev = iodev; 6908c2ecf20Sopenharmony_ci max8998->num_regulators = pdata->num_regulators; 6918c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, max8998); 6928c2ecf20Sopenharmony_ci i2c = max8998->iodev->i2c; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci max8998->buck1_idx = pdata->buck1_default_idx; 6958c2ecf20Sopenharmony_ci max8998->buck2_idx = pdata->buck2_default_idx; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* NOTE: */ 6988c2ecf20Sopenharmony_ci /* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */ 6998c2ecf20Sopenharmony_ci /* will be displayed */ 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* Check if MAX8998 voltage selection GPIOs are defined */ 7028c2ecf20Sopenharmony_ci if (gpio_is_valid(pdata->buck1_set1) && 7038c2ecf20Sopenharmony_ci gpio_is_valid(pdata->buck1_set2)) { 7048c2ecf20Sopenharmony_ci /* Check if SET1 is not equal to 0 */ 7058c2ecf20Sopenharmony_ci if (!pdata->buck1_set1) { 7068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7078c2ecf20Sopenharmony_ci "MAX8998 SET1 GPIO defined as 0 !\n"); 7088c2ecf20Sopenharmony_ci WARN_ON(!pdata->buck1_set1); 7098c2ecf20Sopenharmony_ci return -EIO; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci /* Check if SET2 is not equal to 0 */ 7128c2ecf20Sopenharmony_ci if (!pdata->buck1_set2) { 7138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7148c2ecf20Sopenharmony_ci "MAX8998 SET2 GPIO defined as 0 !\n"); 7158c2ecf20Sopenharmony_ci WARN_ON(!pdata->buck1_set2); 7168c2ecf20Sopenharmony_ci return -EIO; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); 7208c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck1_set1, 7218c2ecf20Sopenharmony_ci max8998->buck1_idx & 0x1); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2"); 7258c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck1_set2, 7268c2ecf20Sopenharmony_ci (max8998->buck1_idx >> 1) & 0x1); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Set predefined values for BUCK1 registers */ 7298c2ecf20Sopenharmony_ci for (v = 0; v < ARRAY_SIZE(pdata->buck1_voltage); ++v) { 7308c2ecf20Sopenharmony_ci int index = MAX8998_BUCK1 - MAX8998_LDO2; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci i = 0; 7338c2ecf20Sopenharmony_ci while (regulators[index].min_uV + 7348c2ecf20Sopenharmony_ci regulators[index].uV_step * i 7358c2ecf20Sopenharmony_ci < pdata->buck1_voltage[v]) 7368c2ecf20Sopenharmony_ci i++; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci max8998->buck1_vol[v] = i; 7398c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, 7408c2ecf20Sopenharmony_ci MAX8998_REG_BUCK1_VOLTAGE1 + v, i); 7418c2ecf20Sopenharmony_ci if (ret) 7428c2ecf20Sopenharmony_ci return ret; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (gpio_is_valid(pdata->buck2_set3)) { 7478c2ecf20Sopenharmony_ci /* Check if SET3 is not equal to 0 */ 7488c2ecf20Sopenharmony_ci if (!pdata->buck2_set3) { 7498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7508c2ecf20Sopenharmony_ci "MAX8998 SET3 GPIO defined as 0 !\n"); 7518c2ecf20Sopenharmony_ci WARN_ON(!pdata->buck2_set3); 7528c2ecf20Sopenharmony_ci return -EIO; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); 7558c2ecf20Sopenharmony_ci gpio_direction_output(pdata->buck2_set3, 7568c2ecf20Sopenharmony_ci max8998->buck2_idx & 0x1); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* Set predefined values for BUCK2 registers */ 7598c2ecf20Sopenharmony_ci for (v = 0; v < ARRAY_SIZE(pdata->buck2_voltage); ++v) { 7608c2ecf20Sopenharmony_ci int index = MAX8998_BUCK2 - MAX8998_LDO2; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci i = 0; 7638c2ecf20Sopenharmony_ci while (regulators[index].min_uV + 7648c2ecf20Sopenharmony_ci regulators[index].uV_step * i 7658c2ecf20Sopenharmony_ci < pdata->buck2_voltage[v]) 7668c2ecf20Sopenharmony_ci i++; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci max8998->buck2_vol[v] = i; 7698c2ecf20Sopenharmony_ci ret = max8998_write_reg(i2c, 7708c2ecf20Sopenharmony_ci MAX8998_REG_BUCK2_VOLTAGE1 + v, i); 7718c2ecf20Sopenharmony_ci if (ret) 7728c2ecf20Sopenharmony_ci return ret; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_regulators; i++) { 7778c2ecf20Sopenharmony_ci int index = pdata->regulators[i].id - MAX8998_LDO2; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci config.dev = max8998->dev; 7808c2ecf20Sopenharmony_ci config.of_node = pdata->regulators[i].reg_node; 7818c2ecf20Sopenharmony_ci config.init_data = pdata->regulators[i].initdata; 7828c2ecf20Sopenharmony_ci config.driver_data = max8998; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, ®ulators[index], 7858c2ecf20Sopenharmony_ci &config); 7868c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 7878c2ecf20Sopenharmony_ci ret = PTR_ERR(rdev); 7888c2ecf20Sopenharmony_ci dev_err(max8998->dev, "regulator %s init failed (%d)\n", 7898c2ecf20Sopenharmony_ci regulators[index].name, ret); 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic const struct platform_device_id max8998_pmic_id[] = { 7988c2ecf20Sopenharmony_ci { "max8998-pmic", TYPE_MAX8998 }, 7998c2ecf20Sopenharmony_ci { "lp3974-pmic", TYPE_LP3974 }, 8008c2ecf20Sopenharmony_ci { } 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max8998_pmic_id); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic struct platform_driver max8998_pmic_driver = { 8058c2ecf20Sopenharmony_ci .driver = { 8068c2ecf20Sopenharmony_ci .name = "max8998-pmic", 8078c2ecf20Sopenharmony_ci }, 8088c2ecf20Sopenharmony_ci .probe = max8998_pmic_probe, 8098c2ecf20Sopenharmony_ci .id_table = max8998_pmic_id, 8108c2ecf20Sopenharmony_ci}; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int __init max8998_pmic_init(void) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci return platform_driver_register(&max8998_pmic_driver); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_cisubsys_initcall(max8998_pmic_init); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic void __exit max8998_pmic_cleanup(void) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci platform_driver_unregister(&max8998_pmic_driver); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_cimodule_exit(max8998_pmic_cleanup); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 8998 voltage regulator driver"); 8258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 8268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 827