summaryrefslogtreecommitdiffstats
path: root/drivers/regulator/max20411-regulator.c
blob: 83dacb4ff1736c1cd770c4e3b8db5723c825399d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
 * Copyright (c) 2022, Linaro Ltd.
 */

#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>

#define MAX20411_UV_STEP		6250
#define MAX20411_BASE_UV		243750
#define MAX20411_MIN_SEL		41 /* 0.5V */
#define MAX20411_MAX_SEL		165 /* 1.275V */
#define MAX20411_VID_OFFSET		0x7
#define MAX20411_VID_MASK		0xff
#define MAX20411_SLEW_OFFSET		0x6
#define MAX20411_SLEW_DVS_MASK		0xc
#define MAX20411_SLEW_SR_MASK		0x3

struct max20411 {
	struct device *dev;
	struct device_node *of_node;
	struct regulator_desc desc;
	struct regulator_dev *rdev;
	struct regmap *regmap;
};

static const unsigned int max20411_slew_rates[] = { 13100, 6600, 3300, 1600 };

static int max20411_enable_time(struct regulator_dev *rdev)
{
	int voltage, rate, ret;
	unsigned int val;

	/* get voltage */
	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
	if (ret)
		return ret;

	val &= rdev->desc->vsel_mask;
	voltage = regulator_list_voltage_linear(rdev, val);

	/* get rate */
	ret = regmap_read(rdev->regmap, MAX20411_SLEW_OFFSET, &val);
	if (ret)
		return ret;

	val = FIELD_GET(MAX20411_SLEW_SR_MASK, val);
	rate = max20411_slew_rates[val];

	return DIV_ROUND_UP(voltage, rate);
}

static const struct regmap_config max20411_regmap_config = {
	.reg_bits		= 8,
	.val_bits		= 8,
	.max_register		= 0xe,
};

static const struct regulator_ops max20411_ops = {
	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.list_voltage		= regulator_list_voltage_linear,
	.enable_time		= max20411_enable_time,
};

static const struct regulator_desc max20411_desc = {
	.ops = &max20411_ops,
	.owner = THIS_MODULE,
	.type = REGULATOR_VOLTAGE,
	.supply_name = "vin",
	.name = "max20411",

	/*
	 * voltage = 0.24375V + selector * 6.25mV
	 * with valid selector between 41 to 165 (0.5V to 1.275V)
	 */
	.min_uV = MAX20411_BASE_UV,
	.uV_step = MAX20411_UV_STEP,
	.linear_min_sel = MAX20411_MIN_SEL,
	.n_voltages = MAX20411_MAX_SEL + 1,

	.vsel_reg = MAX20411_VID_OFFSET,
	.vsel_mask = MAX20411_VID_MASK,

	.ramp_reg = MAX20411_SLEW_OFFSET,
	.ramp_mask = MAX20411_SLEW_DVS_MASK,
	.ramp_delay_table = max20411_slew_rates,
	.n_ramp_values = ARRAY_SIZE(max20411_slew_rates),
};

static int max20411_probe(struct i2c_client *client)
{
	struct regulator_init_data *init_data;
	struct device *dev = &client->dev;
	struct regulator_config cfg = {};
	struct max20411 *max20411;

	max20411 = devm_kzalloc(dev, sizeof(*max20411), GFP_KERNEL);
	if (!max20411)
		return -ENOMEM;

	max20411->regmap = devm_regmap_init_i2c(client, &max20411_regmap_config);
	if (IS_ERR(max20411->regmap)) {
		dev_err(dev, "Failed to allocate regmap!\n");
		return PTR_ERR(max20411->regmap);
	}

	max20411->dev = dev;
	max20411->of_node = dev->of_node;

	max20411->desc = max20411_desc;
	init_data = of_get_regulator_init_data(max20411->dev, max20411->of_node, &max20411->desc);
	if (!init_data)
		return -ENODATA;

	cfg.dev = max20411->dev;
	cfg.init_data = init_data;
	cfg.of_node = max20411->of_node;
	cfg.driver_data = max20411;

	cfg.ena_gpiod = gpiod_get(max20411->dev, "enable", GPIOD_ASIS);
	if (IS_ERR(cfg.ena_gpiod))
		return dev_err_probe(dev, PTR_ERR(cfg.ena_gpiod),
				     "unable to acquire enable gpio\n");

	max20411->rdev = devm_regulator_register(max20411->dev, &max20411->desc, &cfg);
	if (IS_ERR(max20411->rdev))
		dev_err(max20411->dev, "Failed to register regulator\n");

	return PTR_ERR_OR_ZERO(max20411->rdev);
}

static const struct of_device_id of_max20411_match_tbl[] = {
	{ .compatible = "maxim,max20411", },
	{ },
};
MODULE_DEVICE_TABLE(of, of_max20411_match_tbl);

static const struct i2c_device_id max20411_id[] = {
	{ "max20411", 0 },
	{ },
};
MODULE_DEVICE_TABLE(i2c, max20411_id);

static struct i2c_driver max20411_i2c_driver = {
	.driver	= {
		.name = "max20411",
		.of_match_table	= of_max20411_match_tbl,
	},
	.probe_new = max20411_probe,
	.id_table = max20411_id,
};
module_i2c_driver(max20411_i2c_driver);

MODULE_LICENSE("GPL");