162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Regulator driver for DA9055 PMIC
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright(c) 2012 Dialog Semiconductor Ltd.
662306a36Sopenharmony_ci//
762306a36Sopenharmony_ci// Author: David Dajun Chen <dchen@diasemi.com>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/gpio.h>
1362306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/regulator/driver.h>
1662306a36Sopenharmony_ci#include <linux/regulator/machine.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/mfd/da9055/core.h>
2162306a36Sopenharmony_ci#include <linux/mfd/da9055/reg.h>
2262306a36Sopenharmony_ci#include <linux/mfd/da9055/pdata.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define DA9055_MIN_UA		0
2562306a36Sopenharmony_ci#define DA9055_MAX_UA		3
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DA9055_LDO_MODE_SYNC	0
2862306a36Sopenharmony_ci#define DA9055_LDO_MODE_SLEEP	1
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define DA9055_BUCK_MODE_SLEEP	1
3162306a36Sopenharmony_ci#define DA9055_BUCK_MODE_SYNC	2
3262306a36Sopenharmony_ci#define DA9055_BUCK_MODE_AUTO	3
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* DA9055 REGULATOR IDs */
3562306a36Sopenharmony_ci#define DA9055_ID_BUCK1	0
3662306a36Sopenharmony_ci#define DA9055_ID_BUCK2	1
3762306a36Sopenharmony_ci#define DA9055_ID_LDO1		2
3862306a36Sopenharmony_ci#define DA9055_ID_LDO2		3
3962306a36Sopenharmony_ci#define DA9055_ID_LDO3		4
4062306a36Sopenharmony_ci#define DA9055_ID_LDO4		5
4162306a36Sopenharmony_ci#define DA9055_ID_LDO5		6
4262306a36Sopenharmony_ci#define DA9055_ID_LDO6		7
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* DA9055 BUCK current limit */
4562306a36Sopenharmony_cistatic const unsigned int da9055_current_limits[] = {
4662306a36Sopenharmony_ci	500000, 600000, 700000, 800000
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct da9055_conf_reg {
5062306a36Sopenharmony_ci	int reg;
5162306a36Sopenharmony_ci	int sel_mask;
5262306a36Sopenharmony_ci	int en_mask;
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct da9055_volt_reg {
5662306a36Sopenharmony_ci	int reg_a;
5762306a36Sopenharmony_ci	int reg_b;
5862306a36Sopenharmony_ci	int sl_shift;
5962306a36Sopenharmony_ci	int v_mask;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct da9055_mode_reg {
6362306a36Sopenharmony_ci	int reg;
6462306a36Sopenharmony_ci	int mask;
6562306a36Sopenharmony_ci	int shift;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct da9055_regulator_info {
6962306a36Sopenharmony_ci	struct regulator_desc reg_desc;
7062306a36Sopenharmony_ci	struct da9055_conf_reg conf;
7162306a36Sopenharmony_ci	struct da9055_volt_reg volt;
7262306a36Sopenharmony_ci	struct da9055_mode_reg mode;
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistruct da9055_regulator {
7662306a36Sopenharmony_ci	struct da9055 *da9055;
7762306a36Sopenharmony_ci	struct da9055_regulator_info *info;
7862306a36Sopenharmony_ci	struct regulator_dev *rdev;
7962306a36Sopenharmony_ci	enum gpio_select reg_rselect;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic unsigned int da9055_buck_get_mode(struct regulator_dev *rdev)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
8562306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
8662306a36Sopenharmony_ci	int ret, mode = 0;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = da9055_reg_read(regulator->da9055, info->mode.reg);
8962306a36Sopenharmony_ci	if (ret < 0)
9062306a36Sopenharmony_ci		return ret;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	switch ((ret & info->mode.mask) >> info->mode.shift) {
9362306a36Sopenharmony_ci	case DA9055_BUCK_MODE_SYNC:
9462306a36Sopenharmony_ci		mode = REGULATOR_MODE_FAST;
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci	case DA9055_BUCK_MODE_AUTO:
9762306a36Sopenharmony_ci		mode = REGULATOR_MODE_NORMAL;
9862306a36Sopenharmony_ci		break;
9962306a36Sopenharmony_ci	case DA9055_BUCK_MODE_SLEEP:
10062306a36Sopenharmony_ci		mode = REGULATOR_MODE_STANDBY;
10162306a36Sopenharmony_ci		break;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return mode;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int da9055_buck_set_mode(struct regulator_dev *rdev,
10862306a36Sopenharmony_ci					unsigned int mode)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
11162306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
11262306a36Sopenharmony_ci	int val = 0;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	switch (mode) {
11562306a36Sopenharmony_ci	case REGULATOR_MODE_FAST:
11662306a36Sopenharmony_ci		val = DA9055_BUCK_MODE_SYNC << info->mode.shift;
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
11962306a36Sopenharmony_ci		val = DA9055_BUCK_MODE_AUTO << info->mode.shift;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case REGULATOR_MODE_STANDBY:
12262306a36Sopenharmony_ci		val = DA9055_BUCK_MODE_SLEEP << info->mode.shift;
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return da9055_reg_update(regulator->da9055, info->mode.reg,
12762306a36Sopenharmony_ci				 info->mode.mask, val);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic unsigned int da9055_ldo_get_mode(struct regulator_dev *rdev)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
13362306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
13462306a36Sopenharmony_ci	int ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = da9055_reg_read(regulator->da9055, info->volt.reg_b);
13762306a36Sopenharmony_ci	if (ret < 0)
13862306a36Sopenharmony_ci		return ret;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (ret >> info->volt.sl_shift)
14162306a36Sopenharmony_ci		return REGULATOR_MODE_STANDBY;
14262306a36Sopenharmony_ci	else
14362306a36Sopenharmony_ci		return REGULATOR_MODE_NORMAL;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
14962306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
15062306a36Sopenharmony_ci	struct da9055_volt_reg volt = info->volt;
15162306a36Sopenharmony_ci	int val = 0;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	switch (mode) {
15462306a36Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
15562306a36Sopenharmony_ci	case REGULATOR_MODE_FAST:
15662306a36Sopenharmony_ci		val = DA9055_LDO_MODE_SYNC;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case REGULATOR_MODE_STANDBY:
15962306a36Sopenharmony_ci		val = DA9055_LDO_MODE_SLEEP;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return da9055_reg_update(regulator->da9055, volt.reg_b,
16462306a36Sopenharmony_ci				 1 << volt.sl_shift,
16562306a36Sopenharmony_ci				 val << volt.sl_shift);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int da9055_regulator_get_voltage_sel(struct regulator_dev *rdev)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
17162306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
17262306a36Sopenharmony_ci	struct da9055_volt_reg volt = info->volt;
17362306a36Sopenharmony_ci	int ret, sel;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/*
17662306a36Sopenharmony_ci	 * There are two voltage register set A & B for voltage ramping but
17762306a36Sopenharmony_ci	 * either one of then can be active therefore we first determine
17862306a36Sopenharmony_ci	 * the active register set.
17962306a36Sopenharmony_ci	 */
18062306a36Sopenharmony_ci	ret = da9055_reg_read(regulator->da9055, info->conf.reg);
18162306a36Sopenharmony_ci	if (ret < 0)
18262306a36Sopenharmony_ci		return ret;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret &= info->conf.sel_mask;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* Get the voltage for the active register set A/B */
18762306a36Sopenharmony_ci	if (ret == DA9055_REGUALTOR_SET_A)
18862306a36Sopenharmony_ci		ret = da9055_reg_read(regulator->da9055, volt.reg_a);
18962306a36Sopenharmony_ci	else
19062306a36Sopenharmony_ci		ret = da9055_reg_read(regulator->da9055, volt.reg_b);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (ret < 0)
19362306a36Sopenharmony_ci		return ret;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	sel = (ret & volt.v_mask);
19662306a36Sopenharmony_ci	return sel;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int da9055_regulator_set_voltage_sel(struct regulator_dev *rdev,
20062306a36Sopenharmony_ci					    unsigned int selector)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
20362306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
20462306a36Sopenharmony_ci	int ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/*
20762306a36Sopenharmony_ci	 * Regulator register set A/B is not selected through GPIO therefore
20862306a36Sopenharmony_ci	 * we use default register set A for voltage ramping.
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci	if (regulator->reg_rselect == NO_GPIO) {
21162306a36Sopenharmony_ci		/* Select register set A */
21262306a36Sopenharmony_ci		ret = da9055_reg_update(regulator->da9055, info->conf.reg,
21362306a36Sopenharmony_ci					info->conf.sel_mask, DA9055_SEL_REG_A);
21462306a36Sopenharmony_ci		if (ret < 0)
21562306a36Sopenharmony_ci			return ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* Set the voltage */
21862306a36Sopenharmony_ci		return da9055_reg_update(regulator->da9055, info->volt.reg_a,
21962306a36Sopenharmony_ci					 info->volt.v_mask, selector);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/*
22362306a36Sopenharmony_ci	 * Here regulator register set A/B is selected through GPIO.
22462306a36Sopenharmony_ci	 * Therefore we first determine the selected register set A/B and
22562306a36Sopenharmony_ci	 * then set the desired voltage for that register set A/B.
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci	ret = da9055_reg_read(regulator->da9055, info->conf.reg);
22862306a36Sopenharmony_ci	if (ret < 0)
22962306a36Sopenharmony_ci		return ret;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ret &= info->conf.sel_mask;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Set the voltage */
23462306a36Sopenharmony_ci	if (ret == DA9055_REGUALTOR_SET_A)
23562306a36Sopenharmony_ci		return da9055_reg_update(regulator->da9055, info->volt.reg_a,
23662306a36Sopenharmony_ci					 info->volt.v_mask, selector);
23762306a36Sopenharmony_ci	else
23862306a36Sopenharmony_ci		return da9055_reg_update(regulator->da9055, info->volt.reg_b,
23962306a36Sopenharmony_ci					 info->volt.v_mask, selector);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int da9055_regulator_set_suspend_voltage(struct regulator_dev *rdev,
24362306a36Sopenharmony_ci						int uV)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
24662306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
24762306a36Sopenharmony_ci	int ret;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Select register set B for suspend voltage ramping. */
25062306a36Sopenharmony_ci	if (regulator->reg_rselect == NO_GPIO) {
25162306a36Sopenharmony_ci		ret = da9055_reg_update(regulator->da9055, info->conf.reg,
25262306a36Sopenharmony_ci					info->conf.sel_mask, DA9055_SEL_REG_B);
25362306a36Sopenharmony_ci		if (ret < 0)
25462306a36Sopenharmony_ci			return ret;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	ret = regulator_map_voltage_linear(rdev, uV, uV);
25862306a36Sopenharmony_ci	if (ret < 0)
25962306a36Sopenharmony_ci		return ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return da9055_reg_update(regulator->da9055, info->volt.reg_b,
26262306a36Sopenharmony_ci				 info->volt.v_mask, ret);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int da9055_suspend_enable(struct regulator_dev *rdev)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
26862306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* Select register set B for voltage ramping. */
27162306a36Sopenharmony_ci	if (regulator->reg_rselect == NO_GPIO)
27262306a36Sopenharmony_ci		return da9055_reg_update(regulator->da9055, info->conf.reg,
27362306a36Sopenharmony_ci					info->conf.sel_mask, DA9055_SEL_REG_B);
27462306a36Sopenharmony_ci	else
27562306a36Sopenharmony_ci		return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int da9055_suspend_disable(struct regulator_dev *rdev)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct da9055_regulator *regulator = rdev_get_drvdata(rdev);
28162306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Diselect register set B. */
28462306a36Sopenharmony_ci	if (regulator->reg_rselect == NO_GPIO)
28562306a36Sopenharmony_ci		return da9055_reg_update(regulator->da9055, info->conf.reg,
28662306a36Sopenharmony_ci					info->conf.sel_mask, DA9055_SEL_REG_A);
28762306a36Sopenharmony_ci	else
28862306a36Sopenharmony_ci		return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic const struct regulator_ops da9055_buck_ops = {
29262306a36Sopenharmony_ci	.get_mode = da9055_buck_get_mode,
29362306a36Sopenharmony_ci	.set_mode = da9055_buck_set_mode,
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	.get_current_limit = regulator_get_current_limit_regmap,
29662306a36Sopenharmony_ci	.set_current_limit = regulator_set_current_limit_regmap,
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	.get_voltage_sel = da9055_regulator_get_voltage_sel,
29962306a36Sopenharmony_ci	.set_voltage_sel = da9055_regulator_set_voltage_sel,
30062306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
30162306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
30262306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
30362306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
30462306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	.set_suspend_voltage = da9055_regulator_set_suspend_voltage,
30762306a36Sopenharmony_ci	.set_suspend_enable = da9055_suspend_enable,
30862306a36Sopenharmony_ci	.set_suspend_disable = da9055_suspend_disable,
30962306a36Sopenharmony_ci	.set_suspend_mode = da9055_buck_set_mode,
31062306a36Sopenharmony_ci};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic const struct regulator_ops da9055_ldo_ops = {
31362306a36Sopenharmony_ci	.get_mode = da9055_ldo_get_mode,
31462306a36Sopenharmony_ci	.set_mode = da9055_ldo_set_mode,
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	.get_voltage_sel = da9055_regulator_get_voltage_sel,
31762306a36Sopenharmony_ci	.set_voltage_sel = da9055_regulator_set_voltage_sel,
31862306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
31962306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
32062306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
32162306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
32262306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	.set_suspend_voltage = da9055_regulator_set_suspend_voltage,
32562306a36Sopenharmony_ci	.set_suspend_enable = da9055_suspend_enable,
32662306a36Sopenharmony_ci	.set_suspend_disable = da9055_suspend_disable,
32762306a36Sopenharmony_ci	.set_suspend_mode = da9055_ldo_set_mode,
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci#define DA9055_LDO(_id, step, min, max, vbits, voffset) \
33262306a36Sopenharmony_ci{\
33362306a36Sopenharmony_ci	.reg_desc = {\
33462306a36Sopenharmony_ci		.name = #_id,\
33562306a36Sopenharmony_ci		.of_match = of_match_ptr(#_id),\
33662306a36Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),\
33762306a36Sopenharmony_ci		.ops = &da9055_ldo_ops,\
33862306a36Sopenharmony_ci		.type = REGULATOR_VOLTAGE,\
33962306a36Sopenharmony_ci		.id = DA9055_ID_##_id,\
34062306a36Sopenharmony_ci		.n_voltages = (max - min) / step + 1 + (voffset), \
34162306a36Sopenharmony_ci		.enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \
34262306a36Sopenharmony_ci		.enable_mask = 1, \
34362306a36Sopenharmony_ci		.min_uV = (min) * 1000,\
34462306a36Sopenharmony_ci		.uV_step = (step) * 1000,\
34562306a36Sopenharmony_ci		.linear_min_sel = (voffset),\
34662306a36Sopenharmony_ci		.owner = THIS_MODULE,\
34762306a36Sopenharmony_ci	},\
34862306a36Sopenharmony_ci	.conf = {\
34962306a36Sopenharmony_ci		.reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \
35062306a36Sopenharmony_ci		.sel_mask = (1 << 4),\
35162306a36Sopenharmony_ci		.en_mask = 1,\
35262306a36Sopenharmony_ci	},\
35362306a36Sopenharmony_ci	.volt = {\
35462306a36Sopenharmony_ci		.reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \
35562306a36Sopenharmony_ci		.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
35662306a36Sopenharmony_ci		.sl_shift = 7,\
35762306a36Sopenharmony_ci		.v_mask = (1 << (vbits)) - 1,\
35862306a36Sopenharmony_ci	},\
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci#define DA9055_BUCK(_id, step, min, max, vbits, voffset, mbits, sbits) \
36262306a36Sopenharmony_ci{\
36362306a36Sopenharmony_ci	.reg_desc = {\
36462306a36Sopenharmony_ci		.name = #_id,\
36562306a36Sopenharmony_ci		.of_match = of_match_ptr(#_id),\
36662306a36Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),\
36762306a36Sopenharmony_ci		.ops = &da9055_buck_ops,\
36862306a36Sopenharmony_ci		.type = REGULATOR_VOLTAGE,\
36962306a36Sopenharmony_ci		.id = DA9055_ID_##_id,\
37062306a36Sopenharmony_ci		.n_voltages = (max - min) / step + 1 + (voffset), \
37162306a36Sopenharmony_ci		.enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \
37262306a36Sopenharmony_ci		.enable_mask = 1,\
37362306a36Sopenharmony_ci		.min_uV = (min) * 1000,\
37462306a36Sopenharmony_ci		.uV_step = (step) * 1000,\
37562306a36Sopenharmony_ci		.linear_min_sel = (voffset),\
37662306a36Sopenharmony_ci		.owner = THIS_MODULE,\
37762306a36Sopenharmony_ci		.curr_table = da9055_current_limits,\
37862306a36Sopenharmony_ci		.n_current_limits = ARRAY_SIZE(da9055_current_limits),\
37962306a36Sopenharmony_ci		.csel_reg = DA9055_REG_BUCK_LIM,\
38062306a36Sopenharmony_ci		.csel_mask = (mbits),\
38162306a36Sopenharmony_ci	},\
38262306a36Sopenharmony_ci	.conf = {\
38362306a36Sopenharmony_ci		.reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \
38462306a36Sopenharmony_ci		.sel_mask = (1 << 4),\
38562306a36Sopenharmony_ci		.en_mask = 1,\
38662306a36Sopenharmony_ci	},\
38762306a36Sopenharmony_ci	.volt = {\
38862306a36Sopenharmony_ci		.reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \
38962306a36Sopenharmony_ci		.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
39062306a36Sopenharmony_ci		.sl_shift = 7,\
39162306a36Sopenharmony_ci		.v_mask = (1 << (vbits)) - 1,\
39262306a36Sopenharmony_ci	},\
39362306a36Sopenharmony_ci	.mode = {\
39462306a36Sopenharmony_ci		.reg = DA9055_REG_BCORE_MODE,\
39562306a36Sopenharmony_ci		.mask = (mbits),\
39662306a36Sopenharmony_ci		.shift = (sbits),\
39762306a36Sopenharmony_ci	},\
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic struct da9055_regulator_info da9055_regulator_info[] = {
40162306a36Sopenharmony_ci	DA9055_BUCK(BUCK1, 25, 725, 2075, 6, 9, 0xc, 2),
40262306a36Sopenharmony_ci	DA9055_BUCK(BUCK2, 25, 925, 2500, 6, 0, 3, 0),
40362306a36Sopenharmony_ci	DA9055_LDO(LDO1, 50, 900, 3300, 6, 2),
40462306a36Sopenharmony_ci	DA9055_LDO(LDO2, 50, 900, 3300, 6, 3),
40562306a36Sopenharmony_ci	DA9055_LDO(LDO3, 50, 900, 3300, 6, 2),
40662306a36Sopenharmony_ci	DA9055_LDO(LDO4, 50, 900, 3300, 6, 2),
40762306a36Sopenharmony_ci	DA9055_LDO(LDO5, 50, 900, 2750, 6, 2),
40862306a36Sopenharmony_ci	DA9055_LDO(LDO6, 20, 900, 3300, 7, 0),
40962306a36Sopenharmony_ci};
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/*
41262306a36Sopenharmony_ci * Configures regulator to be controlled either through GPIO 1 or 2.
41362306a36Sopenharmony_ci * GPIO can control regulator state and/or select the regulator register
41462306a36Sopenharmony_ci * set A/B for voltage ramping.
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic int da9055_gpio_init(struct da9055_regulator *regulator,
41762306a36Sopenharmony_ci			    struct regulator_config *config,
41862306a36Sopenharmony_ci			    struct da9055_pdata *pdata, int id)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct da9055_regulator_info *info = regulator->info;
42162306a36Sopenharmony_ci	int ret = 0;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (!pdata)
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (pdata->gpio_ren && pdata->gpio_ren[id]) {
42762306a36Sopenharmony_ci		char name[18];
42862306a36Sopenharmony_ci		int gpio_mux = pdata->gpio_ren[id];
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		config->ena_gpiod = pdata->ena_gpiods[id];
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		/*
43362306a36Sopenharmony_ci		 * GPI pin is muxed with regulator to control the
43462306a36Sopenharmony_ci		 * regulator state.
43562306a36Sopenharmony_ci		 */
43662306a36Sopenharmony_ci		sprintf(name, "DA9055 GPI %d", gpio_mux);
43762306a36Sopenharmony_ci		ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN,
43862306a36Sopenharmony_ci					    name);
43962306a36Sopenharmony_ci		if (ret < 0)
44062306a36Sopenharmony_ci			goto err;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		/*
44362306a36Sopenharmony_ci		 * Let the regulator know that its state is controlled
44462306a36Sopenharmony_ci		 * through GPI.
44562306a36Sopenharmony_ci		 */
44662306a36Sopenharmony_ci		ret = da9055_reg_update(regulator->da9055, info->conf.reg,
44762306a36Sopenharmony_ci					DA9055_E_GPI_MASK,
44862306a36Sopenharmony_ci					pdata->reg_ren[id]
44962306a36Sopenharmony_ci					<< DA9055_E_GPI_SHIFT);
45062306a36Sopenharmony_ci		if (ret < 0)
45162306a36Sopenharmony_ci			goto err;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (pdata->gpio_rsel && pdata->gpio_rsel[id]) {
45562306a36Sopenharmony_ci		char name[18];
45662306a36Sopenharmony_ci		int gpio_mux = pdata->gpio_rsel[id];
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		regulator->reg_rselect = pdata->reg_rsel[id];
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		/*
46162306a36Sopenharmony_ci		 * GPI pin is muxed with regulator to select the
46262306a36Sopenharmony_ci		 * regulator register set A/B for voltage ramping.
46362306a36Sopenharmony_ci		 */
46462306a36Sopenharmony_ci		sprintf(name, "DA9055 GPI %d", gpio_mux);
46562306a36Sopenharmony_ci		ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN,
46662306a36Sopenharmony_ci					    name);
46762306a36Sopenharmony_ci		if (ret < 0)
46862306a36Sopenharmony_ci			goto err;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		/*
47162306a36Sopenharmony_ci		 * Let the regulator know that its register set A/B
47262306a36Sopenharmony_ci		 * will be selected through GPI for voltage ramping.
47362306a36Sopenharmony_ci		 */
47462306a36Sopenharmony_ci		ret = da9055_reg_update(regulator->da9055, info->conf.reg,
47562306a36Sopenharmony_ci					DA9055_V_GPI_MASK,
47662306a36Sopenharmony_ci					pdata->reg_rsel[id]
47762306a36Sopenharmony_ci					<< DA9055_V_GPI_SHIFT);
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cierr:
48162306a36Sopenharmony_ci	return ret;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic irqreturn_t da9055_ldo5_6_oc_irq(int irq, void *data)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct da9055_regulator *regulator = data;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	regulator_notifier_call_chain(regulator->rdev,
48962306a36Sopenharmony_ci				      REGULATOR_EVENT_OVER_CURRENT, NULL);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return IRQ_HANDLED;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic inline struct da9055_regulator_info *find_regulator_info(int id)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct da9055_regulator_info *info;
49762306a36Sopenharmony_ci	int i;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(da9055_regulator_info); i++) {
50062306a36Sopenharmony_ci		info = &da9055_regulator_info[i];
50162306a36Sopenharmony_ci		if (info->reg_desc.id == id)
50262306a36Sopenharmony_ci			return info;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return NULL;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int da9055_regulator_probe(struct platform_device *pdev)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct regulator_config config = { };
51162306a36Sopenharmony_ci	struct da9055_regulator *regulator;
51262306a36Sopenharmony_ci	struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
51362306a36Sopenharmony_ci	struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
51462306a36Sopenharmony_ci	int ret, irq;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator),
51762306a36Sopenharmony_ci				 GFP_KERNEL);
51862306a36Sopenharmony_ci	if (!regulator)
51962306a36Sopenharmony_ci		return -ENOMEM;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	regulator->info = find_regulator_info(pdev->id);
52262306a36Sopenharmony_ci	if (regulator->info == NULL) {
52362306a36Sopenharmony_ci		dev_err(&pdev->dev, "invalid regulator ID specified\n");
52462306a36Sopenharmony_ci		return -EINVAL;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	regulator->da9055 = da9055;
52862306a36Sopenharmony_ci	config.dev = da9055->dev;
52962306a36Sopenharmony_ci	config.driver_data = regulator;
53062306a36Sopenharmony_ci	config.regmap = da9055->regmap;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (pdata)
53362306a36Sopenharmony_ci		config.init_data = pdata->regulators[pdev->id];
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	ret = da9055_gpio_init(regulator, &config, pdata, pdev->id);
53662306a36Sopenharmony_ci	if (ret < 0)
53762306a36Sopenharmony_ci		return ret;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	regulator->rdev = devm_regulator_register(&pdev->dev,
54062306a36Sopenharmony_ci						  &regulator->info->reg_desc,
54162306a36Sopenharmony_ci						  &config);
54262306a36Sopenharmony_ci	if (IS_ERR(regulator->rdev)) {
54362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register regulator %s\n",
54462306a36Sopenharmony_ci			regulator->info->reg_desc.name);
54562306a36Sopenharmony_ci		return PTR_ERR(regulator->rdev);
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/* Only LDO 5 and 6 has got the over current interrupt */
54962306a36Sopenharmony_ci	if (pdev->id == DA9055_ID_LDO5 || pdev->id ==  DA9055_ID_LDO6) {
55062306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "REGULATOR");
55162306a36Sopenharmony_ci		if (irq < 0)
55262306a36Sopenharmony_ci			return irq;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
55562306a36Sopenharmony_ci						da9055_ldo5_6_oc_irq,
55662306a36Sopenharmony_ci						IRQF_TRIGGER_HIGH |
55762306a36Sopenharmony_ci						IRQF_ONESHOT |
55862306a36Sopenharmony_ci						IRQF_PROBE_SHARED,
55962306a36Sopenharmony_ci						pdev->name, regulator);
56062306a36Sopenharmony_ci		if (ret != 0) {
56162306a36Sopenharmony_ci			if (ret != -EBUSY) {
56262306a36Sopenharmony_ci				dev_err(&pdev->dev,
56362306a36Sopenharmony_ci				"Failed to request Regulator IRQ %d: %d\n",
56462306a36Sopenharmony_ci				irq, ret);
56562306a36Sopenharmony_ci				return ret;
56662306a36Sopenharmony_ci			}
56762306a36Sopenharmony_ci		}
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	platform_set_drvdata(pdev, regulator);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic struct platform_driver da9055_regulator_driver = {
57662306a36Sopenharmony_ci	.probe = da9055_regulator_probe,
57762306a36Sopenharmony_ci	.driver = {
57862306a36Sopenharmony_ci		.name = "da9055-regulator",
57962306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
58062306a36Sopenharmony_ci	},
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic int __init da9055_regulator_init(void)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	return platform_driver_register(&da9055_regulator_driver);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_cisubsys_initcall(da9055_regulator_init);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic void __exit da9055_regulator_exit(void)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	platform_driver_unregister(&da9055_regulator_driver);
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_cimodule_exit(da9055_regulator_exit);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ciMODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
59662306a36Sopenharmony_ciMODULE_DESCRIPTION("Power Regulator driver for Dialog DA9055 PMIC");
59762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
59862306a36Sopenharmony_ciMODULE_ALIAS("platform:da9055-regulator");
599