162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// max8997.c - Regulator driver for the Maxim 8997/8966
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (C) 2011 Samsung Electronics
662306a36Sopenharmony_ci// MyungJoo Ham <myungjoo.ham@samsung.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// This driver is based on max8998.c
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bug.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/gpio.h>
1362306a36Sopenharmony_ci#include <linux/of_gpio.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/regulator/driver.h>
1862306a36Sopenharmony_ci#include <linux/regulator/machine.h>
1962306a36Sopenharmony_ci#include <linux/mfd/max8997.h>
2062306a36Sopenharmony_ci#include <linux/mfd/max8997-private.h>
2162306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct max8997_data {
2462306a36Sopenharmony_ci	struct device *dev;
2562306a36Sopenharmony_ci	struct max8997_dev *iodev;
2662306a36Sopenharmony_ci	int num_regulators;
2762306a36Sopenharmony_ci	int ramp_delay; /* in mV/us */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	bool buck1_gpiodvs;
3062306a36Sopenharmony_ci	bool buck2_gpiodvs;
3162306a36Sopenharmony_ci	bool buck5_gpiodvs;
3262306a36Sopenharmony_ci	u8 buck1_vol[8];
3362306a36Sopenharmony_ci	u8 buck2_vol[8];
3462306a36Sopenharmony_ci	u8 buck5_vol[8];
3562306a36Sopenharmony_ci	int buck125_gpios[3];
3662306a36Sopenharmony_ci	int buck125_gpioindex;
3762306a36Sopenharmony_ci	bool ignore_gpiodvs_side_effect;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	u8 saved_states[MAX8997_REG_MAX];
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const unsigned int safeoutvolt[] = {
4362306a36Sopenharmony_ci	4850000,
4462306a36Sopenharmony_ci	4900000,
4562306a36Sopenharmony_ci	4950000,
4662306a36Sopenharmony_ci	3300000,
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline void max8997_set_gpio(struct max8997_data *max8997)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	int set3 = (max8997->buck125_gpioindex) & 0x1;
5262306a36Sopenharmony_ci	int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1;
5362306a36Sopenharmony_ci	int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	gpio_set_value(max8997->buck125_gpios[0], set1);
5662306a36Sopenharmony_ci	gpio_set_value(max8997->buck125_gpios[1], set2);
5762306a36Sopenharmony_ci	gpio_set_value(max8997->buck125_gpios[2], set3);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct voltage_map_desc {
6162306a36Sopenharmony_ci	int min;
6262306a36Sopenharmony_ci	int max;
6362306a36Sopenharmony_ci	int step;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Voltage maps in uV */
6762306a36Sopenharmony_cistatic const struct voltage_map_desc ldo_voltage_map_desc = {
6862306a36Sopenharmony_ci	.min = 800000,	.max = 3950000,	.step = 50000,
6962306a36Sopenharmony_ci}; /* LDO1 ~ 18, 21 all */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic const struct voltage_map_desc buck1245_voltage_map_desc = {
7262306a36Sopenharmony_ci	.min = 650000,	.max = 2225000,	.step = 25000,
7362306a36Sopenharmony_ci}; /* Buck1, 2, 4, 5 */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic const struct voltage_map_desc buck37_voltage_map_desc = {
7662306a36Sopenharmony_ci	.min = 750000,	.max = 3900000,	.step = 50000,
7762306a36Sopenharmony_ci}; /* Buck3, 7 */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* current map in uA */
8062306a36Sopenharmony_cistatic const struct voltage_map_desc charger_current_map_desc = {
8162306a36Sopenharmony_ci	.min = 200000,	.max = 950000,	.step = 50000,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic const struct voltage_map_desc topoff_current_map_desc = {
8562306a36Sopenharmony_ci	.min = 50000,	.max = 200000,	.step = 10000,
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const struct voltage_map_desc *reg_voltage_map[] = {
8962306a36Sopenharmony_ci	[MAX8997_LDO1] = &ldo_voltage_map_desc,
9062306a36Sopenharmony_ci	[MAX8997_LDO2] = &ldo_voltage_map_desc,
9162306a36Sopenharmony_ci	[MAX8997_LDO3] = &ldo_voltage_map_desc,
9262306a36Sopenharmony_ci	[MAX8997_LDO4] = &ldo_voltage_map_desc,
9362306a36Sopenharmony_ci	[MAX8997_LDO5] = &ldo_voltage_map_desc,
9462306a36Sopenharmony_ci	[MAX8997_LDO6] = &ldo_voltage_map_desc,
9562306a36Sopenharmony_ci	[MAX8997_LDO7] = &ldo_voltage_map_desc,
9662306a36Sopenharmony_ci	[MAX8997_LDO8] = &ldo_voltage_map_desc,
9762306a36Sopenharmony_ci	[MAX8997_LDO9] = &ldo_voltage_map_desc,
9862306a36Sopenharmony_ci	[MAX8997_LDO10] = &ldo_voltage_map_desc,
9962306a36Sopenharmony_ci	[MAX8997_LDO11] = &ldo_voltage_map_desc,
10062306a36Sopenharmony_ci	[MAX8997_LDO12] = &ldo_voltage_map_desc,
10162306a36Sopenharmony_ci	[MAX8997_LDO13] = &ldo_voltage_map_desc,
10262306a36Sopenharmony_ci	[MAX8997_LDO14] = &ldo_voltage_map_desc,
10362306a36Sopenharmony_ci	[MAX8997_LDO15] = &ldo_voltage_map_desc,
10462306a36Sopenharmony_ci	[MAX8997_LDO16] = &ldo_voltage_map_desc,
10562306a36Sopenharmony_ci	[MAX8997_LDO17] = &ldo_voltage_map_desc,
10662306a36Sopenharmony_ci	[MAX8997_LDO18] = &ldo_voltage_map_desc,
10762306a36Sopenharmony_ci	[MAX8997_LDO21] = &ldo_voltage_map_desc,
10862306a36Sopenharmony_ci	[MAX8997_BUCK1] = &buck1245_voltage_map_desc,
10962306a36Sopenharmony_ci	[MAX8997_BUCK2] = &buck1245_voltage_map_desc,
11062306a36Sopenharmony_ci	[MAX8997_BUCK3] = &buck37_voltage_map_desc,
11162306a36Sopenharmony_ci	[MAX8997_BUCK4] = &buck1245_voltage_map_desc,
11262306a36Sopenharmony_ci	[MAX8997_BUCK5] = &buck1245_voltage_map_desc,
11362306a36Sopenharmony_ci	[MAX8997_BUCK6] = NULL,
11462306a36Sopenharmony_ci	[MAX8997_BUCK7] = &buck37_voltage_map_desc,
11562306a36Sopenharmony_ci	[MAX8997_EN32KHZ_AP] = NULL,
11662306a36Sopenharmony_ci	[MAX8997_EN32KHZ_CP] = NULL,
11762306a36Sopenharmony_ci	[MAX8997_ENVICHG] = NULL,
11862306a36Sopenharmony_ci	[MAX8997_ESAFEOUT1] = NULL,
11962306a36Sopenharmony_ci	[MAX8997_ESAFEOUT2] = NULL,
12062306a36Sopenharmony_ci	[MAX8997_CHARGER_CV] = NULL,
12162306a36Sopenharmony_ci	[MAX8997_CHARGER] = &charger_current_map_desc,
12262306a36Sopenharmony_ci	[MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
12662306a36Sopenharmony_ci		unsigned int selector)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (rid != MAX8997_CHARGER_CV)
13162306a36Sopenharmony_ci		goto err;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	switch (selector) {
13462306a36Sopenharmony_ci	case 0x00:
13562306a36Sopenharmony_ci		return 4200000;
13662306a36Sopenharmony_ci	case 0x01 ... 0x0E:
13762306a36Sopenharmony_ci		return 4000000 + 20000 * (selector - 0x01);
13862306a36Sopenharmony_ci	case 0x0F:
13962306a36Sopenharmony_ci		return 4350000;
14062306a36Sopenharmony_ci	default:
14162306a36Sopenharmony_ci		return -EINVAL;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_cierr:
14462306a36Sopenharmony_ci	return -EINVAL;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int max8997_list_voltage(struct regulator_dev *rdev,
14862306a36Sopenharmony_ci		unsigned int selector)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	const struct voltage_map_desc *desc;
15162306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
15262306a36Sopenharmony_ci	int val;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (rid < 0 || rid >= ARRAY_SIZE(reg_voltage_map))
15562306a36Sopenharmony_ci		return -EINVAL;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	desc = reg_voltage_map[rid];
15862306a36Sopenharmony_ci	if (desc == NULL)
15962306a36Sopenharmony_ci		return -EINVAL;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	val = desc->min + desc->step * selector;
16262306a36Sopenharmony_ci	if (val > desc->max)
16362306a36Sopenharmony_ci		return -EINVAL;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return val;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int max8997_get_enable_register(struct regulator_dev *rdev,
16962306a36Sopenharmony_ci		int *reg, int *mask, int *pattern)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	switch (rid) {
17462306a36Sopenharmony_ci	case MAX8997_LDO1 ... MAX8997_LDO21:
17562306a36Sopenharmony_ci		*reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
17662306a36Sopenharmony_ci		*mask = 0xC0;
17762306a36Sopenharmony_ci		*pattern = 0xC0;
17862306a36Sopenharmony_ci		break;
17962306a36Sopenharmony_ci	case MAX8997_BUCK1:
18062306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK1CTRL;
18162306a36Sopenharmony_ci		*mask = 0x01;
18262306a36Sopenharmony_ci		*pattern = 0x01;
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	case MAX8997_BUCK2:
18562306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK2CTRL;
18662306a36Sopenharmony_ci		*mask = 0x01;
18762306a36Sopenharmony_ci		*pattern = 0x01;
18862306a36Sopenharmony_ci		break;
18962306a36Sopenharmony_ci	case MAX8997_BUCK3:
19062306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK3CTRL;
19162306a36Sopenharmony_ci		*mask = 0x01;
19262306a36Sopenharmony_ci		*pattern = 0x01;
19362306a36Sopenharmony_ci		break;
19462306a36Sopenharmony_ci	case MAX8997_BUCK4:
19562306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK4CTRL;
19662306a36Sopenharmony_ci		*mask = 0x01;
19762306a36Sopenharmony_ci		*pattern = 0x01;
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	case MAX8997_BUCK5:
20062306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK5CTRL;
20162306a36Sopenharmony_ci		*mask = 0x01;
20262306a36Sopenharmony_ci		*pattern = 0x01;
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	case MAX8997_BUCK6:
20562306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK6CTRL;
20662306a36Sopenharmony_ci		*mask = 0x01;
20762306a36Sopenharmony_ci		*pattern = 0x01;
20862306a36Sopenharmony_ci		break;
20962306a36Sopenharmony_ci	case MAX8997_BUCK7:
21062306a36Sopenharmony_ci		*reg = MAX8997_REG_BUCK7CTRL;
21162306a36Sopenharmony_ci		*mask = 0x01;
21262306a36Sopenharmony_ci		*pattern = 0x01;
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci	case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP:
21562306a36Sopenharmony_ci		*reg = MAX8997_REG_MAINCON1;
21662306a36Sopenharmony_ci		*mask = 0x01 << (rid - MAX8997_EN32KHZ_AP);
21762306a36Sopenharmony_ci		*pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP);
21862306a36Sopenharmony_ci		break;
21962306a36Sopenharmony_ci	case MAX8997_ENVICHG:
22062306a36Sopenharmony_ci		*reg = MAX8997_REG_MBCCTRL1;
22162306a36Sopenharmony_ci		*mask = 0x80;
22262306a36Sopenharmony_ci		*pattern = 0x80;
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci	case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2:
22562306a36Sopenharmony_ci		*reg = MAX8997_REG_SAFEOUTCTRL;
22662306a36Sopenharmony_ci		*mask = 0x40 << (rid - MAX8997_ESAFEOUT1);
22762306a36Sopenharmony_ci		*pattern = 0x40 << (rid - MAX8997_ESAFEOUT1);
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	case MAX8997_CHARGER:
23062306a36Sopenharmony_ci		*reg = MAX8997_REG_MBCCTRL2;
23162306a36Sopenharmony_ci		*mask = 0x40;
23262306a36Sopenharmony_ci		*pattern = 0x40;
23362306a36Sopenharmony_ci		break;
23462306a36Sopenharmony_ci	default:
23562306a36Sopenharmony_ci		/* Not controllable or not exists */
23662306a36Sopenharmony_ci		return -EINVAL;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int max8997_reg_is_enabled(struct regulator_dev *rdev)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
24562306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
24662306a36Sopenharmony_ci	int ret, reg, mask, pattern;
24762306a36Sopenharmony_ci	u8 val;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
25062306a36Sopenharmony_ci	if (ret)
25162306a36Sopenharmony_ci		return ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ret = max8997_read_reg(i2c, reg, &val);
25462306a36Sopenharmony_ci	if (ret)
25562306a36Sopenharmony_ci		return ret;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return (val & mask) == pattern;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int max8997_reg_enable(struct regulator_dev *rdev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
26362306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
26462306a36Sopenharmony_ci	int ret, reg, mask, pattern;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
26762306a36Sopenharmony_ci	if (ret)
26862306a36Sopenharmony_ci		return ret;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return max8997_update_reg(i2c, reg, pattern, mask);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic int max8997_reg_disable(struct regulator_dev *rdev)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
27662306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
27762306a36Sopenharmony_ci	int ret, reg, mask, pattern;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
28062306a36Sopenharmony_ci	if (ret)
28162306a36Sopenharmony_ci		return ret;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return max8997_update_reg(i2c, reg, ~pattern, mask);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic int max8997_get_voltage_register(struct regulator_dev *rdev,
28762306a36Sopenharmony_ci		int *_reg, int *_shift, int *_mask)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
29062306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
29162306a36Sopenharmony_ci	int reg, shift = 0, mask = 0x3f;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	switch (rid) {
29462306a36Sopenharmony_ci	case MAX8997_LDO1 ... MAX8997_LDO21:
29562306a36Sopenharmony_ci		reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	case MAX8997_BUCK1:
29862306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK1DVS1;
29962306a36Sopenharmony_ci		if (max8997->buck1_gpiodvs)
30062306a36Sopenharmony_ci			reg += max8997->buck125_gpioindex;
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	case MAX8997_BUCK2:
30362306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK2DVS1;
30462306a36Sopenharmony_ci		if (max8997->buck2_gpiodvs)
30562306a36Sopenharmony_ci			reg += max8997->buck125_gpioindex;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	case MAX8997_BUCK3:
30862306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK3DVS;
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case MAX8997_BUCK4:
31162306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK4DVS;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	case MAX8997_BUCK5:
31462306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK5DVS1;
31562306a36Sopenharmony_ci		if (max8997->buck5_gpiodvs)
31662306a36Sopenharmony_ci			reg += max8997->buck125_gpioindex;
31762306a36Sopenharmony_ci		break;
31862306a36Sopenharmony_ci	case MAX8997_BUCK7:
31962306a36Sopenharmony_ci		reg = MAX8997_REG_BUCK7DVS;
32062306a36Sopenharmony_ci		break;
32162306a36Sopenharmony_ci	case MAX8997_ESAFEOUT1 ...  MAX8997_ESAFEOUT2:
32262306a36Sopenharmony_ci		reg = MAX8997_REG_SAFEOUTCTRL;
32362306a36Sopenharmony_ci		shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0;
32462306a36Sopenharmony_ci		mask = 0x3;
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	case MAX8997_CHARGER_CV:
32762306a36Sopenharmony_ci		reg = MAX8997_REG_MBCCTRL3;
32862306a36Sopenharmony_ci		shift = 0;
32962306a36Sopenharmony_ci		mask = 0xf;
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci	case MAX8997_CHARGER:
33262306a36Sopenharmony_ci		reg = MAX8997_REG_MBCCTRL4;
33362306a36Sopenharmony_ci		shift = 0;
33462306a36Sopenharmony_ci		mask = 0xf;
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	case MAX8997_CHARGER_TOPOFF:
33762306a36Sopenharmony_ci		reg = MAX8997_REG_MBCCTRL5;
33862306a36Sopenharmony_ci		shift = 0;
33962306a36Sopenharmony_ci		mask = 0xf;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	default:
34262306a36Sopenharmony_ci		return -EINVAL;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	*_reg = reg;
34662306a36Sopenharmony_ci	*_shift = shift;
34762306a36Sopenharmony_ci	*_mask = mask;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return 0;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int max8997_get_voltage_sel(struct regulator_dev *rdev)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
35562306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
35662306a36Sopenharmony_ci	int reg, shift, mask, ret;
35762306a36Sopenharmony_ci	u8 val;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
36062306a36Sopenharmony_ci	if (ret)
36162306a36Sopenharmony_ci		return ret;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	ret = max8997_read_reg(i2c, reg, &val);
36462306a36Sopenharmony_ci	if (ret)
36562306a36Sopenharmony_ci		return ret;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	val >>= shift;
36862306a36Sopenharmony_ci	val &= mask;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return val;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic inline int max8997_get_voltage_proper_val(
37462306a36Sopenharmony_ci		const struct voltage_map_desc *desc,
37562306a36Sopenharmony_ci		int min_vol, int max_vol)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	int i;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (desc == NULL)
38062306a36Sopenharmony_ci		return -EINVAL;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (max_vol < desc->min || min_vol > desc->max)
38362306a36Sopenharmony_ci		return -EINVAL;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (min_vol < desc->min)
38662306a36Sopenharmony_ci		min_vol = desc->min;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (desc->min + desc->step * i > max_vol)
39162306a36Sopenharmony_ci		return -EINVAL;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return i;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int max8997_set_voltage_charger_cv(struct regulator_dev *rdev,
39762306a36Sopenharmony_ci		int min_uV, int max_uV, unsigned *selector)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
40062306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
40162306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
40262306a36Sopenharmony_ci	int lb, ub;
40362306a36Sopenharmony_ci	int reg, shift = 0, mask, ret = 0;
40462306a36Sopenharmony_ci	u8 val = 0x0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (rid != MAX8997_CHARGER_CV)
40762306a36Sopenharmony_ci		return -EINVAL;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
41062306a36Sopenharmony_ci	if (ret)
41162306a36Sopenharmony_ci		return ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (max_uV < 4000000 || min_uV > 4350000)
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (min_uV <= 4000000)
41762306a36Sopenharmony_ci		val = 0x1;
41862306a36Sopenharmony_ci	else if (min_uV <= 4200000 && max_uV >= 4200000)
41962306a36Sopenharmony_ci		val = 0x0;
42062306a36Sopenharmony_ci	else {
42162306a36Sopenharmony_ci		lb = (min_uV - 4000001) / 20000 + 2;
42262306a36Sopenharmony_ci		ub = (max_uV - 4000000) / 20000 + 1;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		if (lb > ub)
42562306a36Sopenharmony_ci			return -EINVAL;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		if (lb < 0xf)
42862306a36Sopenharmony_ci			val = lb;
42962306a36Sopenharmony_ci		else {
43062306a36Sopenharmony_ci			if (ub >= 0xf)
43162306a36Sopenharmony_ci				val = 0xf;
43262306a36Sopenharmony_ci			else
43362306a36Sopenharmony_ci				return -EINVAL;
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	*selector = val;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	ret = max8997_update_reg(i2c, reg, val << shift, mask);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return ret;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/*
44562306a36Sopenharmony_ci * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF
44662306a36Sopenharmony_ci * BUCK1, 2, and 5 are available if they are not controlled by gpio
44762306a36Sopenharmony_ci */
44862306a36Sopenharmony_cistatic int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
44962306a36Sopenharmony_ci		int min_uV, int max_uV, unsigned *selector)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
45262306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
45362306a36Sopenharmony_ci	const struct voltage_map_desc *desc;
45462306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
45562306a36Sopenharmony_ci	int i, reg, shift, mask, ret;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (rid) {
45862306a36Sopenharmony_ci	case MAX8997_LDO1 ... MAX8997_LDO21:
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	case MAX8997_BUCK1 ... MAX8997_BUCK5:
46162306a36Sopenharmony_ci		break;
46262306a36Sopenharmony_ci	case MAX8997_BUCK6:
46362306a36Sopenharmony_ci		return -EINVAL;
46462306a36Sopenharmony_ci	case MAX8997_BUCK7:
46562306a36Sopenharmony_ci		break;
46662306a36Sopenharmony_ci	case MAX8997_CHARGER:
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	case MAX8997_CHARGER_TOPOFF:
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	default:
47162306a36Sopenharmony_ci		return -EINVAL;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	desc = reg_voltage_map[rid];
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	i = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
47762306a36Sopenharmony_ci	if (i < 0)
47862306a36Sopenharmony_ci		return i;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
48162306a36Sopenharmony_ci	if (ret)
48262306a36Sopenharmony_ci		return ret;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	ret = max8997_update_reg(i2c, reg, i << shift, mask << shift);
48562306a36Sopenharmony_ci	*selector = i;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return ret;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev,
49162306a36Sopenharmony_ci						unsigned int old_selector,
49262306a36Sopenharmony_ci						unsigned int new_selector)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
49562306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
49662306a36Sopenharmony_ci	const struct voltage_map_desc *desc = reg_voltage_map[rid];
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Delay is required only if the voltage is increasing */
49962306a36Sopenharmony_ci	if (old_selector >= new_selector)
50062306a36Sopenharmony_ci		return 0;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/* No need to delay if gpio_dvs_mode */
50362306a36Sopenharmony_ci	switch (rid) {
50462306a36Sopenharmony_ci	case MAX8997_BUCK1:
50562306a36Sopenharmony_ci		if (max8997->buck1_gpiodvs)
50662306a36Sopenharmony_ci			return 0;
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	case MAX8997_BUCK2:
50962306a36Sopenharmony_ci		if (max8997->buck2_gpiodvs)
51062306a36Sopenharmony_ci			return 0;
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci	case MAX8997_BUCK5:
51362306a36Sopenharmony_ci		if (max8997->buck5_gpiodvs)
51462306a36Sopenharmony_ci			return 0;
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	switch (rid) {
51962306a36Sopenharmony_ci	case MAX8997_BUCK1:
52062306a36Sopenharmony_ci	case MAX8997_BUCK2:
52162306a36Sopenharmony_ci	case MAX8997_BUCK4:
52262306a36Sopenharmony_ci	case MAX8997_BUCK5:
52362306a36Sopenharmony_ci		return DIV_ROUND_UP(desc->step * (new_selector - old_selector),
52462306a36Sopenharmony_ci				    max8997->ramp_delay * 1000);
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci * Assess the damage on the voltage setting of BUCK1,2,5 by the change.
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci * When GPIO-DVS mode is used for multiple bucks, changing the voltage value
53462306a36Sopenharmony_ci * of one of the bucks may affect that of another buck, which is the side
53562306a36Sopenharmony_ci * effect of the change (set_voltage). This function examines the GPIO-DVS
53662306a36Sopenharmony_ci * configurations and checks whether such side-effect exists.
53762306a36Sopenharmony_ci */
53862306a36Sopenharmony_cistatic int max8997_assess_side_effect(struct regulator_dev *rdev,
53962306a36Sopenharmony_ci		u8 new_val, int *best)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
54262306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
54362306a36Sopenharmony_ci	u8 *buckx_val[3];
54462306a36Sopenharmony_ci	bool buckx_gpiodvs[3];
54562306a36Sopenharmony_ci	int side_effect[8];
54662306a36Sopenharmony_ci	int min_side_effect = INT_MAX;
54762306a36Sopenharmony_ci	int i;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	*best = -1;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	switch (rid) {
55262306a36Sopenharmony_ci	case MAX8997_BUCK1:
55362306a36Sopenharmony_ci		rid = 0;
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case MAX8997_BUCK2:
55662306a36Sopenharmony_ci		rid = 1;
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	case MAX8997_BUCK5:
55962306a36Sopenharmony_ci		rid = 2;
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci	default:
56262306a36Sopenharmony_ci		return -EINVAL;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	buckx_val[0] = max8997->buck1_vol;
56662306a36Sopenharmony_ci	buckx_val[1] = max8997->buck2_vol;
56762306a36Sopenharmony_ci	buckx_val[2] = max8997->buck5_vol;
56862306a36Sopenharmony_ci	buckx_gpiodvs[0] = max8997->buck1_gpiodvs;
56962306a36Sopenharmony_ci	buckx_gpiodvs[1] = max8997->buck2_gpiodvs;
57062306a36Sopenharmony_ci	buckx_gpiodvs[2] = max8997->buck5_gpiodvs;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
57362306a36Sopenharmony_ci		int others;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		if (new_val != (buckx_val[rid])[i]) {
57662306a36Sopenharmony_ci			side_effect[i] = -1;
57762306a36Sopenharmony_ci			continue;
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		side_effect[i] = 0;
58162306a36Sopenharmony_ci		for (others = 0; others < 3; others++) {
58262306a36Sopenharmony_ci			int diff;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci			if (others == rid)
58562306a36Sopenharmony_ci				continue;
58662306a36Sopenharmony_ci			if (buckx_gpiodvs[others] == false)
58762306a36Sopenharmony_ci				continue; /* Not affected */
58862306a36Sopenharmony_ci			diff = (buckx_val[others])[i] -
58962306a36Sopenharmony_ci				(buckx_val[others])[max8997->buck125_gpioindex];
59062306a36Sopenharmony_ci			if (diff > 0)
59162306a36Sopenharmony_ci				side_effect[i] += diff;
59262306a36Sopenharmony_ci			else if (diff < 0)
59362306a36Sopenharmony_ci				side_effect[i] -= diff;
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci		if (side_effect[i] == 0) {
59662306a36Sopenharmony_ci			*best = i;
59762306a36Sopenharmony_ci			return 0; /* NO SIDE EFFECT! Use This! */
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci		if (side_effect[i] < min_side_effect) {
60062306a36Sopenharmony_ci			min_side_effect = side_effect[i];
60162306a36Sopenharmony_ci			*best = i;
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (*best == -1)
60662306a36Sopenharmony_ci		return -EINVAL;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return side_effect[*best];
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci/*
61262306a36Sopenharmony_ci * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls
61362306a36Sopenharmony_ci * max8997_set_voltage_ldobuck to do the job.
61462306a36Sopenharmony_ci */
61562306a36Sopenharmony_cistatic int max8997_set_voltage_buck(struct regulator_dev *rdev,
61662306a36Sopenharmony_ci		int min_uV, int max_uV, unsigned *selector)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
61962306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
62062306a36Sopenharmony_ci	const struct voltage_map_desc *desc;
62162306a36Sopenharmony_ci	int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
62262306a36Sopenharmony_ci	bool gpio_dvs_mode = false;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7)
62562306a36Sopenharmony_ci		return -EINVAL;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	switch (rid) {
62862306a36Sopenharmony_ci	case MAX8997_BUCK1:
62962306a36Sopenharmony_ci		if (max8997->buck1_gpiodvs)
63062306a36Sopenharmony_ci			gpio_dvs_mode = true;
63162306a36Sopenharmony_ci		break;
63262306a36Sopenharmony_ci	case MAX8997_BUCK2:
63362306a36Sopenharmony_ci		if (max8997->buck2_gpiodvs)
63462306a36Sopenharmony_ci			gpio_dvs_mode = true;
63562306a36Sopenharmony_ci		break;
63662306a36Sopenharmony_ci	case MAX8997_BUCK5:
63762306a36Sopenharmony_ci		if (max8997->buck5_gpiodvs)
63862306a36Sopenharmony_ci			gpio_dvs_mode = true;
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (!gpio_dvs_mode)
64362306a36Sopenharmony_ci		return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV,
64462306a36Sopenharmony_ci						selector);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	desc = reg_voltage_map[rid];
64762306a36Sopenharmony_ci	new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
64862306a36Sopenharmony_ci	if (new_val < 0)
64962306a36Sopenharmony_ci		return new_val;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	tmp_dmg = INT_MAX;
65262306a36Sopenharmony_ci	tmp_idx = -1;
65362306a36Sopenharmony_ci	tmp_val = -1;
65462306a36Sopenharmony_ci	do {
65562306a36Sopenharmony_ci		damage = max8997_assess_side_effect(rdev, new_val, &new_idx);
65662306a36Sopenharmony_ci		if (damage == 0)
65762306a36Sopenharmony_ci			goto out;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		if (tmp_dmg > damage) {
66062306a36Sopenharmony_ci			tmp_idx = new_idx;
66162306a36Sopenharmony_ci			tmp_val = new_val;
66262306a36Sopenharmony_ci			tmp_dmg = damage;
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		new_val++;
66662306a36Sopenharmony_ci	} while (desc->min + desc->step * new_val <= desc->max);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	new_idx = tmp_idx;
66962306a36Sopenharmony_ci	new_val = tmp_val;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (max8997->ignore_gpiodvs_side_effect == false)
67262306a36Sopenharmony_ci		return -EINVAL;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	dev_warn(&rdev->dev,
67562306a36Sopenharmony_ci		"MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:  %d -> %d\n",
67662306a36Sopenharmony_ci		max8997->buck125_gpioindex, tmp_idx);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ciout:
67962306a36Sopenharmony_ci	if (new_idx < 0 || new_val < 0)
68062306a36Sopenharmony_ci		return -EINVAL;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	max8997->buck125_gpioindex = new_idx;
68362306a36Sopenharmony_ci	max8997_set_gpio(max8997);
68462306a36Sopenharmony_ci	*selector = new_val;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return 0;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/* For SAFEOUT1 and SAFEOUT2 */
69062306a36Sopenharmony_cistatic int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev,
69162306a36Sopenharmony_ci					   unsigned selector)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
69462306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
69562306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
69662306a36Sopenharmony_ci	int reg, shift = 0, mask, ret;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
69962306a36Sopenharmony_ci		return -EINVAL;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
70262306a36Sopenharmony_ci	if (ret)
70362306a36Sopenharmony_ci		return ret;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	return max8997_update_reg(i2c, reg, selector << shift, mask << shift);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int max8997_reg_disable_suspend(struct regulator_dev *rdev)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
71162306a36Sopenharmony_ci	struct i2c_client *i2c = max8997->iodev->i2c;
71262306a36Sopenharmony_ci	int ret, reg, mask, pattern;
71362306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
71662306a36Sopenharmony_ci	if (ret)
71762306a36Sopenharmony_ci		return ret;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	max8997_read_reg(i2c, reg, &max8997->saved_states[rid]);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (rid == MAX8997_LDO1 ||
72262306a36Sopenharmony_ci			rid == MAX8997_LDO10 ||
72362306a36Sopenharmony_ci			rid == MAX8997_LDO21) {
72462306a36Sopenharmony_ci		dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n",
72562306a36Sopenharmony_ci				rdev->desc->name);
72662306a36Sopenharmony_ci		return max8997_update_reg(i2c, reg, 0x40, mask);
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n",
73062306a36Sopenharmony_ci			rdev->desc->name, max8997->saved_states[rid] & mask,
73162306a36Sopenharmony_ci			(~pattern) & mask);
73262306a36Sopenharmony_ci	return max8997_update_reg(i2c, reg, ~pattern, mask);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic const struct regulator_ops max8997_ldo_ops = {
73662306a36Sopenharmony_ci	.list_voltage		= max8997_list_voltage,
73762306a36Sopenharmony_ci	.is_enabled		= max8997_reg_is_enabled,
73862306a36Sopenharmony_ci	.enable			= max8997_reg_enable,
73962306a36Sopenharmony_ci	.disable		= max8997_reg_disable,
74062306a36Sopenharmony_ci	.get_voltage_sel	= max8997_get_voltage_sel,
74162306a36Sopenharmony_ci	.set_voltage		= max8997_set_voltage_ldobuck,
74262306a36Sopenharmony_ci	.set_suspend_disable	= max8997_reg_disable_suspend,
74362306a36Sopenharmony_ci};
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic const struct regulator_ops max8997_buck_ops = {
74662306a36Sopenharmony_ci	.list_voltage		= max8997_list_voltage,
74762306a36Sopenharmony_ci	.is_enabled		= max8997_reg_is_enabled,
74862306a36Sopenharmony_ci	.enable			= max8997_reg_enable,
74962306a36Sopenharmony_ci	.disable		= max8997_reg_disable,
75062306a36Sopenharmony_ci	.get_voltage_sel	= max8997_get_voltage_sel,
75162306a36Sopenharmony_ci	.set_voltage		= max8997_set_voltage_buck,
75262306a36Sopenharmony_ci	.set_voltage_time_sel	= max8997_set_voltage_buck_time_sel,
75362306a36Sopenharmony_ci	.set_suspend_disable	= max8997_reg_disable_suspend,
75462306a36Sopenharmony_ci};
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic const struct regulator_ops max8997_fixedvolt_ops = {
75762306a36Sopenharmony_ci	.list_voltage		= max8997_list_voltage,
75862306a36Sopenharmony_ci	.is_enabled		= max8997_reg_is_enabled,
75962306a36Sopenharmony_ci	.enable			= max8997_reg_enable,
76062306a36Sopenharmony_ci	.disable		= max8997_reg_disable,
76162306a36Sopenharmony_ci	.set_suspend_disable	= max8997_reg_disable_suspend,
76262306a36Sopenharmony_ci};
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic const struct regulator_ops max8997_safeout_ops = {
76562306a36Sopenharmony_ci	.list_voltage		= regulator_list_voltage_table,
76662306a36Sopenharmony_ci	.is_enabled		= max8997_reg_is_enabled,
76762306a36Sopenharmony_ci	.enable			= max8997_reg_enable,
76862306a36Sopenharmony_ci	.disable		= max8997_reg_disable,
76962306a36Sopenharmony_ci	.get_voltage_sel	= max8997_get_voltage_sel,
77062306a36Sopenharmony_ci	.set_voltage_sel	= max8997_set_voltage_safeout_sel,
77162306a36Sopenharmony_ci	.set_suspend_disable	= max8997_reg_disable_suspend,
77262306a36Sopenharmony_ci};
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic const struct regulator_ops max8997_fixedstate_ops = {
77562306a36Sopenharmony_ci	.list_voltage		= max8997_list_voltage_charger_cv,
77662306a36Sopenharmony_ci	.get_voltage_sel	= max8997_get_voltage_sel,
77762306a36Sopenharmony_ci	.set_voltage		= max8997_set_voltage_charger_cv,
77862306a36Sopenharmony_ci};
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int max8997_set_current_limit(struct regulator_dev *rdev,
78162306a36Sopenharmony_ci				     int min_uA, int max_uA)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	unsigned dummy;
78462306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF)
78762306a36Sopenharmony_ci		return -EINVAL;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* Reuse max8997_set_voltage_ldobuck to set current_limit. */
79062306a36Sopenharmony_ci	return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy);
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic int max8997_get_current_limit(struct regulator_dev *rdev)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	int sel, rid = rdev_get_id(rdev);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF)
79862306a36Sopenharmony_ci		return -EINVAL;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	sel = max8997_get_voltage_sel(rdev);
80162306a36Sopenharmony_ci	if (sel < 0)
80262306a36Sopenharmony_ci		return sel;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	/* Reuse max8997_list_voltage to get current_limit. */
80562306a36Sopenharmony_ci	return max8997_list_voltage(rdev, sel);
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic const struct regulator_ops max8997_charger_ops = {
80962306a36Sopenharmony_ci	.is_enabled		= max8997_reg_is_enabled,
81062306a36Sopenharmony_ci	.enable			= max8997_reg_enable,
81162306a36Sopenharmony_ci	.disable		= max8997_reg_disable,
81262306a36Sopenharmony_ci	.get_current_limit	= max8997_get_current_limit,
81362306a36Sopenharmony_ci	.set_current_limit	= max8997_set_current_limit,
81462306a36Sopenharmony_ci};
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic const struct regulator_ops max8997_charger_fixedstate_ops = {
81762306a36Sopenharmony_ci	.get_current_limit	= max8997_get_current_limit,
81862306a36Sopenharmony_ci	.set_current_limit	= max8997_set_current_limit,
81962306a36Sopenharmony_ci};
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\
82262306a36Sopenharmony_ci	.name		= #_name,		\
82362306a36Sopenharmony_ci	.id		= MAX8997_##_name,	\
82462306a36Sopenharmony_ci	.ops		= &_ops,		\
82562306a36Sopenharmony_ci	.type		= REGULATOR_VOLTAGE,	\
82662306a36Sopenharmony_ci	.owner		= THIS_MODULE,		\
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\
83062306a36Sopenharmony_ci	.name		= #_name,		\
83162306a36Sopenharmony_ci	.id		= MAX8997_##_name,	\
83262306a36Sopenharmony_ci	.ops		= &_ops,		\
83362306a36Sopenharmony_ci	.type		= REGULATOR_CURRENT,	\
83462306a36Sopenharmony_ci	.owner		= THIS_MODULE,		\
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic struct regulator_desc regulators[] = {
83862306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops),
83962306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops),
84062306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops),
84162306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops),
84262306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops),
84362306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops),
84462306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops),
84562306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops),
84662306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops),
84762306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops),
84862306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops),
84962306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops),
85062306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops),
85162306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops),
85262306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops),
85362306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops),
85462306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops),
85562306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops),
85662306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops),
85762306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops),
85862306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops),
85962306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops),
86062306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops),
86162306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops),
86262306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops),
86362306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops),
86462306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops),
86562306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops),
86662306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops),
86762306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops),
86862306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops),
86962306a36Sopenharmony_ci	MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops),
87062306a36Sopenharmony_ci	MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops),
87162306a36Sopenharmony_ci	MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF,
87262306a36Sopenharmony_ci				  max8997_charger_fixedstate_ops),
87362306a36Sopenharmony_ci};
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci#ifdef CONFIG_OF
87662306a36Sopenharmony_cistatic int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev,
87762306a36Sopenharmony_ci			struct max8997_platform_data *pdata,
87862306a36Sopenharmony_ci			struct device_node *pmic_np)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	int i, gpio;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
88362306a36Sopenharmony_ci		gpio = of_get_named_gpio(pmic_np,
88462306a36Sopenharmony_ci					"max8997,pmic-buck125-dvs-gpios", i);
88562306a36Sopenharmony_ci		if (!gpio_is_valid(gpio)) {
88662306a36Sopenharmony_ci			dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio);
88762306a36Sopenharmony_ci			return -EINVAL;
88862306a36Sopenharmony_ci		}
88962306a36Sopenharmony_ci		pdata->buck125_gpios[i] = gpio;
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci	return 0;
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cistatic int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
89562306a36Sopenharmony_ci					struct max8997_platform_data *pdata)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
89862306a36Sopenharmony_ci	struct device_node *pmic_np, *regulators_np, *reg_np;
89962306a36Sopenharmony_ci	struct max8997_regulator_data *rdata;
90062306a36Sopenharmony_ci	unsigned int i, dvs_voltage_nr = 1, ret;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	pmic_np = iodev->dev->of_node;
90362306a36Sopenharmony_ci	if (!pmic_np) {
90462306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not find pmic sub-node\n");
90562306a36Sopenharmony_ci		return -ENODEV;
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	regulators_np = of_get_child_by_name(pmic_np, "regulators");
90962306a36Sopenharmony_ci	if (!regulators_np) {
91062306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not find regulators sub-node\n");
91162306a36Sopenharmony_ci		return -EINVAL;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* count the number of regulators to be supported in pmic */
91562306a36Sopenharmony_ci	pdata->num_regulators = of_get_child_count(regulators_np);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	rdata = devm_kcalloc(&pdev->dev,
91862306a36Sopenharmony_ci			     pdata->num_regulators, sizeof(*rdata),
91962306a36Sopenharmony_ci			     GFP_KERNEL);
92062306a36Sopenharmony_ci	if (!rdata) {
92162306a36Sopenharmony_ci		of_node_put(regulators_np);
92262306a36Sopenharmony_ci		return -ENOMEM;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	pdata->regulators = rdata;
92662306a36Sopenharmony_ci	for_each_child_of_node(regulators_np, reg_np) {
92762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(regulators); i++)
92862306a36Sopenharmony_ci			if (of_node_name_eq(reg_np, regulators[i].name))
92962306a36Sopenharmony_ci				break;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		if (i == ARRAY_SIZE(regulators)) {
93262306a36Sopenharmony_ci			dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
93362306a36Sopenharmony_ci				 reg_np);
93462306a36Sopenharmony_ci			continue;
93562306a36Sopenharmony_ci		}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		rdata->id = i;
93862306a36Sopenharmony_ci		rdata->initdata = of_get_regulator_init_data(&pdev->dev,
93962306a36Sopenharmony_ci							     reg_np,
94062306a36Sopenharmony_ci							     &regulators[i]);
94162306a36Sopenharmony_ci		rdata->reg_node = reg_np;
94262306a36Sopenharmony_ci		rdata++;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci	of_node_put(regulators_np);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	pdata->buck1_gpiodvs = of_property_read_bool(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs");
94762306a36Sopenharmony_ci	pdata->buck2_gpiodvs = of_property_read_bool(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs");
94862306a36Sopenharmony_ci	pdata->buck5_gpiodvs = of_property_read_bool(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs");
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
95162306a36Sopenharmony_ci						pdata->buck5_gpiodvs) {
95262306a36Sopenharmony_ci		ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np);
95362306a36Sopenharmony_ci		if (ret)
95462306a36Sopenharmony_ci			return -EINVAL;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		if (of_property_read_u32(pmic_np,
95762306a36Sopenharmony_ci				"max8997,pmic-buck125-default-dvs-idx",
95862306a36Sopenharmony_ci				&pdata->buck125_default_idx)) {
95962306a36Sopenharmony_ci			pdata->buck125_default_idx = 0;
96062306a36Sopenharmony_ci		} else {
96162306a36Sopenharmony_ci			if (pdata->buck125_default_idx >= 8) {
96262306a36Sopenharmony_ci				pdata->buck125_default_idx = 0;
96362306a36Sopenharmony_ci				dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n");
96462306a36Sopenharmony_ci			}
96562306a36Sopenharmony_ci		}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		if (of_get_property(pmic_np,
96862306a36Sopenharmony_ci			"max8997,pmic-ignore-gpiodvs-side-effect", NULL))
96962306a36Sopenharmony_ci			pdata->ignore_gpiodvs_side_effect = true;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		dvs_voltage_nr = 8;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (of_property_read_u32_array(pmic_np,
97562306a36Sopenharmony_ci				"max8997,pmic-buck1-dvs-voltage",
97662306a36Sopenharmony_ci				pdata->buck1_voltage, dvs_voltage_nr)) {
97762306a36Sopenharmony_ci		dev_err(&pdev->dev, "buck1 voltages not specified\n");
97862306a36Sopenharmony_ci		return -EINVAL;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (of_property_read_u32_array(pmic_np,
98262306a36Sopenharmony_ci				"max8997,pmic-buck2-dvs-voltage",
98362306a36Sopenharmony_ci				pdata->buck2_voltage, dvs_voltage_nr)) {
98462306a36Sopenharmony_ci		dev_err(&pdev->dev, "buck2 voltages not specified\n");
98562306a36Sopenharmony_ci		return -EINVAL;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (of_property_read_u32_array(pmic_np,
98962306a36Sopenharmony_ci				"max8997,pmic-buck5-dvs-voltage",
99062306a36Sopenharmony_ci				pdata->buck5_voltage, dvs_voltage_nr)) {
99162306a36Sopenharmony_ci		dev_err(&pdev->dev, "buck5 voltages not specified\n");
99262306a36Sopenharmony_ci		return -EINVAL;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci#else
99862306a36Sopenharmony_cistatic int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
99962306a36Sopenharmony_ci					struct max8997_platform_data *pdata)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	return 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci#endif /* CONFIG_OF */
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic int max8997_pmic_probe(struct platform_device *pdev)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
100862306a36Sopenharmony_ci	struct max8997_platform_data *pdata = iodev->pdata;
100962306a36Sopenharmony_ci	struct regulator_config config = { };
101062306a36Sopenharmony_ci	struct regulator_dev *rdev;
101162306a36Sopenharmony_ci	struct max8997_data *max8997;
101262306a36Sopenharmony_ci	struct i2c_client *i2c;
101362306a36Sopenharmony_ci	int i, ret, nr_dvs;
101462306a36Sopenharmony_ci	u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (!pdata) {
101762306a36Sopenharmony_ci		dev_err(&pdev->dev, "No platform init data supplied.\n");
101862306a36Sopenharmony_ci		return -ENODEV;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (iodev->dev->of_node) {
102262306a36Sopenharmony_ci		ret = max8997_pmic_dt_parse_pdata(pdev, pdata);
102362306a36Sopenharmony_ci		if (ret)
102462306a36Sopenharmony_ci			return ret;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data),
102862306a36Sopenharmony_ci			       GFP_KERNEL);
102962306a36Sopenharmony_ci	if (!max8997)
103062306a36Sopenharmony_ci		return -ENOMEM;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	max8997->dev = &pdev->dev;
103362306a36Sopenharmony_ci	max8997->iodev = iodev;
103462306a36Sopenharmony_ci	max8997->num_regulators = pdata->num_regulators;
103562306a36Sopenharmony_ci	platform_set_drvdata(pdev, max8997);
103662306a36Sopenharmony_ci	i2c = max8997->iodev->i2c;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	max8997->buck125_gpioindex = pdata->buck125_default_idx;
103962306a36Sopenharmony_ci	max8997->buck1_gpiodvs = pdata->buck1_gpiodvs;
104062306a36Sopenharmony_ci	max8997->buck2_gpiodvs = pdata->buck2_gpiodvs;
104162306a36Sopenharmony_ci	max8997->buck5_gpiodvs = pdata->buck5_gpiodvs;
104262306a36Sopenharmony_ci	memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3);
104362306a36Sopenharmony_ci	max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
104662306a36Sopenharmony_ci			pdata->buck5_gpiodvs) ? 8 : 1;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	for (i = 0; i < nr_dvs; i++) {
104962306a36Sopenharmony_ci		max8997->buck1_vol[i] = ret =
105062306a36Sopenharmony_ci			max8997_get_voltage_proper_val(
105162306a36Sopenharmony_ci					&buck1245_voltage_map_desc,
105262306a36Sopenharmony_ci					pdata->buck1_voltage[i],
105362306a36Sopenharmony_ci					pdata->buck1_voltage[i] +
105462306a36Sopenharmony_ci					buck1245_voltage_map_desc.step);
105562306a36Sopenharmony_ci		if (ret < 0)
105662306a36Sopenharmony_ci			return ret;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		max8997->buck2_vol[i] = ret =
105962306a36Sopenharmony_ci			max8997_get_voltage_proper_val(
106062306a36Sopenharmony_ci					&buck1245_voltage_map_desc,
106162306a36Sopenharmony_ci					pdata->buck2_voltage[i],
106262306a36Sopenharmony_ci					pdata->buck2_voltage[i] +
106362306a36Sopenharmony_ci					buck1245_voltage_map_desc.step);
106462306a36Sopenharmony_ci		if (ret < 0)
106562306a36Sopenharmony_ci			return ret;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		max8997->buck5_vol[i] = ret =
106862306a36Sopenharmony_ci			max8997_get_voltage_proper_val(
106962306a36Sopenharmony_ci					&buck1245_voltage_map_desc,
107062306a36Sopenharmony_ci					pdata->buck5_voltage[i],
107162306a36Sopenharmony_ci					pdata->buck5_voltage[i] +
107262306a36Sopenharmony_ci					buck1245_voltage_map_desc.step);
107362306a36Sopenharmony_ci		if (ret < 0)
107462306a36Sopenharmony_ci			return ret;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		if (max_buck1 < max8997->buck1_vol[i])
107762306a36Sopenharmony_ci			max_buck1 = max8997->buck1_vol[i];
107862306a36Sopenharmony_ci		if (max_buck2 < max8997->buck2_vol[i])
107962306a36Sopenharmony_ci			max_buck2 = max8997->buck2_vol[i];
108062306a36Sopenharmony_ci		if (max_buck5 < max8997->buck5_vol[i])
108162306a36Sopenharmony_ci			max_buck5 = max8997->buck5_vol[i];
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	/* For the safety, set max voltage before setting up */
108562306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
108662306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
108762306a36Sopenharmony_ci				max_buck1, 0x3f);
108862306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
108962306a36Sopenharmony_ci				max_buck2, 0x3f);
109062306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
109162306a36Sopenharmony_ci				max_buck5, 0x3f);
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* Initialize all the DVS related BUCK registers */
109562306a36Sopenharmony_ci	for (i = 0; i < nr_dvs; i++) {
109662306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
109762306a36Sopenharmony_ci				max8997->buck1_vol[i],
109862306a36Sopenharmony_ci				0x3f);
109962306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
110062306a36Sopenharmony_ci				max8997->buck2_vol[i],
110162306a36Sopenharmony_ci				0x3f);
110262306a36Sopenharmony_ci		max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
110362306a36Sopenharmony_ci				max8997->buck5_vol[i],
110462306a36Sopenharmony_ci				0x3f);
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/*
110862306a36Sopenharmony_ci	 * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them.
110962306a36Sopenharmony_ci	 * If at least one of them cares, set gpios.
111062306a36Sopenharmony_ci	 */
111162306a36Sopenharmony_ci	if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
111262306a36Sopenharmony_ci			pdata->buck5_gpiodvs) {
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		if (!gpio_is_valid(pdata->buck125_gpios[0]) ||
111562306a36Sopenharmony_ci				!gpio_is_valid(pdata->buck125_gpios[1]) ||
111662306a36Sopenharmony_ci				!gpio_is_valid(pdata->buck125_gpios[2])) {
111762306a36Sopenharmony_ci			dev_err(&pdev->dev, "GPIO NOT VALID\n");
111862306a36Sopenharmony_ci			return -EINVAL;
111962306a36Sopenharmony_ci		}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0],
112262306a36Sopenharmony_ci					"MAX8997 SET1");
112362306a36Sopenharmony_ci		if (ret)
112462306a36Sopenharmony_ci			return ret;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1],
112762306a36Sopenharmony_ci					"MAX8997 SET2");
112862306a36Sopenharmony_ci		if (ret)
112962306a36Sopenharmony_ci			return ret;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2],
113262306a36Sopenharmony_ci				"MAX8997 SET3");
113362306a36Sopenharmony_ci		if (ret)
113462306a36Sopenharmony_ci			return ret;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		gpio_direction_output(pdata->buck125_gpios[0],
113762306a36Sopenharmony_ci				(max8997->buck125_gpioindex >> 2)
113862306a36Sopenharmony_ci				& 0x1); /* SET1 */
113962306a36Sopenharmony_ci		gpio_direction_output(pdata->buck125_gpios[1],
114062306a36Sopenharmony_ci				(max8997->buck125_gpioindex >> 1)
114162306a36Sopenharmony_ci				& 0x1); /* SET2 */
114262306a36Sopenharmony_ci		gpio_direction_output(pdata->buck125_gpios[2],
114362306a36Sopenharmony_ci				(max8997->buck125_gpioindex >> 0)
114462306a36Sopenharmony_ci				& 0x1); /* SET3 */
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* DVS-GPIO disabled */
114862306a36Sopenharmony_ci	max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ?
114962306a36Sopenharmony_ci			(1 << 1) : (0 << 1), 1 << 1);
115062306a36Sopenharmony_ci	max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ?
115162306a36Sopenharmony_ci			(1 << 1) : (0 << 1), 1 << 1);
115262306a36Sopenharmony_ci	max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ?
115362306a36Sopenharmony_ci			(1 << 1) : (0 << 1), 1 << 1);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* Misc Settings */
115662306a36Sopenharmony_ci	max8997->ramp_delay = 10; /* set 10mV/us, which is the default */
115762306a36Sopenharmony_ci	max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	for (i = 0; i < pdata->num_regulators; i++) {
116062306a36Sopenharmony_ci		const struct voltage_map_desc *desc;
116162306a36Sopenharmony_ci		int id = pdata->regulators[i].id;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		desc = reg_voltage_map[id];
116462306a36Sopenharmony_ci		if (desc) {
116562306a36Sopenharmony_ci			regulators[id].n_voltages =
116662306a36Sopenharmony_ci				(desc->max - desc->min) / desc->step + 1;
116762306a36Sopenharmony_ci		} else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) {
116862306a36Sopenharmony_ci			regulators[id].volt_table = safeoutvolt;
116962306a36Sopenharmony_ci			regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt);
117062306a36Sopenharmony_ci		} else if (id == MAX8997_CHARGER_CV) {
117162306a36Sopenharmony_ci			regulators[id].n_voltages = 16;
117262306a36Sopenharmony_ci		}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		config.dev = max8997->dev;
117562306a36Sopenharmony_ci		config.init_data = pdata->regulators[i].initdata;
117662306a36Sopenharmony_ci		config.driver_data = max8997;
117762306a36Sopenharmony_ci		config.of_node = pdata->regulators[i].reg_node;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		rdev = devm_regulator_register(&pdev->dev, &regulators[id],
118062306a36Sopenharmony_ci					       &config);
118162306a36Sopenharmony_ci		if (IS_ERR(rdev)) {
118262306a36Sopenharmony_ci			dev_err(max8997->dev, "regulator init failed for %d\n",
118362306a36Sopenharmony_ci					id);
118462306a36Sopenharmony_ci			return PTR_ERR(rdev);
118562306a36Sopenharmony_ci		}
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return 0;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic const struct platform_device_id max8997_pmic_id[] = {
119262306a36Sopenharmony_ci	{ "max8997-pmic", 0},
119362306a36Sopenharmony_ci	{ },
119462306a36Sopenharmony_ci};
119562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max8997_pmic_id);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_cistatic struct platform_driver max8997_pmic_driver = {
119862306a36Sopenharmony_ci	.driver = {
119962306a36Sopenharmony_ci		.name = "max8997-pmic",
120062306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
120162306a36Sopenharmony_ci	},
120262306a36Sopenharmony_ci	.probe = max8997_pmic_probe,
120362306a36Sopenharmony_ci	.id_table = max8997_pmic_id,
120462306a36Sopenharmony_ci};
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic int __init max8997_pmic_init(void)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	return platform_driver_register(&max8997_pmic_driver);
120962306a36Sopenharmony_ci}
121062306a36Sopenharmony_cisubsys_initcall(max8997_pmic_init);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic void __exit max8997_pmic_cleanup(void)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	platform_driver_unregister(&max8997_pmic_driver);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_cimodule_exit(max8997_pmic_cleanup);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver");
121962306a36Sopenharmony_ciMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
122062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1221