1f18792714608a670c2762d22f695d77d02fc965eSachin Kamat/*
2f18792714608a670c2762d22f695d77d02fc965eSachin Kamat * Copyright (c) 2013 Samsung Electronics Co., Ltd
3f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *		http://www.samsung.com
4f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *
5f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *  This program is free software; you can redistribute  it and/or modify it
6f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *  under  the terms of  the GNU General  Public License as published by the
7f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *  Free Software Foundation;  either version 2 of the  License, or (at your
8f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *  option) any later version.
9f18792714608a670c2762d22f695d77d02fc965eSachin Kamat *
10f18792714608a670c2762d22f695d77d02fc965eSachin Kamat */
11f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
12f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/bug.h>
13f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/err.h>
14f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/gpio.h>
15f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/slab.h>
16f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/module.h>
17f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/of.h>
18f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/regmap.h>
19f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/platform_device.h>
20f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/regulator/driver.h>
21f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/regulator/machine.h>
22f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/regulator/of_regulator.h>
23f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/mfd/samsung/core.h>
24f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#include <linux/mfd/samsung/s2mpa01.h>
25f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
26f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
27f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
28f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstruct s2mpa01_info {
29f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay24;
30f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay3;
31f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay5;
32f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay16;
33f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay7;
34f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ramp_delay8910;
35f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
36f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
37f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic int get_ramp_delay(int ramp_delay)
38f18792714608a670c2762d22f695d77d02fc965eSachin Kamat{
39f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	unsigned char cnt = 0;
40f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
41f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	ramp_delay /= 6250;
42f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
43f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	while (true) {
44f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = ramp_delay >> 1;
45f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay == 0)
46f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			break;
47f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		cnt++;
48f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
49f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
50f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	if (cnt > 3)
51f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		cnt = 3;
52f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
53f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	return cnt;
54f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
55f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
56f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
57f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				   unsigned int old_selector,
58f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				   unsigned int new_selector)
59f18792714608a670c2762d22f695d77d02fc965eSachin Kamat{
60f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
61f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	unsigned int ramp_delay = 0;
62f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int old_volt, new_volt;
63f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
640608032a9067c165e5ed75c56311a08cbb28564fKrzysztof Kozlowski	switch (rdev_get_id(rdev)) {
65f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK2:
66f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK4:
67f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay24;
68f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
69f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK3:
70f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay3;
71f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
72f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK5:
73f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay5;
74f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
75f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK1:
76f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK6:
77f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay16;
78f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
79f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK7:
80f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay7;
81f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
82f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK8:
83f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK9:
84f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK10:
85f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = s2mpa01->ramp_delay8910;
86f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
87f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
88f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
89f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	if (ramp_delay == 0)
90f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_delay = rdev->desc->ramp_delay;
91f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
92f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
93f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
94f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
95f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
96f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
97f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
98f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
99f18792714608a670c2762d22f695d77d02fc965eSachin Kamat{
100f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
101f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;
102f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	unsigned int ramp_enable = 1, enable_shift = 0;
103f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int ret;
104f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
1050608032a9067c165e5ed75c56311a08cbb28564fKrzysztof Kozlowski	switch (rdev_get_id(rdev)) {
106f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK1:
107f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
108f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (!ramp_delay) {
109f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_enable = 0;
110f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			break;
111f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		}
112f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
113f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay > s2mpa01->ramp_delay16)
114f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			s2mpa01->ramp_delay16 = ramp_delay;
115f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
116f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_delay = s2mpa01->ramp_delay16;
117f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
118f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
119f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
120f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK2:
121f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
122f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (!ramp_delay) {
123f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_enable = 0;
124f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			break;
125f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		}
126f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
127f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay > s2mpa01->ramp_delay24)
128f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			s2mpa01->ramp_delay24 = ramp_delay;
129f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
130f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_delay = s2mpa01->ramp_delay24;
131f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
132f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
133f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_reg = S2MPA01_REG_RAMP1;
134f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
135f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK3:
136f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;
137f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (!ramp_delay) {
138f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_enable = 0;
139f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			break;
140f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		}
141f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
142f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		s2mpa01->ramp_delay3 = ramp_delay;
143f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;
144f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_reg = S2MPA01_REG_RAMP1;
145f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
146f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK4:
147f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;
148f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (!ramp_delay) {
149f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_enable = 0;
150f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			break;
151f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		}
152f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
153f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay > s2mpa01->ramp_delay24)
154f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			s2mpa01->ramp_delay24 = ramp_delay;
155f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
156f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_delay = s2mpa01->ramp_delay24;
157f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
158f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
159f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_reg = S2MPA01_REG_RAMP1;
160f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
161f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK5:
162f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		s2mpa01->ramp_delay5 = ramp_delay;
163f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;
164f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
165f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK6:
166f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay > s2mpa01->ramp_delay16)
167f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			s2mpa01->ramp_delay16 = ramp_delay;
168f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
169f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_delay = s2mpa01->ramp_delay16;
170f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
171f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
172f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
173f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK7:
174f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		s2mpa01->ramp_delay7 = ramp_delay;
175f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;
176f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
177f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK8:
178f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK9:
179f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	case S2MPA01_BUCK10:
180f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (ramp_delay > s2mpa01->ramp_delay8910)
181f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			s2mpa01->ramp_delay8910 = ramp_delay;
182f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
183f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			ramp_delay = s2mpa01->ramp_delay8910;
184f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
185f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;
186f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		break;
187f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	default:
188f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		return 0;
189f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
190f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
191f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	if (!ramp_enable)
192f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		goto ramp_disable;
193f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
19451e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski	/* Ramp delay can be enabled/disabled only for buck[1234] */
19551e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski	if (rdev_get_id(rdev) >= S2MPA01_BUCK1 &&
19651e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski			rdev_get_id(rdev) <= S2MPA01_BUCK4) {
19751e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski		ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
19851e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski					 1 << enable_shift, 1 << enable_shift);
19951e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski		if (ret) {
20051e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski			dev_err(&rdev->dev, "failed to enable ramp rate\n");
20151e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski			return ret;
20251e2fc0a251ba64c68207e4c6f6ac33c891b2465Krzysztof Kozlowski		}
203f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
204f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
205f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	ramp_val = get_ramp_delay(ramp_delay);
206f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
207f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
208f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				  ramp_val << ramp_shift);
209f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
210f18792714608a670c2762d22f695d77d02fc965eSachin Kamatramp_disable:
211f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
212f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				  1 << enable_shift, 0);
213f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
214f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
215f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic struct regulator_ops s2mpa01_ldo_ops = {
216f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.list_voltage		= regulator_list_voltage_linear,
217f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.map_voltage		= regulator_map_voltage_linear,
218f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.is_enabled		= regulator_is_enabled_regmap,
219f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable			= regulator_enable_regmap,
220f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.disable		= regulator_disable_regmap,
221f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
222f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
223f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
224f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
225f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
226f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic struct regulator_ops s2mpa01_buck_ops = {
227f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.list_voltage		= regulator_list_voltage_linear,
228f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.map_voltage		= regulator_map_voltage_linear,
229f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.is_enabled		= regulator_is_enabled_regmap,
230f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable			= regulator_enable_regmap,
231f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.disable		= regulator_disable_regmap,
232f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
233f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
234f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.set_voltage_time_sel	= s2mpa01_regulator_set_voltage_time_sel,
235f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.set_ramp_delay		= s2mpa01_set_ramp_delay,
236f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
237f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
238d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap#define regulator_desc_ldo(num, step) {			\
239f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.name		= "LDO"#num,			\
240f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.id		= S2MPA01_LDO##num,		\
241f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ops		= &s2mpa01_ldo_ops,		\
242f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.type		= REGULATOR_VOLTAGE,		\
243f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.owner		= THIS_MODULE,			\
2440e4f417857083f399769491f6e7773d111debd0fAmit Daniel Kachhap	.min_uV		= MIN_800_MV,			\
245d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	.uV_step	= step,				\
246f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.n_voltages	= S2MPA01_LDO_N_VOLTAGES,	\
247f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
248f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_mask	= S2MPA01_LDO_VSEL_MASK,	\
249f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
250f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_mask	= S2MPA01_ENABLE_MASK		\
251f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
252f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
253f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#define regulator_desc_buck1_4(num)	{			\
254f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.name		= "BUCK"#num,				\
255f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.id		= S2MPA01_BUCK##num,			\
256f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ops		= &s2mpa01_buck_ops,			\
257f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.type		= REGULATOR_VOLTAGE,			\
258f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.owner		= THIS_MODULE,				\
2590e4f417857083f399769491f6e7773d111debd0fAmit Daniel Kachhap	.min_uV		= MIN_600_MV,				\
2600e4f417857083f399769491f6e7773d111debd0fAmit Daniel Kachhap	.uV_step	= STEP_6_25_MV,				\
261f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
262f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
263f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_reg	= S2MPA01_REG_B1CTRL2 + (num - 1) * 2,	\
264f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
265f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_reg	= S2MPA01_REG_B1CTRL1 + (num - 1) * 2,	\
266f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_mask	= S2MPA01_ENABLE_MASK			\
267f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
268f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
269f18792714608a670c2762d22f695d77d02fc965eSachin Kamat#define regulator_desc_buck5	{				\
270f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.name		= "BUCK5",				\
271f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.id		= S2MPA01_BUCK5,			\
272f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ops		= &s2mpa01_buck_ops,			\
273f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.type		= REGULATOR_VOLTAGE,			\
274f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.owner		= THIS_MODULE,				\
2750e4f417857083f399769491f6e7773d111debd0fAmit Daniel Kachhap	.min_uV		= MIN_800_MV,				\
2760e4f417857083f399769491f6e7773d111debd0fAmit Daniel Kachhap	.uV_step	= STEP_6_25_MV,				\
277f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
278f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
279f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_reg	= S2MPA01_REG_B5CTRL2,			\
280f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
281f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_reg	= S2MPA01_REG_B5CTRL1,			\
282f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_mask	= S2MPA01_ENABLE_MASK			\
283f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
284f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
285d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap#define regulator_desc_buck6_10(num, min, step) {			\
286f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.name		= "BUCK"#num,				\
287f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.id		= S2MPA01_BUCK##num,			\
288f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ops		= &s2mpa01_buck_ops,			\
289f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.type		= REGULATOR_VOLTAGE,			\
290f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.owner		= THIS_MODULE,				\
291d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	.min_uV		= min,					\
292d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	.uV_step	= step,					\
293f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
294f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
295f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_reg	= S2MPA01_REG_B6CTRL2 + (num - 6) * 2,	\
296f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
297f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_reg	= S2MPA01_REG_B6CTRL1 + (num - 6) * 2,	\
298f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.enable_mask	= S2MPA01_ENABLE_MASK			\
299f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
300f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
301f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic struct regulator_desc regulators[] = {
302d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(1, STEP_25_MV),
303d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(2, STEP_50_MV),
304d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(3, STEP_50_MV),
305d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(4, STEP_50_MV),
306d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(5, STEP_50_MV),
307d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(6, STEP_25_MV),
308d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(7, STEP_50_MV),
309d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(8, STEP_50_MV),
310d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(9, STEP_50_MV),
311d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(10, STEP_50_MV),
312d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(11, STEP_25_MV),
313d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(12, STEP_50_MV),
314d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(13, STEP_50_MV),
315d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(14, STEP_50_MV),
316d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(15, STEP_50_MV),
317d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(16, STEP_50_MV),
318d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(17, STEP_50_MV),
319d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(18, STEP_50_MV),
320d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(19, STEP_50_MV),
321d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(20, STEP_50_MV),
322d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(21, STEP_50_MV),
323d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(22, STEP_25_MV),
324d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(23, STEP_25_MV),
325d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(24, STEP_50_MV),
326d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(25, STEP_50_MV),
327d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_ldo(26, STEP_50_MV),
328f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	regulator_desc_buck1_4(1),
329f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	regulator_desc_buck1_4(2),
330f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	regulator_desc_buck1_4(3),
331f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	regulator_desc_buck1_4(4),
332f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	regulator_desc_buck5,
333d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_buck6_10(6, MIN_600_MV, STEP_6_25_MV),
334d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_buck6_10(7, MIN_600_MV, STEP_6_25_MV),
335d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_buck6_10(8, MIN_800_MV, STEP_12_5_MV),
336d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_buck6_10(9, MIN_1500_MV, STEP_12_5_MV),
337d264fd4541753bf3fe2613805b3cab95b54a3f32Amit Daniel Kachhap	regulator_desc_buck6_10(10, MIN_1000_MV, STEP_12_5_MV),
338f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
339f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
340f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic int s2mpa01_pmic_probe(struct platform_device *pdev)
341f18792714608a670c2762d22f695d77d02fc965eSachin Kamat{
342f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
343f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
344282179105d5403d991d2510ec74d1031695b3ef0Javier Martinez Canillas	struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX] = { };
345f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct device_node *reg_np = NULL;
346f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct regulator_config config = { };
347f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	struct s2mpa01_info *s2mpa01;
348f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	int i;
349f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
350f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);
351f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	if (!s2mpa01)
352f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		return -ENOMEM;
353f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
354f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
355f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		rdata[i].name = regulators[i].name;
356f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
357f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	if (iodev->dev->of_node) {
358f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		reg_np = of_get_child_by_name(iodev->dev->of_node,
359f18792714608a670c2762d22f695d77d02fc965eSachin Kamat							"regulators");
360f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			if (!reg_np) {
361f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				dev_err(&pdev->dev,
362f18792714608a670c2762d22f695d77d02fc965eSachin Kamat					"could not find regulators sub-node\n");
363f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				return -EINVAL;
364f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			}
365f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
366f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		of_regulator_match(&pdev->dev, reg_np, rdata,
367f18792714608a670c2762d22f695d77d02fc965eSachin Kamat						S2MPA01_REGULATOR_MAX);
368f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		of_node_put(reg_np);
369f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
370f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
371f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	platform_set_drvdata(pdev, s2mpa01);
372f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
373f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	config.dev = &pdev->dev;
374f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	config.regmap = iodev->regmap_pmic;
375f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	config.driver_data = s2mpa01;
376f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
377f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
378f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		struct regulator_dev *rdev;
379f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (pdata)
380f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			config.init_data = pdata->regulators[i].initdata;
381f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		else
382f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			config.init_data = rdata[i].init_data;
383f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
384f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (reg_np)
385f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			config.of_node = rdata[i].of_node;
386f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
387f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		rdev = devm_regulator_register(&pdev->dev,
388f18792714608a670c2762d22f695d77d02fc965eSachin Kamat						&regulators[i], &config);
389f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		if (IS_ERR(rdev)) {
390f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			dev_err(&pdev->dev, "regulator init failed for %d\n",
391f18792714608a670c2762d22f695d77d02fc965eSachin Kamat				i);
392f18792714608a670c2762d22f695d77d02fc965eSachin Kamat			return PTR_ERR(rdev);
393f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		}
394f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	}
395f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
396f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	return 0;
397f18792714608a670c2762d22f695d77d02fc965eSachin Kamat}
398f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
399f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic const struct platform_device_id s2mpa01_pmic_id[] = {
400f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	{ "s2mpa01-pmic", 0},
401f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	{ },
402f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
403f18792714608a670c2762d22f695d77d02fc965eSachin KamatMODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);
404f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
405f18792714608a670c2762d22f695d77d02fc965eSachin Kamatstatic struct platform_driver s2mpa01_pmic_driver = {
406f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.driver = {
407f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		.name = "s2mpa01-pmic",
408f18792714608a670c2762d22f695d77d02fc965eSachin Kamat		.owner = THIS_MODULE,
409f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	},
410f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.probe = s2mpa01_pmic_probe,
411f18792714608a670c2762d22f695d77d02fc965eSachin Kamat	.id_table = s2mpa01_pmic_id,
412f18792714608a670c2762d22f695d77d02fc965eSachin Kamat};
413f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
414f18792714608a670c2762d22f695d77d02fc965eSachin Kamatmodule_platform_driver(s2mpa01_pmic_driver);
415f18792714608a670c2762d22f695d77d02fc965eSachin Kamat
416f18792714608a670c2762d22f695d77d02fc965eSachin Kamat/* Module information */
417f18792714608a670c2762d22f695d77d02fc965eSachin KamatMODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
418f18792714608a670c2762d22f695d77d02fc965eSachin KamatMODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");
419f18792714608a670c2762d22f695d77d02fc965eSachin KamatMODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver");
420f18792714608a670c2762d22f695d77d02fc965eSachin KamatMODULE_LICENSE("GPL");
421