162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (C) 2020 ROHM Semiconductors
362306a36Sopenharmony_ci// ROHM BD9576MUF/BD9573MUF regulator driver
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/err.h>
662306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
762306a36Sopenharmony_ci#include <linux/interrupt.h>
862306a36Sopenharmony_ci#include <linux/jiffies.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/mfd/rohm-bd957x.h>
1162306a36Sopenharmony_ci#include <linux/mfd/rohm-generic.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/property.h>
1662306a36Sopenharmony_ci#include <linux/regulator/driver.h>
1762306a36Sopenharmony_ci#include <linux/regulator/machine.h>
1862306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/spinlock.h>
2162306a36Sopenharmony_ci#include <linux/workqueue.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define BD957X_VOUTS1_VOLT	3300000
2462306a36Sopenharmony_ci#define BD957X_VOUTS4_BASE_VOLT	1030000
2562306a36Sopenharmony_ci#define BD957X_VOUTS34_NUM_VOLT	32
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define BD9576_THERM_IRQ_MASK_TW	BIT(5)
2862306a36Sopenharmony_ci#define BD9576_xVD_IRQ_MASK_VOUTL1	BIT(5)
2962306a36Sopenharmony_ci#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW	BIT(6)
3062306a36Sopenharmony_ci#define BD9576_xVD_IRQ_MASK_VOUT1TO4	0x0F
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const unsigned int vout1_volt_table[] = {
3362306a36Sopenharmony_ci	5000000, 4900000, 4800000, 4700000, 4600000,
3462306a36Sopenharmony_ci	4500000, 4500000, 4500000, 5000000, 5100000,
3562306a36Sopenharmony_ci	5200000, 5300000, 5400000, 5500000, 5500000,
3662306a36Sopenharmony_ci	5500000
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const unsigned int vout2_volt_table[] = {
4062306a36Sopenharmony_ci	1800000, 1780000, 1760000, 1740000, 1720000,
4162306a36Sopenharmony_ci	1700000, 1680000, 1660000, 1800000, 1820000,
4262306a36Sopenharmony_ci	1840000, 1860000, 1880000, 1900000, 1920000,
4362306a36Sopenharmony_ci	1940000
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic const unsigned int voutl1_volt_table[] = {
4762306a36Sopenharmony_ci	2500000, 2540000, 2580000, 2620000, 2660000,
4862306a36Sopenharmony_ci	2700000, 2740000, 2780000, 2500000, 2460000,
4962306a36Sopenharmony_ci	2420000, 2380000, 2340000, 2300000, 2260000,
5062306a36Sopenharmony_ci	2220000
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const struct linear_range vout1_xvd_ranges[] = {
5462306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
5562306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
5662306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const struct linear_range vout234_xvd_ranges[] = {
6062306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
6162306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
6262306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0),
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic const struct linear_range voutL1_xvd_ranges[] = {
6662306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
6762306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
6862306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0),
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic struct linear_range voutS1_ocw_ranges_internal[] = {
7262306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0),
7362306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000),
7462306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0),
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic struct linear_range voutS1_ocw_ranges[] = {
7862306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0),
7962306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000),
8062306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0),
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic struct linear_range voutS1_ocp_ranges_internal[] = {
8462306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0),
8562306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000),
8662306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0),
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic struct linear_range voutS1_ocp_ranges[] = {
9062306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0),
9162306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000),
9262306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0),
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct bd957x_regulator_data {
9662306a36Sopenharmony_ci	struct regulator_desc desc;
9762306a36Sopenharmony_ci	int base_voltage;
9862306a36Sopenharmony_ci	struct regulator_dev *rdev;
9962306a36Sopenharmony_ci	int ovd_notif;
10062306a36Sopenharmony_ci	int uvd_notif;
10162306a36Sopenharmony_ci	int temp_notif;
10262306a36Sopenharmony_ci	int ovd_err;
10362306a36Sopenharmony_ci	int uvd_err;
10462306a36Sopenharmony_ci	int temp_err;
10562306a36Sopenharmony_ci	const struct linear_range *xvd_ranges;
10662306a36Sopenharmony_ci	int num_xvd_ranges;
10762306a36Sopenharmony_ci	bool oc_supported;
10862306a36Sopenharmony_ci	unsigned int ovd_reg;
10962306a36Sopenharmony_ci	unsigned int uvd_reg;
11062306a36Sopenharmony_ci	unsigned int xvd_mask;
11162306a36Sopenharmony_ci	unsigned int ocp_reg;
11262306a36Sopenharmony_ci	unsigned int ocp_mask;
11362306a36Sopenharmony_ci	unsigned int ocw_reg;
11462306a36Sopenharmony_ci	unsigned int ocw_mask;
11562306a36Sopenharmony_ci	unsigned int ocw_rfet;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define BD9576_NUM_REGULATORS 6
11962306a36Sopenharmony_ci#define BD9576_NUM_OVD_REGULATORS 5
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistruct bd957x_data {
12262306a36Sopenharmony_ci	struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
12362306a36Sopenharmony_ci	struct regmap *regmap;
12462306a36Sopenharmony_ci	struct delayed_work therm_irq_suppress;
12562306a36Sopenharmony_ci	struct delayed_work ovd_irq_suppress;
12662306a36Sopenharmony_ci	struct delayed_work uvd_irq_suppress;
12762306a36Sopenharmony_ci	unsigned int therm_irq;
12862306a36Sopenharmony_ci	unsigned int ovd_irq;
12962306a36Sopenharmony_ci	unsigned int uvd_irq;
13062306a36Sopenharmony_ci	spinlock_t err_lock;
13162306a36Sopenharmony_ci	int regulator_global_err;
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int bd957x_vout34_list_voltage(struct regulator_dev *rdev,
13562306a36Sopenharmony_ci				      unsigned int selector)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	const struct regulator_desc *desc = rdev->desc;
13862306a36Sopenharmony_ci	int multiplier = selector & desc->vsel_mask & 0x7f;
13962306a36Sopenharmony_ci	int tune;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* VOUT3 and 4 has 10mV step */
14262306a36Sopenharmony_ci	tune = multiplier * 10000;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (!(selector & 0x80))
14562306a36Sopenharmony_ci		return desc->fixed_uV - tune;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return desc->fixed_uV + tune;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int bd957x_list_voltage(struct regulator_dev *rdev,
15162306a36Sopenharmony_ci			       unsigned int selector)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	const struct regulator_desc *desc = rdev->desc;
15462306a36Sopenharmony_ci	int index = selector & desc->vsel_mask & 0x7f;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (!(selector & 0x80))
15762306a36Sopenharmony_ci		index += desc->n_voltages/2;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (index >= desc->n_voltages)
16062306a36Sopenharmony_ci		return -EINVAL;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return desc->volt_table[index];
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data,
16662306a36Sopenharmony_ci				  bool warn)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	if (warn) {
16962306a36Sopenharmony_ci		data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN;
17062306a36Sopenharmony_ci		data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN;
17162306a36Sopenharmony_ci	} else {
17262306a36Sopenharmony_ci		data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT;
17362306a36Sopenharmony_ci		data->ovd_err = REGULATOR_ERROR_REGULATION_OUT;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data,
17862306a36Sopenharmony_ci				  bool warn)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	if (warn) {
18162306a36Sopenharmony_ci		data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN;
18262306a36Sopenharmony_ci		data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN;
18362306a36Sopenharmony_ci	} else {
18462306a36Sopenharmony_ci		data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT;
18562306a36Sopenharmony_ci		data->uvd_err = REGULATOR_ERROR_OVER_CURRENT;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data,
19062306a36Sopenharmony_ci				  bool warn)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	if (warn) {
19362306a36Sopenharmony_ci		data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
19462306a36Sopenharmony_ci		data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN;
19562306a36Sopenharmony_ci	} else {
19662306a36Sopenharmony_ci		data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE;
19762306a36Sopenharmony_ci		data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void bd9576_fill_temp_flags(struct bd957x_regulator_data *data,
20262306a36Sopenharmony_ci				   bool enable, bool warn)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	if (!enable) {
20562306a36Sopenharmony_ci		data->temp_notif = 0;
20662306a36Sopenharmony_ci		data->temp_err = 0;
20762306a36Sopenharmony_ci	} else if (warn) {
20862306a36Sopenharmony_ci		data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN;
20962306a36Sopenharmony_ci		data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN;
21062306a36Sopenharmony_ci	} else {
21162306a36Sopenharmony_ci		data->temp_notif = REGULATOR_EVENT_OVER_TEMP;
21262306a36Sopenharmony_ci		data->temp_err = REGULATOR_ERROR_OVER_TEMP;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int bd9576_set_limit(const struct linear_range *r, int num_ranges,
21762306a36Sopenharmony_ci			    struct regmap *regmap, int reg, int mask, int lim)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	int ret;
22062306a36Sopenharmony_ci	bool found;
22162306a36Sopenharmony_ci	int sel = 0;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (lim) {
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		ret = linear_range_get_selector_low_array(r, num_ranges,
22662306a36Sopenharmony_ci							  lim, &sel, &found);
22762306a36Sopenharmony_ci		if (ret)
22862306a36Sopenharmony_ci			return ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		if (!found)
23162306a36Sopenharmony_ci			dev_warn(regmap_get_device(regmap),
23262306a36Sopenharmony_ci				 "limit %d out of range. Setting lower\n",
23362306a36Sopenharmony_ci				 lim);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return regmap_update_bits(regmap, reg, mask, sel);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity,
24062306a36Sopenharmony_ci				    struct bd957x_regulator_data *r)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	if ((severity == REGULATOR_SEVERITY_ERR &&
24362306a36Sopenharmony_ci	    r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) ||
24462306a36Sopenharmony_ci	    (severity == REGULATOR_SEVERITY_WARN &&
24562306a36Sopenharmony_ci	    r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) {
24662306a36Sopenharmony_ci		dev_warn(rdev_get_dev(rdev),
24762306a36Sopenharmony_ci			 "Can't support both OCP WARN and ERR\n");
24862306a36Sopenharmony_ci		/* Do not overwrite ERR config with WARN */
24962306a36Sopenharmony_ci		if (severity == REGULATOR_SEVERITY_WARN)
25062306a36Sopenharmony_ci			return true;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		bd9576_fill_ocp_flags(r, 0);
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return false;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity,
25962306a36Sopenharmony_ci				    struct bd957x_regulator_data *r)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	if ((severity == REGULATOR_SEVERITY_ERR &&
26262306a36Sopenharmony_ci	     r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) ||
26362306a36Sopenharmony_ci	     (severity == REGULATOR_SEVERITY_WARN &&
26462306a36Sopenharmony_ci	     r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) {
26562306a36Sopenharmony_ci		dev_warn(rdev_get_dev(rdev),
26662306a36Sopenharmony_ci			 "Can't support both UVD WARN and ERR\n");
26762306a36Sopenharmony_ci		if (severity == REGULATOR_SEVERITY_WARN)
26862306a36Sopenharmony_ci			return true;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		bd9576_fill_uvd_flags(r, 0);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return false;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity,
27762306a36Sopenharmony_ci				    struct bd957x_regulator_data *r)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	if ((severity == REGULATOR_SEVERITY_ERR &&
28062306a36Sopenharmony_ci	     r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) ||
28162306a36Sopenharmony_ci	     (severity == REGULATOR_SEVERITY_WARN &&
28262306a36Sopenharmony_ci	     r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) {
28362306a36Sopenharmony_ci		dev_warn(rdev_get_dev(rdev),
28462306a36Sopenharmony_ci			 "Can't support both OVD WARN and ERR\n");
28562306a36Sopenharmony_ci		if (severity == REGULATOR_SEVERITY_WARN)
28662306a36Sopenharmony_ci			return true;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		bd9576_fill_ovd_flags(r, 0);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return false;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity,
29562306a36Sopenharmony_ci				    struct bd957x_regulator_data *r)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	if ((severity == REGULATOR_SEVERITY_ERR &&
29862306a36Sopenharmony_ci	     r->temp_notif != REGULATOR_EVENT_OVER_TEMP) ||
29962306a36Sopenharmony_ci	     (severity == REGULATOR_SEVERITY_WARN &&
30062306a36Sopenharmony_ci	     r->temp_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) {
30162306a36Sopenharmony_ci		dev_warn(rdev_get_dev(rdev),
30262306a36Sopenharmony_ci			 "Can't support both thermal WARN and ERR\n");
30362306a36Sopenharmony_ci		if (severity == REGULATOR_SEVERITY_WARN)
30462306a36Sopenharmony_ci			return true;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return false;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity,
31162306a36Sopenharmony_ci			  bool enable)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct bd957x_data *d;
31462306a36Sopenharmony_ci	struct bd957x_regulator_data *r;
31562306a36Sopenharmony_ci	int reg, mask;
31662306a36Sopenharmony_ci	int Vfet, rfet;
31762306a36Sopenharmony_ci	const struct linear_range *range;
31862306a36Sopenharmony_ci	int num_ranges;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if ((lim_uA && !enable) || (!lim_uA && enable))
32162306a36Sopenharmony_ci		return -EINVAL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
32462306a36Sopenharmony_ci	if (!r->oc_supported)
32562306a36Sopenharmony_ci		return -EINVAL;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	d = rdev_get_drvdata(rdev);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (severity == REGULATOR_SEVERITY_PROT) {
33062306a36Sopenharmony_ci		reg = r->ocp_reg;
33162306a36Sopenharmony_ci		mask = r->ocp_mask;
33262306a36Sopenharmony_ci		if (r->ocw_rfet) {
33362306a36Sopenharmony_ci			range = voutS1_ocp_ranges;
33462306a36Sopenharmony_ci			num_ranges = ARRAY_SIZE(voutS1_ocp_ranges);
33562306a36Sopenharmony_ci			rfet = r->ocw_rfet / 1000;
33662306a36Sopenharmony_ci		} else {
33762306a36Sopenharmony_ci			range = voutS1_ocp_ranges_internal;
33862306a36Sopenharmony_ci			num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal);
33962306a36Sopenharmony_ci			/* Internal values are already micro-amperes */
34062306a36Sopenharmony_ci			rfet = 1000;
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci	} else {
34362306a36Sopenharmony_ci		reg = r->ocw_reg;
34462306a36Sopenharmony_ci		mask = r->ocw_mask;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		if (r->ocw_rfet) {
34762306a36Sopenharmony_ci			range = voutS1_ocw_ranges;
34862306a36Sopenharmony_ci			num_ranges = ARRAY_SIZE(voutS1_ocw_ranges);
34962306a36Sopenharmony_ci			rfet = r->ocw_rfet / 1000;
35062306a36Sopenharmony_ci		} else {
35162306a36Sopenharmony_ci			range = voutS1_ocw_ranges_internal;
35262306a36Sopenharmony_ci			num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal);
35362306a36Sopenharmony_ci			/* Internal values are already micro-amperes */
35462306a36Sopenharmony_ci			rfet = 1000;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		/* We abuse uvd fields for OCW on VoutS1 */
35862306a36Sopenharmony_ci		if (r->uvd_notif) {
35962306a36Sopenharmony_ci			/*
36062306a36Sopenharmony_ci			 * If both warning and error are requested, prioritize
36162306a36Sopenharmony_ci			 * ERROR configuration
36262306a36Sopenharmony_ci			 */
36362306a36Sopenharmony_ci			if (check_ocp_flag_mismatch(rdev, severity, r))
36462306a36Sopenharmony_ci				return 0;
36562306a36Sopenharmony_ci		} else {
36662306a36Sopenharmony_ci			bool warn = severity == REGULATOR_SEVERITY_WARN;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			bd9576_fill_ocp_flags(r, warn);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * limits are given in uA, rfet is mOhm
37462306a36Sopenharmony_ci	 * Divide lim_uA by 1000 to get Vfet in uV.
37562306a36Sopenharmony_ci	 * (We expect both Rfet and limit uA to be magnitude of hundreds of
37662306a36Sopenharmony_ci	 * milli Amperes & milli Ohms => we should still have decent accuracy)
37762306a36Sopenharmony_ci	 */
37862306a36Sopenharmony_ci	Vfet = lim_uA/1000 * rfet;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return bd9576_set_limit(range, num_ranges, d->regmap,
38162306a36Sopenharmony_ci				reg, mask, Vfet);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity,
38562306a36Sopenharmony_ci			  bool enable)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct bd957x_data *d;
38862306a36Sopenharmony_ci	struct bd957x_regulator_data *r;
38962306a36Sopenharmony_ci	int mask, reg;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (severity == REGULATOR_SEVERITY_PROT) {
39262306a36Sopenharmony_ci		if (!enable || lim_uV)
39362306a36Sopenharmony_ci			return -EINVAL;
39462306a36Sopenharmony_ci		return 0;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * BD9576 has enable control as a special value in limit reg. Can't
39962306a36Sopenharmony_ci	 * set limit but keep feature disabled or enable W/O given limit.
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	if ((lim_uV && !enable) || (!lim_uV && enable))
40262306a36Sopenharmony_ci		return -EINVAL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
40562306a36Sopenharmony_ci	d = rdev_get_drvdata(rdev);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	mask = r->xvd_mask;
40862306a36Sopenharmony_ci	reg = r->uvd_reg;
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Check that there is no mismatch for what the detection IRQs are to
41162306a36Sopenharmony_ci	 * be used.
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	if (r->uvd_notif) {
41462306a36Sopenharmony_ci		if (check_uvd_flag_mismatch(rdev, severity, r))
41562306a36Sopenharmony_ci			return 0;
41662306a36Sopenharmony_ci	} else {
41762306a36Sopenharmony_ci		bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN);
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
42162306a36Sopenharmony_ci				reg, mask, lim_uV);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity,
42562306a36Sopenharmony_ci			  bool enable)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct bd957x_data *d;
42862306a36Sopenharmony_ci	struct bd957x_regulator_data *r;
42962306a36Sopenharmony_ci	int mask, reg;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (severity == REGULATOR_SEVERITY_PROT) {
43262306a36Sopenharmony_ci		if (!enable || lim_uV)
43362306a36Sopenharmony_ci			return -EINVAL;
43462306a36Sopenharmony_ci		return 0;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/*
43862306a36Sopenharmony_ci	 * BD9576 has enable control as a special value in limit reg. Can't
43962306a36Sopenharmony_ci	 * set limit but keep feature disabled or enable W/O given limit.
44062306a36Sopenharmony_ci	 */
44162306a36Sopenharmony_ci	if ((lim_uV && !enable) || (!lim_uV && enable))
44262306a36Sopenharmony_ci		return -EINVAL;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
44562306a36Sopenharmony_ci	d = rdev_get_drvdata(rdev);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	mask = r->xvd_mask;
44862306a36Sopenharmony_ci	reg = r->ovd_reg;
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * Check that there is no mismatch for what the detection IRQs are to
45162306a36Sopenharmony_ci	 * be used.
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	if (r->ovd_notif) {
45462306a36Sopenharmony_ci		if (check_ovd_flag_mismatch(rdev, severity, r))
45562306a36Sopenharmony_ci			return 0;
45662306a36Sopenharmony_ci	} else {
45762306a36Sopenharmony_ci		bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN);
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
46162306a36Sopenharmony_ci				reg, mask, lim_uV);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity,
46662306a36Sopenharmony_ci			  bool enable)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct bd957x_data *d;
46962306a36Sopenharmony_ci	struct bd957x_regulator_data *r;
47062306a36Sopenharmony_ci	int i;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/*
47362306a36Sopenharmony_ci	 * BD9576MUF has fixed temperature limits
47462306a36Sopenharmony_ci	 * The detection can only be enabled/disabled
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci	if (lim)
47762306a36Sopenharmony_ci		return -EINVAL;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Protection can't be disabled */
48062306a36Sopenharmony_ci	if (severity == REGULATOR_SEVERITY_PROT) {
48162306a36Sopenharmony_ci		if (!enable)
48262306a36Sopenharmony_ci			return -EINVAL;
48362306a36Sopenharmony_ci		else
48462306a36Sopenharmony_ci			return 0;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
48862306a36Sopenharmony_ci	d = rdev_get_drvdata(rdev);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/*
49162306a36Sopenharmony_ci	 * Check that there is no mismatch for what the detection IRQs are to
49262306a36Sopenharmony_ci	 * be used.
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	if (r->temp_notif)
49562306a36Sopenharmony_ci		if (check_temp_flag_mismatch(rdev, severity, r))
49662306a36Sopenharmony_ci			return 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (enable)
50162306a36Sopenharmony_ci		return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
50262306a36Sopenharmony_ci					 BD9576_THERM_IRQ_MASK_TW, 0);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * If any of the regulators is interested in thermal warning we keep IRQ
50662306a36Sopenharmony_ci	 * enabled.
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	for (i = 0; i < BD9576_NUM_REGULATORS; i++)
50962306a36Sopenharmony_ci		if (d->regulator_data[i].temp_notif)
51062306a36Sopenharmony_ci			return 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
51362306a36Sopenharmony_ci				  BD9576_THERM_IRQ_MASK_TW,
51462306a36Sopenharmony_ci				  BD9576_THERM_IRQ_MASK_TW);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic const struct regulator_ops bd9573_vout34_ops = {
51862306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
51962306a36Sopenharmony_ci	.list_voltage = bd957x_vout34_list_voltage,
52062306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
52162306a36Sopenharmony_ci};
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic const struct regulator_ops bd9576_vout34_ops = {
52462306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
52562306a36Sopenharmony_ci	.list_voltage = bd957x_vout34_list_voltage,
52662306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
52762306a36Sopenharmony_ci	.set_over_voltage_protection = bd9576_set_ovp,
52862306a36Sopenharmony_ci	.set_under_voltage_protection = bd9576_set_uvp,
52962306a36Sopenharmony_ci	.set_thermal_protection = bd9576_set_tw,
53062306a36Sopenharmony_ci};
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic const struct regulator_ops bd9573_vouts1_regulator_ops = {
53362306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
53462306a36Sopenharmony_ci};
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic const struct regulator_ops bd9576_vouts1_regulator_ops = {
53762306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
53862306a36Sopenharmony_ci	.set_over_current_protection = bd9576_set_ocp,
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic const struct regulator_ops bd9573_ops = {
54262306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
54362306a36Sopenharmony_ci	.list_voltage = bd957x_list_voltage,
54462306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
54562306a36Sopenharmony_ci};
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic const struct regulator_ops bd9576_ops = {
54862306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
54962306a36Sopenharmony_ci	.list_voltage = bd957x_list_voltage,
55062306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
55162306a36Sopenharmony_ci	.set_over_voltage_protection = bd9576_set_ovp,
55262306a36Sopenharmony_ci	.set_under_voltage_protection = bd9576_set_uvp,
55362306a36Sopenharmony_ci	.set_thermal_protection = bd9576_set_tw,
55462306a36Sopenharmony_ci};
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic const struct regulator_ops  *bd9573_ops_arr[] = {
55762306a36Sopenharmony_ci	[BD957X_VD50]	= &bd9573_ops,
55862306a36Sopenharmony_ci	[BD957X_VD18]	= &bd9573_ops,
55962306a36Sopenharmony_ci	[BD957X_VDDDR]	= &bd9573_vout34_ops,
56062306a36Sopenharmony_ci	[BD957X_VD10]	= &bd9573_vout34_ops,
56162306a36Sopenharmony_ci	[BD957X_VOUTL1]	= &bd9573_ops,
56262306a36Sopenharmony_ci	[BD957X_VOUTS1]	= &bd9573_vouts1_regulator_ops,
56362306a36Sopenharmony_ci};
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic const struct regulator_ops  *bd9576_ops_arr[] = {
56662306a36Sopenharmony_ci	[BD957X_VD50]	= &bd9576_ops,
56762306a36Sopenharmony_ci	[BD957X_VD18]	= &bd9576_ops,
56862306a36Sopenharmony_ci	[BD957X_VDDDR]	= &bd9576_vout34_ops,
56962306a36Sopenharmony_ci	[BD957X_VD10]	= &bd9576_vout34_ops,
57062306a36Sopenharmony_ci	[BD957X_VOUTL1]	= &bd9576_ops,
57162306a36Sopenharmony_ci	[BD957X_VOUTS1]	= &bd9576_vouts1_regulator_ops,
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic int vouts1_get_fet_res(struct device_node *np,
57562306a36Sopenharmony_ci				const struct regulator_desc *desc,
57662306a36Sopenharmony_ci				struct regulator_config *cfg)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct bd957x_regulator_data *data;
57962306a36Sopenharmony_ci	int ret;
58062306a36Sopenharmony_ci	u32 uohms;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	data = container_of(desc, struct bd957x_regulator_data, desc);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms);
58562306a36Sopenharmony_ci	if (ret) {
58662306a36Sopenharmony_ci		if (ret != -EINVAL)
58762306a36Sopenharmony_ci			return ret;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		return 0;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci	data->ocw_rfet = uohms;
59262306a36Sopenharmony_ci	return 0;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic struct bd957x_data bd957x_regulators = {
59662306a36Sopenharmony_ci	.regulator_data = {
59762306a36Sopenharmony_ci		{
59862306a36Sopenharmony_ci			.desc = {
59962306a36Sopenharmony_ci				.name = "VD50",
60062306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-vd50"),
60162306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
60262306a36Sopenharmony_ci				.id = BD957X_VD50,
60362306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
60462306a36Sopenharmony_ci				.volt_table = &vout1_volt_table[0],
60562306a36Sopenharmony_ci				.n_voltages = ARRAY_SIZE(vout1_volt_table),
60662306a36Sopenharmony_ci				.vsel_reg = BD957X_REG_VOUT1_TUNE,
60762306a36Sopenharmony_ci				.vsel_mask = BD957X_MASK_VOUT1_TUNE,
60862306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGER1,
60962306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
61062306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
61162306a36Sopenharmony_ci				.enable_is_inverted = true,
61262306a36Sopenharmony_ci				.owner = THIS_MODULE,
61362306a36Sopenharmony_ci			},
61462306a36Sopenharmony_ci			.xvd_ranges = vout1_xvd_ranges,
61562306a36Sopenharmony_ci			.num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges),
61662306a36Sopenharmony_ci			.ovd_reg = BD9576_REG_VOUT1_OVD,
61762306a36Sopenharmony_ci			.uvd_reg = BD9576_REG_VOUT1_UVD,
61862306a36Sopenharmony_ci			.xvd_mask = BD9576_MASK_XVD,
61962306a36Sopenharmony_ci		},
62062306a36Sopenharmony_ci		{
62162306a36Sopenharmony_ci			.desc = {
62262306a36Sopenharmony_ci				.name = "VD18",
62362306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-vd18"),
62462306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
62562306a36Sopenharmony_ci				.id = BD957X_VD18,
62662306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
62762306a36Sopenharmony_ci				.volt_table = &vout2_volt_table[0],
62862306a36Sopenharmony_ci				.n_voltages = ARRAY_SIZE(vout2_volt_table),
62962306a36Sopenharmony_ci				.vsel_reg = BD957X_REG_VOUT2_TUNE,
63062306a36Sopenharmony_ci				.vsel_mask = BD957X_MASK_VOUT2_TUNE,
63162306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGER2,
63262306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
63362306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
63462306a36Sopenharmony_ci				.enable_is_inverted = true,
63562306a36Sopenharmony_ci				.owner = THIS_MODULE,
63662306a36Sopenharmony_ci			},
63762306a36Sopenharmony_ci			.xvd_ranges = vout234_xvd_ranges,
63862306a36Sopenharmony_ci			.num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
63962306a36Sopenharmony_ci			.ovd_reg = BD9576_REG_VOUT2_OVD,
64062306a36Sopenharmony_ci			.uvd_reg = BD9576_REG_VOUT2_UVD,
64162306a36Sopenharmony_ci			.xvd_mask = BD9576_MASK_XVD,
64262306a36Sopenharmony_ci		},
64362306a36Sopenharmony_ci		{
64462306a36Sopenharmony_ci			.desc = {
64562306a36Sopenharmony_ci				.name = "VDDDR",
64662306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-vdddr"),
64762306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
64862306a36Sopenharmony_ci				.id = BD957X_VDDDR,
64962306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
65062306a36Sopenharmony_ci				.n_voltages = BD957X_VOUTS34_NUM_VOLT,
65162306a36Sopenharmony_ci				.vsel_reg = BD957X_REG_VOUT3_TUNE,
65262306a36Sopenharmony_ci				.vsel_mask = BD957X_MASK_VOUT3_TUNE,
65362306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGER3,
65462306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
65562306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
65662306a36Sopenharmony_ci				.enable_is_inverted = true,
65762306a36Sopenharmony_ci				.owner = THIS_MODULE,
65862306a36Sopenharmony_ci			},
65962306a36Sopenharmony_ci			.ovd_reg = BD9576_REG_VOUT3_OVD,
66062306a36Sopenharmony_ci			.uvd_reg = BD9576_REG_VOUT3_UVD,
66162306a36Sopenharmony_ci			.xvd_mask = BD9576_MASK_XVD,
66262306a36Sopenharmony_ci			.xvd_ranges = vout234_xvd_ranges,
66362306a36Sopenharmony_ci			.num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
66462306a36Sopenharmony_ci		},
66562306a36Sopenharmony_ci		{
66662306a36Sopenharmony_ci			.desc = {
66762306a36Sopenharmony_ci				.name = "VD10",
66862306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-vd10"),
66962306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
67062306a36Sopenharmony_ci				.id = BD957X_VD10,
67162306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
67262306a36Sopenharmony_ci				.fixed_uV = BD957X_VOUTS4_BASE_VOLT,
67362306a36Sopenharmony_ci				.n_voltages = BD957X_VOUTS34_NUM_VOLT,
67462306a36Sopenharmony_ci				.vsel_reg = BD957X_REG_VOUT4_TUNE,
67562306a36Sopenharmony_ci				.vsel_mask = BD957X_MASK_VOUT4_TUNE,
67662306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGER4,
67762306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
67862306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
67962306a36Sopenharmony_ci				.enable_is_inverted = true,
68062306a36Sopenharmony_ci				.owner = THIS_MODULE,
68162306a36Sopenharmony_ci			},
68262306a36Sopenharmony_ci			.xvd_ranges = vout234_xvd_ranges,
68362306a36Sopenharmony_ci			.num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
68462306a36Sopenharmony_ci			.ovd_reg = BD9576_REG_VOUT4_OVD,
68562306a36Sopenharmony_ci			.uvd_reg = BD9576_REG_VOUT4_UVD,
68662306a36Sopenharmony_ci			.xvd_mask = BD9576_MASK_XVD,
68762306a36Sopenharmony_ci		},
68862306a36Sopenharmony_ci		{
68962306a36Sopenharmony_ci			.desc = {
69062306a36Sopenharmony_ci				.name = "VOUTL1",
69162306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-voutl1"),
69262306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
69362306a36Sopenharmony_ci				.id = BD957X_VOUTL1,
69462306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
69562306a36Sopenharmony_ci				.volt_table = &voutl1_volt_table[0],
69662306a36Sopenharmony_ci				.n_voltages = ARRAY_SIZE(voutl1_volt_table),
69762306a36Sopenharmony_ci				.vsel_reg = BD957X_REG_VOUTL1_TUNE,
69862306a36Sopenharmony_ci				.vsel_mask = BD957X_MASK_VOUTL1_TUNE,
69962306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGERL1,
70062306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
70162306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
70262306a36Sopenharmony_ci				.enable_is_inverted = true,
70362306a36Sopenharmony_ci				.owner = THIS_MODULE,
70462306a36Sopenharmony_ci			},
70562306a36Sopenharmony_ci			.xvd_ranges = voutL1_xvd_ranges,
70662306a36Sopenharmony_ci			.num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges),
70762306a36Sopenharmony_ci			.ovd_reg = BD9576_REG_VOUTL1_OVD,
70862306a36Sopenharmony_ci			.uvd_reg = BD9576_REG_VOUTL1_UVD,
70962306a36Sopenharmony_ci			.xvd_mask = BD9576_MASK_XVD,
71062306a36Sopenharmony_ci		},
71162306a36Sopenharmony_ci		{
71262306a36Sopenharmony_ci			.desc = {
71362306a36Sopenharmony_ci				.name = "VOUTS1",
71462306a36Sopenharmony_ci				.of_match = of_match_ptr("regulator-vouts1"),
71562306a36Sopenharmony_ci				.regulators_node = of_match_ptr("regulators"),
71662306a36Sopenharmony_ci				.id = BD957X_VOUTS1,
71762306a36Sopenharmony_ci				.type = REGULATOR_VOLTAGE,
71862306a36Sopenharmony_ci				.n_voltages = 1,
71962306a36Sopenharmony_ci				.fixed_uV = BD957X_VOUTS1_VOLT,
72062306a36Sopenharmony_ci				.enable_reg = BD957X_REG_POW_TRIGGERS1,
72162306a36Sopenharmony_ci				.enable_mask = BD957X_REGULATOR_EN_MASK,
72262306a36Sopenharmony_ci				.enable_val = BD957X_REGULATOR_DIS_VAL,
72362306a36Sopenharmony_ci				.enable_is_inverted = true,
72462306a36Sopenharmony_ci				.owner = THIS_MODULE,
72562306a36Sopenharmony_ci				.of_parse_cb = vouts1_get_fet_res,
72662306a36Sopenharmony_ci			},
72762306a36Sopenharmony_ci			.oc_supported = true,
72862306a36Sopenharmony_ci			.ocw_reg = BD9576_REG_VOUT1S_OCW,
72962306a36Sopenharmony_ci			.ocw_mask = BD9576_MASK_VOUT1S_OCW,
73062306a36Sopenharmony_ci			.ocp_reg = BD9576_REG_VOUT1S_OCP,
73162306a36Sopenharmony_ci			.ocp_mask = BD9576_MASK_VOUT1S_OCP,
73262306a36Sopenharmony_ci		},
73362306a36Sopenharmony_ci	},
73462306a36Sopenharmony_ci};
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	int val, ret;
73962306a36Sopenharmony_ci	struct bd957x_data *d = (struct bd957x_data *)rid->data;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	ret = regmap_read(d->regmap, reg, &val);
74262306a36Sopenharmony_ci	if (ret)
74362306a36Sopenharmony_ci		return REGULATOR_FAILED_RETRY;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (rid->opaque && rid->opaque == (val & mask)) {
74662306a36Sopenharmony_ci		/*
74762306a36Sopenharmony_ci		 * It seems we stil have same status. Ack and return
74862306a36Sopenharmony_ci		 * information that we are still out of limits and core
74962306a36Sopenharmony_ci		 * should not enable IRQ
75062306a36Sopenharmony_ci		 */
75162306a36Sopenharmony_ci		regmap_write(d->regmap, reg, mask & val);
75262306a36Sopenharmony_ci		return REGULATOR_ERROR_ON;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci	rid->opaque = 0;
75562306a36Sopenharmony_ci	/*
75662306a36Sopenharmony_ci	 * Status was changed. Either prolem was solved or we have new issues.
75762306a36Sopenharmony_ci	 * Let's re-enable IRQs and be prepared to report problems again
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	return REGULATOR_ERROR_CLEARED;
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic int bd9576_uvd_renable(struct regulator_irq_data *rid)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int bd9576_ovd_renable(struct regulator_irq_data *rid)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic int bd9576_temp_renable(struct regulator_irq_data *rid)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT,
77562306a36Sopenharmony_ci			      BD9576_THERM_IRQ_MASK_TW);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid,
77962306a36Sopenharmony_ci			      unsigned long *dev_mask)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	int val, ret, i;
78262306a36Sopenharmony_ci	struct bd957x_data *d = (struct bd957x_data *)rid->data;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val);
78562306a36Sopenharmony_ci	if (ret)
78662306a36Sopenharmony_ci		return REGULATOR_FAILED_RETRY;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	*dev_mask = 0;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	rid->opaque = val & UVD_IRQ_VALID_MASK;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/*
79362306a36Sopenharmony_ci	 * Go through the set status bits and report either error or warning
79462306a36Sopenharmony_ci	 * to the notifier depending on what was flagged in DT
79562306a36Sopenharmony_ci	 */
79662306a36Sopenharmony_ci	*dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
79762306a36Sopenharmony_ci	/* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
79862306a36Sopenharmony_ci	*dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
79962306a36Sopenharmony_ci	/*
80062306a36Sopenharmony_ci	 * We (ab)use the uvd for OCW notification. DT parsing should
80162306a36Sopenharmony_ci	 * have added correct OCW flag to uvd_notif and uvd_err for S1
80262306a36Sopenharmony_ci	 */
80362306a36Sopenharmony_ci	*dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	for_each_set_bit(i, dev_mask, 6) {
80662306a36Sopenharmony_ci		struct bd957x_regulator_data *rdata;
80762306a36Sopenharmony_ci		struct regulator_err_state *stat;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		rdata = &d->regulator_data[i];
81062306a36Sopenharmony_ci		stat  = &rid->states[i];
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		stat->notifs	= rdata->uvd_notif;
81362306a36Sopenharmony_ci		stat->errors	= rdata->uvd_err;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT,
81762306a36Sopenharmony_ci			   UVD_IRQ_VALID_MASK & val);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return 0;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid,
82362306a36Sopenharmony_ci			      unsigned long *dev_mask)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	int val, ret, i;
82662306a36Sopenharmony_ci	struct bd957x_data *d = (struct bd957x_data *)rid->data;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val);
82962306a36Sopenharmony_ci	if (ret)
83062306a36Sopenharmony_ci		return REGULATOR_FAILED_RETRY;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	rid->opaque = val & OVD_IRQ_VALID_MASK;
83362306a36Sopenharmony_ci	*dev_mask = 0;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	if (!(val & OVD_IRQ_VALID_MASK))
83662306a36Sopenharmony_ci		return 0;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	*dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
83962306a36Sopenharmony_ci	/* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
84062306a36Sopenharmony_ci	*dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	for_each_set_bit(i, dev_mask, 5) {
84362306a36Sopenharmony_ci		struct bd957x_regulator_data *rdata;
84462306a36Sopenharmony_ci		struct regulator_err_state *stat;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		rdata = &d->regulator_data[i];
84762306a36Sopenharmony_ci		stat  = &rid->states[i];
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci		stat->notifs	= rdata->ovd_notif;
85062306a36Sopenharmony_ci		stat->errors	= rdata->ovd_err;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* Clear the sub-IRQ status */
85462306a36Sopenharmony_ci	regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT,
85562306a36Sopenharmony_ci		     OVD_IRQ_VALID_MASK & val);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return 0;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci#define BD9576_DEV_MASK_ALL_REGULATORS 0x3F
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid,
86362306a36Sopenharmony_ci				  unsigned long *dev_mask)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	int val, ret, i;
86662306a36Sopenharmony_ci	struct bd957x_data *d = (struct bd957x_data *)rid->data;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val);
86962306a36Sopenharmony_ci	if (ret)
87062306a36Sopenharmony_ci		return REGULATOR_FAILED_RETRY;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (!(val & BD9576_THERM_IRQ_MASK_TW)) {
87362306a36Sopenharmony_ci		*dev_mask = 0;
87462306a36Sopenharmony_ci		return 0;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	*dev_mask = BD9576_DEV_MASK_ALL_REGULATORS;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	for (i = 0; i < BD9576_NUM_REGULATORS; i++) {
88062306a36Sopenharmony_ci		struct bd957x_regulator_data *rdata;
88162306a36Sopenharmony_ci		struct regulator_err_state *stat;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci		rdata = &d->regulator_data[i];
88462306a36Sopenharmony_ci		stat  = &rid->states[i];
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		stat->notifs	= rdata->temp_notif;
88762306a36Sopenharmony_ci		stat->errors	= rdata->temp_err;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* Clear the sub-IRQ status */
89162306a36Sopenharmony_ci	regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT,
89262306a36Sopenharmony_ci		     BD9576_THERM_IRQ_MASK_TW);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int bd957x_probe(struct platform_device *pdev)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	int i;
90062306a36Sopenharmony_ci	unsigned int num_reg_data;
90162306a36Sopenharmony_ci	bool vout_mode, ddr_sel, may_have_irqs = false;
90262306a36Sopenharmony_ci	struct regmap *regmap;
90362306a36Sopenharmony_ci	struct bd957x_data *ic_data;
90462306a36Sopenharmony_ci	struct regulator_config config = { 0 };
90562306a36Sopenharmony_ci	/* All regulators are related to UVD and thermal IRQs... */
90662306a36Sopenharmony_ci	struct regulator_dev *rdevs[BD9576_NUM_REGULATORS];
90762306a36Sopenharmony_ci	/* ...But VoutS1 is not flagged by OVD IRQ */
90862306a36Sopenharmony_ci	struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS];
90962306a36Sopenharmony_ci	static const struct regulator_irq_desc bd9576_notif_uvd = {
91062306a36Sopenharmony_ci		.name = "bd9576-uvd",
91162306a36Sopenharmony_ci		.irq_off_ms = 1000,
91262306a36Sopenharmony_ci		.map_event = bd9576_uvd_handler,
91362306a36Sopenharmony_ci		.renable = bd9576_uvd_renable,
91462306a36Sopenharmony_ci		.data = &bd957x_regulators,
91562306a36Sopenharmony_ci	};
91662306a36Sopenharmony_ci	static const struct regulator_irq_desc bd9576_notif_ovd = {
91762306a36Sopenharmony_ci		.name = "bd9576-ovd",
91862306a36Sopenharmony_ci		.irq_off_ms = 1000,
91962306a36Sopenharmony_ci		.map_event = bd9576_ovd_handler,
92062306a36Sopenharmony_ci		.renable = bd9576_ovd_renable,
92162306a36Sopenharmony_ci		.data = &bd957x_regulators,
92262306a36Sopenharmony_ci	};
92362306a36Sopenharmony_ci	static const struct regulator_irq_desc bd9576_notif_temp = {
92462306a36Sopenharmony_ci		.name = "bd9576-temp",
92562306a36Sopenharmony_ci		.irq_off_ms = 1000,
92662306a36Sopenharmony_ci		.map_event = bd9576_thermal_handler,
92762306a36Sopenharmony_ci		.renable = bd9576_temp_renable,
92862306a36Sopenharmony_ci		.data = &bd957x_regulators,
92962306a36Sopenharmony_ci	};
93062306a36Sopenharmony_ci	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	ic_data = &bd957x_regulators;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	regmap = dev_get_regmap(pdev->dev.parent, NULL);
93762306a36Sopenharmony_ci	if (!regmap) {
93862306a36Sopenharmony_ci		dev_err(&pdev->dev, "No regmap\n");
93962306a36Sopenharmony_ci		return -EINVAL;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	ic_data->regmap = regmap;
94362306a36Sopenharmony_ci	vout_mode = device_property_read_bool(pdev->dev.parent,
94462306a36Sopenharmony_ci					      "rohm,vout1-en-low");
94562306a36Sopenharmony_ci	if (vout_mode) {
94662306a36Sopenharmony_ci		struct gpio_desc *en;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "GPIO controlled mode\n");
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		/* VOUT1 enable state judged by VOUT1_EN pin */
95162306a36Sopenharmony_ci		/* See if we have GPIO defined */
95262306a36Sopenharmony_ci		en = devm_fwnode_gpiod_get(&pdev->dev,
95362306a36Sopenharmony_ci					   dev_fwnode(pdev->dev.parent),
95462306a36Sopenharmony_ci					   "rohm,vout1-en", GPIOD_OUT_LOW,
95562306a36Sopenharmony_ci					   "vout1-en");
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		/* VOUT1_OPS gpio ctrl */
95862306a36Sopenharmony_ci		/*
95962306a36Sopenharmony_ci		 * Regulator core prioritizes the ena_gpio over
96062306a36Sopenharmony_ci		 * enable/disable/is_enabled callbacks so no need to clear them
96162306a36Sopenharmony_ci		 * even if GPIO is used. So, we can still use same ops.
96262306a36Sopenharmony_ci		 *
96362306a36Sopenharmony_ci		 * In theory it is possible someone wants to set vout1-en LOW
96462306a36Sopenharmony_ci		 * during OTP loading and set VOUT1 to be controlled by GPIO -
96562306a36Sopenharmony_ci		 * but control the GPIO from some where else than this driver.
96662306a36Sopenharmony_ci		 * For that to work we should unset the is_enabled callback
96762306a36Sopenharmony_ci		 * here.
96862306a36Sopenharmony_ci		 *
96962306a36Sopenharmony_ci		 * I believe such case where rohm,vout1-en-low is set and
97062306a36Sopenharmony_ci		 * vout1-en-gpios is not is likely to be a misconfiguration.
97162306a36Sopenharmony_ci		 * So let's just err out for now.
97262306a36Sopenharmony_ci		 */
97362306a36Sopenharmony_ci		if (!IS_ERR(en))
97462306a36Sopenharmony_ci			config.ena_gpiod = en;
97562306a36Sopenharmony_ci		else
97662306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, PTR_ERR(en),
97762306a36Sopenharmony_ci					"Failed to get VOUT1 control GPIO\n");
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/*
98162306a36Sopenharmony_ci	 * If more than one PMIC needs to be controlled by same processor then
98262306a36Sopenharmony_ci	 * allocate the regulator data array here and use bd9576_regulators as
98362306a36Sopenharmony_ci	 * template. At the moment I see no such use-case so I spare some
98462306a36Sopenharmony_ci	 * bytes and use bd9576_regulators directly for non-constant configs
98562306a36Sopenharmony_ci	 * like DDR voltage selection.
98662306a36Sopenharmony_ci	 */
98762306a36Sopenharmony_ci	platform_set_drvdata(pdev, ic_data);
98862306a36Sopenharmony_ci	ddr_sel = device_property_read_bool(pdev->dev.parent,
98962306a36Sopenharmony_ci					    "rohm,ddr-sel-low");
99062306a36Sopenharmony_ci	if (ddr_sel)
99162306a36Sopenharmony_ci		ic_data->regulator_data[2].desc.fixed_uV = 1350000;
99262306a36Sopenharmony_ci	else
99362306a36Sopenharmony_ci		ic_data->regulator_data[2].desc.fixed_uV = 1500000;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	switch (chip) {
99662306a36Sopenharmony_ci	case ROHM_CHIP_TYPE_BD9576:
99762306a36Sopenharmony_ci		may_have_irqs = true;
99862306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "Found BD9576MUF\n");
99962306a36Sopenharmony_ci		break;
100062306a36Sopenharmony_ci	case ROHM_CHIP_TYPE_BD9573:
100162306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "Found BD9573MUF\n");
100262306a36Sopenharmony_ci		break;
100362306a36Sopenharmony_ci	default:
100462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unsupported chip type\n");
100562306a36Sopenharmony_ci		return -EINVAL;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	for (i = 0; i < num_reg_data; i++) {
100962306a36Sopenharmony_ci		struct regulator_desc *d;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci		d = &ic_data->regulator_data[i].desc;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		if (may_have_irqs) {
101562306a36Sopenharmony_ci			if (d->id >= ARRAY_SIZE(bd9576_ops_arr))
101662306a36Sopenharmony_ci				return -EINVAL;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci			d->ops = bd9576_ops_arr[d->id];
101962306a36Sopenharmony_ci		} else {
102062306a36Sopenharmony_ci			if (d->id >= ARRAY_SIZE(bd9573_ops_arr))
102162306a36Sopenharmony_ci				return -EINVAL;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci			d->ops = bd9573_ops_arr[d->id];
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	config.dev = pdev->dev.parent;
102862306a36Sopenharmony_ci	config.regmap = regmap;
102962306a36Sopenharmony_ci	config.driver_data = ic_data;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	for (i = 0; i < num_reg_data; i++) {
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		struct bd957x_regulator_data *r = &ic_data->regulator_data[i];
103462306a36Sopenharmony_ci		const struct regulator_desc *desc = &r->desc;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		r->rdev = devm_regulator_register(&pdev->dev, desc,
103762306a36Sopenharmony_ci							   &config);
103862306a36Sopenharmony_ci		if (IS_ERR(r->rdev))
103962306a36Sopenharmony_ci			return dev_err_probe(&pdev->dev, PTR_ERR(r->rdev),
104062306a36Sopenharmony_ci					"failed to register %s regulator\n",
104162306a36Sopenharmony_ci					desc->name);
104262306a36Sopenharmony_ci		/*
104362306a36Sopenharmony_ci		 * Clear the VOUT1 GPIO setting - rest of the regulators do not
104462306a36Sopenharmony_ci		 * support GPIO control
104562306a36Sopenharmony_ci		 */
104662306a36Sopenharmony_ci		config.ena_gpiod = NULL;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		if (!may_have_irqs)
104962306a36Sopenharmony_ci			continue;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci		rdevs[i] = r->rdev;
105262306a36Sopenharmony_ci		if (i < BD957X_VOUTS1)
105362306a36Sopenharmony_ci			ovd_devs[i] = r->rdev;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci	if (may_have_irqs) {
105662306a36Sopenharmony_ci		void *ret;
105762306a36Sopenharmony_ci		/*
105862306a36Sopenharmony_ci		 * We can add both the possible error and warning flags here
105962306a36Sopenharmony_ci		 * because the core uses these only for status clearing and
106062306a36Sopenharmony_ci		 * if we use warnings - errors are always clear and the other
106162306a36Sopenharmony_ci		 * way around. We can also add CURRENT flag for all regulators
106262306a36Sopenharmony_ci		 * because it is never set if it is not supported. Same applies
106362306a36Sopenharmony_ci		 * to setting UVD for VoutS1 - it is not accidentally cleared
106462306a36Sopenharmony_ci		 * as it is never set.
106562306a36Sopenharmony_ci		 */
106662306a36Sopenharmony_ci		int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE |
106762306a36Sopenharmony_ci			       REGULATOR_ERROR_UNDER_VOLTAGE_WARN |
106862306a36Sopenharmony_ci			       REGULATOR_ERROR_OVER_CURRENT |
106962306a36Sopenharmony_ci			       REGULATOR_ERROR_OVER_CURRENT_WARN;
107062306a36Sopenharmony_ci		int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN |
107162306a36Sopenharmony_ci			       REGULATOR_ERROR_REGULATION_OUT;
107262306a36Sopenharmony_ci		int temp_errs = REGULATOR_ERROR_OVER_TEMP |
107362306a36Sopenharmony_ci				REGULATOR_ERROR_OVER_TEMP_WARN;
107462306a36Sopenharmony_ci		int irq;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "bd9576-uvd");
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci		/* Register notifiers - can fail if IRQ is not given */
107962306a36Sopenharmony_ci		ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd,
108062306a36Sopenharmony_ci						irq, 0, uvd_errs, NULL,
108162306a36Sopenharmony_ci						&rdevs[0],
108262306a36Sopenharmony_ci						BD9576_NUM_REGULATORS);
108362306a36Sopenharmony_ci		if (IS_ERR(ret)) {
108462306a36Sopenharmony_ci			if (PTR_ERR(ret) == -EPROBE_DEFER)
108562306a36Sopenharmony_ci				return -EPROBE_DEFER;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci			dev_warn(&pdev->dev, "UVD disabled %pe\n", ret);
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "bd9576-ovd");
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd,
109362306a36Sopenharmony_ci						irq, 0, ovd_errs, NULL,
109462306a36Sopenharmony_ci						&ovd_devs[0],
109562306a36Sopenharmony_ci						BD9576_NUM_OVD_REGULATORS);
109662306a36Sopenharmony_ci		if (IS_ERR(ret)) {
109762306a36Sopenharmony_ci			if (PTR_ERR(ret) == -EPROBE_DEFER)
109862306a36Sopenharmony_ci				return -EPROBE_DEFER;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci			dev_warn(&pdev->dev, "OVD disabled %pe\n", ret);
110162306a36Sopenharmony_ci		}
110262306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "bd9576-temp");
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci		ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp,
110562306a36Sopenharmony_ci						irq, 0, temp_errs, NULL,
110662306a36Sopenharmony_ci						&rdevs[0],
110762306a36Sopenharmony_ci						BD9576_NUM_REGULATORS);
110862306a36Sopenharmony_ci		if (IS_ERR(ret)) {
110962306a36Sopenharmony_ci			if (PTR_ERR(ret) == -EPROBE_DEFER)
111062306a36Sopenharmony_ci				return -EPROBE_DEFER;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci			dev_warn(&pdev->dev, "Thermal warning disabled %pe\n",
111362306a36Sopenharmony_ci				 ret);
111462306a36Sopenharmony_ci		}
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci	return 0;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic const struct platform_device_id bd957x_pmic_id[] = {
112062306a36Sopenharmony_ci	{ "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
112162306a36Sopenharmony_ci	{ "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
112262306a36Sopenharmony_ci	{ },
112362306a36Sopenharmony_ci};
112462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic struct platform_driver bd957x_regulator = {
112762306a36Sopenharmony_ci	.driver = {
112862306a36Sopenharmony_ci		.name = "bd957x-pmic",
112962306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
113062306a36Sopenharmony_ci	},
113162306a36Sopenharmony_ci	.probe = bd957x_probe,
113262306a36Sopenharmony_ci	.id_table = bd957x_pmic_id,
113362306a36Sopenharmony_ci};
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cimodule_platform_driver(bd957x_regulator);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ciMODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
113862306a36Sopenharmony_ciMODULE_DESCRIPTION("ROHM BD9576/BD9573 voltage regulator driver");
113962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
114062306a36Sopenharmony_ciMODULE_ALIAS("platform:bd957x-pmic");
1141