1af71cccaSOkan Sahin // SPDX-License-Identifier: GPL-2.0-only
2af71cccaSOkan Sahin /*
3af71cccaSOkan Sahin  * Copyright (c) 2023 Analog Devices, Inc.
4af71cccaSOkan Sahin  * ADI Regulator driver for the MAX77857
5af71cccaSOkan Sahin  * MAX77859 and MAX77831.
6af71cccaSOkan Sahin  */
7af71cccaSOkan Sahin #include <linux/bitfield.h>
8af71cccaSOkan Sahin #include <linux/i2c.h>
9af71cccaSOkan Sahin #include <linux/interrupt.h>
10af71cccaSOkan Sahin #include <linux/module.h>
11af71cccaSOkan Sahin #include <linux/regmap.h>
12af71cccaSOkan Sahin #include <linux/regulator/driver.h>
13af71cccaSOkan Sahin #include <linux/regulator/machine.h>
14af71cccaSOkan Sahin #include <linux/regulator/of_regulator.h>
15af71cccaSOkan Sahin #include <linux/util_macros.h>
16af71cccaSOkan Sahin 
17af71cccaSOkan Sahin #define MAX77857_REG_INT_SRC		0x10
18af71cccaSOkan Sahin #define MAX77857_REG_INT_MASK		0x11
19af71cccaSOkan Sahin #define MAX77857_REG_CONT1		0x12
20af71cccaSOkan Sahin #define MAX77857_REG_CONT2		0x13
21af71cccaSOkan Sahin #define MAX77857_REG_CONT3		0x14
22af71cccaSOkan Sahin 
23af71cccaSOkan Sahin #define MAX77857_INT_SRC_OCP		BIT(0)
24af71cccaSOkan Sahin #define MAX77857_INT_SRC_THS		BIT(1)
25af71cccaSOkan Sahin #define MAX77857_INT_SRC_HARDSHORT	BIT(2)
26af71cccaSOkan Sahin #define MAX77857_INT_SRC_OVP		BIT(3)
27af71cccaSOkan Sahin #define MAX77857_INT_SRC_POK		BIT(4)
28af71cccaSOkan Sahin 
29af71cccaSOkan Sahin #define MAX77857_ILIM_MASK		GENMASK(2, 0)
30af71cccaSOkan Sahin #define MAX77857_CONT1_FREQ		GENMASK(4, 3)
31af71cccaSOkan Sahin #define MAX77857_CONT3_FPWM		BIT(5)
32af71cccaSOkan Sahin 
33af71cccaSOkan Sahin #define MAX77859_REG_INT_SRC		0x11
34af71cccaSOkan Sahin #define MAX77859_REG_CONT1		0x13
35af71cccaSOkan Sahin #define MAX77859_REG_CONT2		0x14
36af71cccaSOkan Sahin #define MAX77859_REG_CONT3		0x15
37af71cccaSOkan Sahin #define MAX77859_REG_CONT5		0x17
38af71cccaSOkan Sahin #define MAX77859_CONT2_FPWM		BIT(2)
39af71cccaSOkan Sahin #define MAX77859_CONT2_INTB		BIT(3)
40af71cccaSOkan Sahin #define MAX77859_CONT3_DVS_START	BIT(2)
41af71cccaSOkan Sahin #define MAX77859_VOLTAGE_SEL_MASK	GENMASK(9, 0)
42af71cccaSOkan Sahin 
43af71cccaSOkan Sahin #define MAX77859_CURRENT_MIN		1000000
44af71cccaSOkan Sahin #define MAX77859_CURRENT_MAX		5000000
45af71cccaSOkan Sahin #define MAX77859_CURRENT_STEP		50000
46af71cccaSOkan Sahin 
47af71cccaSOkan Sahin enum max77857_id {
48af71cccaSOkan Sahin 	ID_MAX77831 = 1,
49af71cccaSOkan Sahin 	ID_MAX77857,
50af71cccaSOkan Sahin 	ID_MAX77859,
51af71cccaSOkan Sahin 	ID_MAX77859A,
52af71cccaSOkan Sahin };
53af71cccaSOkan Sahin 
max77857_volatile_reg(struct device * dev,unsigned int reg)54af71cccaSOkan Sahin static bool max77857_volatile_reg(struct device *dev, unsigned int reg)
55af71cccaSOkan Sahin {
56*b29f42c6SKrzysztof Kozlowski 	enum max77857_id id = (uintptr_t)dev_get_drvdata(dev);
57af71cccaSOkan Sahin 
58af71cccaSOkan Sahin 	switch (id) {
59af71cccaSOkan Sahin 	case ID_MAX77831:
60af71cccaSOkan Sahin 	case ID_MAX77857:
61af71cccaSOkan Sahin 		return reg == MAX77857_REG_INT_SRC;
62af71cccaSOkan Sahin 	case ID_MAX77859:
63af71cccaSOkan Sahin 	case ID_MAX77859A:
64af71cccaSOkan Sahin 		return reg == MAX77859_REG_INT_SRC;
65af71cccaSOkan Sahin 	default:
66af71cccaSOkan Sahin 		return true;
67af71cccaSOkan Sahin 	}
68af71cccaSOkan Sahin }
69af71cccaSOkan Sahin 
7039b5ba6cSYang Yingliang static struct regmap_config max77857_regmap_config = {
71af71cccaSOkan Sahin 	.reg_bits = 8,
72af71cccaSOkan Sahin 	.val_bits = 8,
73af71cccaSOkan Sahin 	.cache_type = REGCACHE_MAPLE,
74af71cccaSOkan Sahin 	.volatile_reg = max77857_volatile_reg,
75af71cccaSOkan Sahin };
76af71cccaSOkan Sahin 
max77857_get_status(struct regulator_dev * rdev)77af71cccaSOkan Sahin static int max77857_get_status(struct regulator_dev *rdev)
78af71cccaSOkan Sahin {
79af71cccaSOkan Sahin 	unsigned int val;
80af71cccaSOkan Sahin 	int ret;
81af71cccaSOkan Sahin 
82af71cccaSOkan Sahin 	ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
83af71cccaSOkan Sahin 	if (ret)
84af71cccaSOkan Sahin 		return ret;
85af71cccaSOkan Sahin 
86af71cccaSOkan Sahin 	if (FIELD_GET(MAX77857_INT_SRC_POK, val))
87af71cccaSOkan Sahin 		return REGULATOR_STATUS_ON;
88af71cccaSOkan Sahin 
89af71cccaSOkan Sahin 	return REGULATOR_STATUS_ERROR;
90af71cccaSOkan Sahin }
91af71cccaSOkan Sahin 
max77857_get_mode(struct regulator_dev * rdev)92af71cccaSOkan Sahin static unsigned int max77857_get_mode(struct regulator_dev *rdev)
93af71cccaSOkan Sahin {
94*b29f42c6SKrzysztof Kozlowski 	enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
95af71cccaSOkan Sahin 	unsigned int regval;
96af71cccaSOkan Sahin 	int ret;
97af71cccaSOkan Sahin 
98af71cccaSOkan Sahin 	switch (id) {
99af71cccaSOkan Sahin 	case ID_MAX77831:
100af71cccaSOkan Sahin 	case ID_MAX77857:
101af71cccaSOkan Sahin 		ret = regmap_read(rdev->regmap, MAX77857_REG_CONT3, &regval);
102af71cccaSOkan Sahin 		if (ret)
103af71cccaSOkan Sahin 			return ret;
104af71cccaSOkan Sahin 
105af71cccaSOkan Sahin 		if (FIELD_GET(MAX77857_CONT3_FPWM, regval))
106af71cccaSOkan Sahin 			return REGULATOR_MODE_FAST;
107af71cccaSOkan Sahin 
108af71cccaSOkan Sahin 		break;
109af71cccaSOkan Sahin 	case ID_MAX77859:
110af71cccaSOkan Sahin 	case ID_MAX77859A:
111af71cccaSOkan Sahin 		ret = regmap_read(rdev->regmap, MAX77859_REG_CONT2, &regval);
112af71cccaSOkan Sahin 		if (ret)
113af71cccaSOkan Sahin 			return ret;
114af71cccaSOkan Sahin 
115af71cccaSOkan Sahin 		if (FIELD_GET(MAX77859_CONT2_FPWM, regval))
116af71cccaSOkan Sahin 			return REGULATOR_MODE_FAST;
117af71cccaSOkan Sahin 
118af71cccaSOkan Sahin 		break;
119af71cccaSOkan Sahin 	default:
120af71cccaSOkan Sahin 		return -EINVAL;
121af71cccaSOkan Sahin 	}
122af71cccaSOkan Sahin 
123af71cccaSOkan Sahin 	return REGULATOR_MODE_NORMAL;
124af71cccaSOkan Sahin }
125af71cccaSOkan Sahin 
max77857_set_mode(struct regulator_dev * rdev,unsigned int mode)126af71cccaSOkan Sahin static int max77857_set_mode(struct regulator_dev *rdev, unsigned int mode)
127af71cccaSOkan Sahin {
128*b29f42c6SKrzysztof Kozlowski 	enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
129af71cccaSOkan Sahin 	unsigned int reg, val;
130af71cccaSOkan Sahin 
131af71cccaSOkan Sahin 	switch (id) {
132af71cccaSOkan Sahin 	case ID_MAX77831:
133af71cccaSOkan Sahin 	case ID_MAX77857:
134af71cccaSOkan Sahin 		reg = MAX77857_REG_CONT3;
135af71cccaSOkan Sahin 		val = MAX77857_CONT3_FPWM;
136af71cccaSOkan Sahin 		break;
137af71cccaSOkan Sahin 	case ID_MAX77859:
138af71cccaSOkan Sahin 	case ID_MAX77859A:
139af71cccaSOkan Sahin 		reg = MAX77859_REG_CONT2;
140af71cccaSOkan Sahin 		val = MAX77859_CONT2_FPWM;
141af71cccaSOkan Sahin 		break;
142af71cccaSOkan Sahin 	default:
143af71cccaSOkan Sahin 		return -EINVAL;
144af71cccaSOkan Sahin 	}
145af71cccaSOkan Sahin 
146af71cccaSOkan Sahin 	switch (mode) {
147af71cccaSOkan Sahin 	case REGULATOR_MODE_FAST:
148af71cccaSOkan Sahin 		return regmap_set_bits(rdev->regmap, reg, val);
149af71cccaSOkan Sahin 	case REGULATOR_MODE_NORMAL:
150af71cccaSOkan Sahin 		return regmap_clear_bits(rdev->regmap, reg, val);
151af71cccaSOkan Sahin 	default:
152af71cccaSOkan Sahin 		return -EINVAL;
153af71cccaSOkan Sahin 	}
154af71cccaSOkan Sahin }
155af71cccaSOkan Sahin 
max77857_get_error_flags(struct regulator_dev * rdev,unsigned int * flags)156af71cccaSOkan Sahin static int max77857_get_error_flags(struct regulator_dev *rdev,
157af71cccaSOkan Sahin 				    unsigned int *flags)
158af71cccaSOkan Sahin {
159af71cccaSOkan Sahin 	unsigned int val;
160af71cccaSOkan Sahin 	int ret;
161af71cccaSOkan Sahin 
162af71cccaSOkan Sahin 	ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
163af71cccaSOkan Sahin 	if (ret)
164af71cccaSOkan Sahin 		return ret;
165af71cccaSOkan Sahin 
166af71cccaSOkan Sahin 	*flags = 0;
167af71cccaSOkan Sahin 
168af71cccaSOkan Sahin 	if (FIELD_GET(MAX77857_INT_SRC_OVP, val))
169af71cccaSOkan Sahin 		*flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN;
170af71cccaSOkan Sahin 
171af71cccaSOkan Sahin 	if (FIELD_GET(MAX77857_INT_SRC_OCP, val) ||
172af71cccaSOkan Sahin 	    FIELD_GET(MAX77857_INT_SRC_HARDSHORT, val))
173af71cccaSOkan Sahin 		*flags |= REGULATOR_ERROR_OVER_CURRENT;
174af71cccaSOkan Sahin 
175af71cccaSOkan Sahin 	if (FIELD_GET(MAX77857_INT_SRC_THS, val))
176af71cccaSOkan Sahin 		*flags |= REGULATOR_ERROR_OVER_TEMP;
177af71cccaSOkan Sahin 
178af71cccaSOkan Sahin 	if (!FIELD_GET(MAX77857_INT_SRC_POK, val))
179af71cccaSOkan Sahin 		*flags |= REGULATOR_ERROR_FAIL;
180af71cccaSOkan Sahin 
181af71cccaSOkan Sahin 	return 0;
182af71cccaSOkan Sahin }
183af71cccaSOkan Sahin 
184af71cccaSOkan Sahin static struct linear_range max77859_lin_ranges[] = {
185af71cccaSOkan Sahin 	REGULATOR_LINEAR_RANGE(3200000, 0x0A0, 0x320, 20000)
186af71cccaSOkan Sahin };
187af71cccaSOkan Sahin 
188af71cccaSOkan Sahin static const unsigned int max77859_ramp_table[4] = {
189af71cccaSOkan Sahin 	1000, 500, 250, 125
190af71cccaSOkan Sahin };
191af71cccaSOkan Sahin 
max77859_set_voltage_sel(struct regulator_dev * rdev,unsigned int sel)192af71cccaSOkan Sahin static int max77859_set_voltage_sel(struct regulator_dev *rdev,
193af71cccaSOkan Sahin 				    unsigned int sel)
194af71cccaSOkan Sahin {
195af71cccaSOkan Sahin 	__be16 reg;
196af71cccaSOkan Sahin 	int ret;
197af71cccaSOkan Sahin 
198af71cccaSOkan Sahin 	reg = cpu_to_be16(sel);
199af71cccaSOkan Sahin 
200af71cccaSOkan Sahin 	ret = regmap_bulk_write(rdev->regmap, MAX77859_REG_CONT3, &reg, 2);
201af71cccaSOkan Sahin 	if (ret)
202af71cccaSOkan Sahin 		return ret;
203af71cccaSOkan Sahin 
204af71cccaSOkan Sahin 	/* actually apply new voltage */
205af71cccaSOkan Sahin 	return regmap_set_bits(rdev->regmap, MAX77859_REG_CONT3,
206af71cccaSOkan Sahin 			       MAX77859_CONT3_DVS_START);
207af71cccaSOkan Sahin }
208af71cccaSOkan Sahin 
max77859_get_voltage_sel(struct regulator_dev * rdev)209541e7595SArnd Bergmann static int max77859_get_voltage_sel(struct regulator_dev *rdev)
210af71cccaSOkan Sahin {
211af71cccaSOkan Sahin 	__be16 reg;
212af71cccaSOkan Sahin 	int ret;
213af71cccaSOkan Sahin 
214af71cccaSOkan Sahin 	ret = regmap_bulk_read(rdev->regmap, MAX77859_REG_CONT3, &reg, 2);
215af71cccaSOkan Sahin 	if (ret)
216af71cccaSOkan Sahin 		return ret;
217af71cccaSOkan Sahin 
218af71cccaSOkan Sahin 	return FIELD_GET(MAX77859_VOLTAGE_SEL_MASK, __be16_to_cpu(reg));
219af71cccaSOkan Sahin }
220af71cccaSOkan Sahin 
max77859_set_current_limit(struct regulator_dev * rdev,int min_uA,int max_uA)221541e7595SArnd Bergmann static int max77859_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
222af71cccaSOkan Sahin {
223af71cccaSOkan Sahin 	u32 selector;
224af71cccaSOkan Sahin 
225af71cccaSOkan Sahin 	if (max_uA < MAX77859_CURRENT_MIN)
226af71cccaSOkan Sahin 		return -EINVAL;
227af71cccaSOkan Sahin 
228af71cccaSOkan Sahin 	selector = 0x12 + (max_uA - MAX77859_CURRENT_MIN) / MAX77859_CURRENT_STEP;
229af71cccaSOkan Sahin 
230af71cccaSOkan Sahin 	selector = clamp_val(selector, 0x00, 0x7F);
231af71cccaSOkan Sahin 
232af71cccaSOkan Sahin 	return regmap_write(rdev->regmap, MAX77859_REG_CONT5, selector);
233af71cccaSOkan Sahin }
234af71cccaSOkan Sahin 
max77859_get_current_limit(struct regulator_dev * rdev)235541e7595SArnd Bergmann static int max77859_get_current_limit(struct regulator_dev *rdev)
236af71cccaSOkan Sahin {
237af71cccaSOkan Sahin 	u32 selector;
238af71cccaSOkan Sahin 	int ret;
239af71cccaSOkan Sahin 
240af71cccaSOkan Sahin 	ret = regmap_read(rdev->regmap, MAX77859_REG_CONT5, &selector);
241af71cccaSOkan Sahin 	if (ret)
242af71cccaSOkan Sahin 		return ret;
243af71cccaSOkan Sahin 
244af71cccaSOkan Sahin 	if (selector <= 0x12)
245af71cccaSOkan Sahin 		return MAX77859_CURRENT_MIN;
246af71cccaSOkan Sahin 
247af71cccaSOkan Sahin 	if (selector >= 0x64)
248af71cccaSOkan Sahin 		return MAX77859_CURRENT_MAX;
249af71cccaSOkan Sahin 
250af71cccaSOkan Sahin 	return MAX77859_CURRENT_MIN + (selector - 0x12) * MAX77859_CURRENT_STEP;
251af71cccaSOkan Sahin }
252af71cccaSOkan Sahin 
253af71cccaSOkan Sahin static const struct regulator_ops max77859_regulator_ops = {
254af71cccaSOkan Sahin 	.list_voltage = regulator_list_voltage_linear_range,
255af71cccaSOkan Sahin 	.set_voltage_sel = max77859_set_voltage_sel,
256af71cccaSOkan Sahin 	.get_voltage_sel = max77859_get_voltage_sel,
257af71cccaSOkan Sahin 	.set_ramp_delay = regulator_set_ramp_delay_regmap,
258af71cccaSOkan Sahin 	.get_status = max77857_get_status,
259af71cccaSOkan Sahin 	.set_mode = max77857_set_mode,
260af71cccaSOkan Sahin 	.get_mode = max77857_get_mode,
261af71cccaSOkan Sahin 	.get_error_flags = max77857_get_error_flags,
262af71cccaSOkan Sahin };
263af71cccaSOkan Sahin 
264af71cccaSOkan Sahin static const struct regulator_ops max77859a_regulator_ops = {
265af71cccaSOkan Sahin 	.list_voltage = regulator_list_voltage_linear_range,
266af71cccaSOkan Sahin 	.set_voltage_sel = max77859_set_voltage_sel,
267af71cccaSOkan Sahin 	.get_voltage_sel = max77859_get_voltage_sel,
268af71cccaSOkan Sahin 	.set_current_limit = max77859_set_current_limit,
269af71cccaSOkan Sahin 	.get_current_limit = max77859_get_current_limit,
270af71cccaSOkan Sahin 	.set_ramp_delay = regulator_set_ramp_delay_regmap,
271af71cccaSOkan Sahin 	.get_status = max77857_get_status,
272af71cccaSOkan Sahin 	.set_mode = max77857_set_mode,
273af71cccaSOkan Sahin 	.get_mode = max77857_get_mode,
274af71cccaSOkan Sahin 	.get_error_flags = max77857_get_error_flags,
275af71cccaSOkan Sahin };
276af71cccaSOkan Sahin 
277af71cccaSOkan Sahin static const struct regulator_ops max77857_regulator_ops = {
278af71cccaSOkan Sahin 	.list_voltage = regulator_list_voltage_linear_range,
279af71cccaSOkan Sahin 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
280af71cccaSOkan Sahin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
281af71cccaSOkan Sahin 	.set_ramp_delay = regulator_set_ramp_delay_regmap,
282af71cccaSOkan Sahin 	.get_status = max77857_get_status,
283af71cccaSOkan Sahin 	.set_mode = max77857_set_mode,
284af71cccaSOkan Sahin 	.get_mode = max77857_get_mode,
285af71cccaSOkan Sahin 	.get_error_flags = max77857_get_error_flags,
286af71cccaSOkan Sahin };
287af71cccaSOkan Sahin 
288af71cccaSOkan Sahin static struct linear_range max77857_lin_ranges[] = {
289af71cccaSOkan Sahin 	REGULATOR_LINEAR_RANGE(4485000, 0x3D, 0xCC, 73500)
290af71cccaSOkan Sahin };
291af71cccaSOkan Sahin 
292af71cccaSOkan Sahin static const unsigned int max77857_switch_freq[] = {
293af71cccaSOkan Sahin 	1200000, 1500000, 1800000, 2100000
294af71cccaSOkan Sahin };
295af71cccaSOkan Sahin 
29693083725SYang Yingliang #define RAMAP_DELAY_INIT_VAL 1333
29793083725SYang Yingliang 
298af71cccaSOkan Sahin static const unsigned int max77857_ramp_table[2][4] = {
29993083725SYang Yingliang 	{ RAMAP_DELAY_INIT_VAL, 667, 333, 227 }, /* when switch freq is 1.8MHz or 2.1MHz */
300af71cccaSOkan Sahin 	{ 1166, 667, 333, 167 }, /* when switch freq is 1.2MHz or 1.5MHz */
301af71cccaSOkan Sahin };
302af71cccaSOkan Sahin 
303af71cccaSOkan Sahin static struct regulator_desc max77857_regulator_desc = {
304af71cccaSOkan Sahin 	.ops = &max77857_regulator_ops,
305af71cccaSOkan Sahin 	.name = "max77857",
306af71cccaSOkan Sahin 	.linear_ranges = max77857_lin_ranges,
307af71cccaSOkan Sahin 	.n_linear_ranges = ARRAY_SIZE(max77857_lin_ranges),
308af71cccaSOkan Sahin 	.vsel_mask = 0xFF,
309af71cccaSOkan Sahin 	.vsel_reg = MAX77857_REG_CONT2,
310af71cccaSOkan Sahin 	.ramp_delay_table = max77857_ramp_table[0],
311af71cccaSOkan Sahin 	.n_ramp_values = ARRAY_SIZE(max77857_ramp_table[0]),
312af71cccaSOkan Sahin 	.ramp_reg = MAX77857_REG_CONT3,
313af71cccaSOkan Sahin 	.ramp_mask = GENMASK(1, 0),
31493083725SYang Yingliang 	.ramp_delay = RAMAP_DELAY_INIT_VAL,
315af71cccaSOkan Sahin 	.owner = THIS_MODULE,
316af71cccaSOkan Sahin };
317af71cccaSOkan Sahin 
max77857_calc_range(struct device * dev,enum max77857_id id)318af71cccaSOkan Sahin static void max77857_calc_range(struct device *dev, enum max77857_id id)
319af71cccaSOkan Sahin {
320af71cccaSOkan Sahin 	struct linear_range *range;
321af71cccaSOkan Sahin 	unsigned long vref_step;
322af71cccaSOkan Sahin 	u32 rtop = 0;
323af71cccaSOkan Sahin 	u32 rbot = 0;
324af71cccaSOkan Sahin 
325af71cccaSOkan Sahin 	device_property_read_u32(dev, "adi,rtop-ohms", &rtop);
326af71cccaSOkan Sahin 	device_property_read_u32(dev, "adi,rbot-ohms", &rbot);
327af71cccaSOkan Sahin 
328af71cccaSOkan Sahin 	if (!rbot || !rtop)
329af71cccaSOkan Sahin 		return;
330af71cccaSOkan Sahin 
331af71cccaSOkan Sahin 	switch (id) {
332af71cccaSOkan Sahin 	case ID_MAX77831:
333af71cccaSOkan Sahin 	case ID_MAX77857:
334af71cccaSOkan Sahin 		range = max77857_lin_ranges;
335af71cccaSOkan Sahin 		vref_step = 4900UL;
336af71cccaSOkan Sahin 		break;
337af71cccaSOkan Sahin 	case ID_MAX77859:
338af71cccaSOkan Sahin 	case ID_MAX77859A:
339af71cccaSOkan Sahin 		range = max77859_lin_ranges;
340af71cccaSOkan Sahin 		vref_step = 1250UL;
341af71cccaSOkan Sahin 		break;
342af71cccaSOkan Sahin 	}
343af71cccaSOkan Sahin 
344af71cccaSOkan Sahin 	range->step = DIV_ROUND_CLOSEST(vref_step * (rbot + rtop), rbot);
345af71cccaSOkan Sahin 	range->min = range->step * range->min_sel;
346af71cccaSOkan Sahin }
347af71cccaSOkan Sahin 
max77857_probe(struct i2c_client * client)348af71cccaSOkan Sahin static int max77857_probe(struct i2c_client *client)
349af71cccaSOkan Sahin {
350af71cccaSOkan Sahin 	const struct i2c_device_id *i2c_id;
351af71cccaSOkan Sahin 	struct device *dev = &client->dev;
352af71cccaSOkan Sahin 	struct regulator_config cfg = { };
353af71cccaSOkan Sahin 	struct regulator_dev *rdev;
354af71cccaSOkan Sahin 	struct regmap *regmap;
355af71cccaSOkan Sahin 	enum max77857_id id;
356af71cccaSOkan Sahin 	u32 switch_freq = 0;
357af71cccaSOkan Sahin 	int ret;
358af71cccaSOkan Sahin 
359af71cccaSOkan Sahin 	i2c_id = i2c_client_get_device_id(client);
360af71cccaSOkan Sahin 	if (!i2c_id)
361af71cccaSOkan Sahin 		return -EINVAL;
362af71cccaSOkan Sahin 
363af71cccaSOkan Sahin 	id = i2c_id->driver_data;
364af71cccaSOkan Sahin 
365af71cccaSOkan Sahin 	dev_set_drvdata(dev, (void *)id);
366af71cccaSOkan Sahin 
367af71cccaSOkan Sahin 	if (id == ID_MAX77859 || id == ID_MAX77859A) {
368af71cccaSOkan Sahin 		max77857_regulator_desc.ops = &max77859_regulator_ops;
369af71cccaSOkan Sahin 		max77857_regulator_desc.linear_ranges = max77859_lin_ranges;
370af71cccaSOkan Sahin 		max77857_regulator_desc.ramp_delay_table = max77859_ramp_table;
371af71cccaSOkan Sahin 		max77857_regulator_desc.ramp_delay = max77859_ramp_table[0];
372af71cccaSOkan Sahin 	}
373af71cccaSOkan Sahin 
374af71cccaSOkan Sahin 	if (id == ID_MAX77859A)
375af71cccaSOkan Sahin 		max77857_regulator_desc.ops = &max77859a_regulator_ops;
376af71cccaSOkan Sahin 
377af71cccaSOkan Sahin 	max77857_calc_range(dev, id);
378af71cccaSOkan Sahin 
379af71cccaSOkan Sahin 	regmap = devm_regmap_init_i2c(client, &max77857_regmap_config);
380af71cccaSOkan Sahin 	if (IS_ERR(regmap))
381af71cccaSOkan Sahin 		return dev_err_probe(dev, PTR_ERR(regmap),
382af71cccaSOkan Sahin 				     "cannot initialize regmap\n");
383af71cccaSOkan Sahin 
384af71cccaSOkan Sahin 	device_property_read_u32(dev, "adi,switch-frequency-hz", &switch_freq);
385af71cccaSOkan Sahin 	if (switch_freq) {
386af71cccaSOkan Sahin 		switch_freq = find_closest(switch_freq, max77857_switch_freq,
387af71cccaSOkan Sahin 					   ARRAY_SIZE(max77857_switch_freq));
388af71cccaSOkan Sahin 
389af71cccaSOkan Sahin 		if (id == ID_MAX77831 && switch_freq == 3)
390af71cccaSOkan Sahin 			switch_freq = 2;
391af71cccaSOkan Sahin 
392af71cccaSOkan Sahin 		switch (id) {
393af71cccaSOkan Sahin 		case ID_MAX77831:
394af71cccaSOkan Sahin 		case ID_MAX77857:
395af71cccaSOkan Sahin 			ret = regmap_update_bits(regmap, MAX77857_REG_CONT1,
396af71cccaSOkan Sahin 						 MAX77857_CONT1_FREQ, switch_freq);
397af71cccaSOkan Sahin 
398af71cccaSOkan Sahin 			if (switch_freq >= 2)
399af71cccaSOkan Sahin 				break;
400af71cccaSOkan Sahin 
401af71cccaSOkan Sahin 			max77857_regulator_desc.ramp_delay_table = max77857_ramp_table[1];
402af71cccaSOkan Sahin 			max77857_regulator_desc.ramp_delay = max77857_ramp_table[1][0];
403af71cccaSOkan Sahin 			break;
404af71cccaSOkan Sahin 		case ID_MAX77859:
405af71cccaSOkan Sahin 		case ID_MAX77859A:
406af71cccaSOkan Sahin 			ret = regmap_update_bits(regmap, MAX77859_REG_CONT1,
407af71cccaSOkan Sahin 						 MAX77857_CONT1_FREQ, switch_freq);
408af71cccaSOkan Sahin 			break;
409af71cccaSOkan Sahin 		}
410af71cccaSOkan Sahin 		if (ret)
411af71cccaSOkan Sahin 			return ret;
412af71cccaSOkan Sahin 	}
413af71cccaSOkan Sahin 
414af71cccaSOkan Sahin 	cfg.dev = dev;
415af71cccaSOkan Sahin 	cfg.driver_data = (void *)id;
416af71cccaSOkan Sahin 	cfg.regmap = regmap;
417af71cccaSOkan Sahin 	cfg.init_data = of_get_regulator_init_data(dev, dev->of_node,
418af71cccaSOkan Sahin 						   &max77857_regulator_desc);
419af71cccaSOkan Sahin 	if (!cfg.init_data)
420af71cccaSOkan Sahin 		return -ENOMEM;
421af71cccaSOkan Sahin 
422af71cccaSOkan Sahin 	rdev = devm_regulator_register(dev, &max77857_regulator_desc, &cfg);
423af71cccaSOkan Sahin 	if (IS_ERR(rdev))
424af71cccaSOkan Sahin 		return dev_err_probe(dev, PTR_ERR(rdev),
425af71cccaSOkan Sahin 				     "cannot register regulator\n");
426af71cccaSOkan Sahin 
427af71cccaSOkan Sahin 	return 0;
428af71cccaSOkan Sahin }
429af71cccaSOkan Sahin 
430af71cccaSOkan Sahin const struct i2c_device_id max77857_id[] = {
431af71cccaSOkan Sahin 	{ "max77831", ID_MAX77831 },
432af71cccaSOkan Sahin 	{ "max77857", ID_MAX77857 },
433af71cccaSOkan Sahin 	{ "max77859", ID_MAX77859 },
434af71cccaSOkan Sahin 	{ "max77859a", ID_MAX77859A },
435af71cccaSOkan Sahin 	{ }
436af71cccaSOkan Sahin };
437af71cccaSOkan Sahin MODULE_DEVICE_TABLE(i2c, max77857_id);
438af71cccaSOkan Sahin 
439af71cccaSOkan Sahin static const struct of_device_id max77857_of_id[] = {
440af71cccaSOkan Sahin 	{ .compatible = "adi,max77831", .data = (void *)ID_MAX77831 },
441af71cccaSOkan Sahin 	{ .compatible = "adi,max77857", .data = (void *)ID_MAX77857 },
442af71cccaSOkan Sahin 	{ .compatible = "adi,max77859", .data = (void *)ID_MAX77859 },
443af71cccaSOkan Sahin 	{ .compatible = "adi,max77859a", .data = (void *)ID_MAX77859A },
444af71cccaSOkan Sahin 	{ }
445af71cccaSOkan Sahin };
446af71cccaSOkan Sahin MODULE_DEVICE_TABLE(of, max77857_of_id);
447af71cccaSOkan Sahin 
44839b5ba6cSYang Yingliang static struct i2c_driver max77857_driver = {
449af71cccaSOkan Sahin 	.driver = {
450af71cccaSOkan Sahin 		.name = "max77857",
451af71cccaSOkan Sahin 		.of_match_table = max77857_of_id,
452af71cccaSOkan Sahin 	},
453af71cccaSOkan Sahin 	.id_table = max77857_id,
4542920e08bSUwe Kleine-König 	.probe = max77857_probe,
455af71cccaSOkan Sahin };
456af71cccaSOkan Sahin module_i2c_driver(max77857_driver);
457af71cccaSOkan Sahin 
458af71cccaSOkan Sahin MODULE_DESCRIPTION("Analog Devices MAX77857 Buck-Boost Converter Driver");
459af71cccaSOkan Sahin MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
460af71cccaSOkan Sahin MODULE_AUTHOR("Okan Sahin <Okan.Sahin@analog.com>");
461af71cccaSOkan Sahin MODULE_LICENSE("GPL");
462