1134458Siedowse// SPDX-License-Identifier: GPL-2.0-only
2134458Siedowse/*
3134458Siedowse * linux/drivers/regulator/aat2870-regulator.c
4134458Siedowse *
5134458Siedowse * Copyright (c) 2011, NVIDIA Corporation.
6134458Siedowse * Author: Jin Park <jinyoungp@nvidia.com>
7134458Siedowse */
8134458Siedowse
9134458Siedowse#include <linux/kernel.h>
10134458Siedowse#include <linux/init.h>
11134458Siedowse#include <linux/err.h>
12134458Siedowse#include <linux/module.h>
13134458Siedowse#include <linux/slab.h>
14134458Siedowse#include <linux/platform_device.h>
15134458Siedowse#include <linux/regulator/driver.h>
16134458Siedowse#include <linux/regulator/machine.h>
17134458Siedowse#include <linux/mfd/aat2870.h>
18134458Siedowse
19134458Siedowsestruct aat2870_regulator {
20134458Siedowse	struct aat2870_data *aat2870;
21134458Siedowse	struct regulator_desc desc;
22134458Siedowse
23134458Siedowse	u8 enable_addr;
24134458Siedowse	u8 enable_shift;
25134458Siedowse	u8 enable_mask;
26134458Siedowse
27134458Siedowse	u8 voltage_addr;
28134458Siedowse	u8 voltage_shift;
29134458Siedowse	u8 voltage_mask;
30134458Siedowse};
31134458Siedowse
32134458Siedowsestatic int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
33134458Siedowse				       unsigned selector)
34134458Siedowse{
35134458Siedowse	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
36134458Siedowse	struct aat2870_data *aat2870 = ri->aat2870;
37134458Siedowse
38134458Siedowse	return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
39134458Siedowse			       selector << ri->voltage_shift);
40134458Siedowse}
41134458Siedowse
42134458Siedowsestatic int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
43134458Siedowse{
44134458Siedowse	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
45134458Siedowse	struct aat2870_data *aat2870 = ri->aat2870;
46134458Siedowse	u8 val;
47134458Siedowse	int ret;
48134458Siedowse
49134458Siedowse	ret = aat2870->read(aat2870, ri->voltage_addr, &val);
50134458Siedowse	if (ret)
51134458Siedowse		return ret;
52134458Siedowse
53134458Siedowse	return (val & ri->voltage_mask) >> ri->voltage_shift;
54134458Siedowse}
55134458Siedowse
56134458Siedowsestatic int aat2870_ldo_enable(struct regulator_dev *rdev)
57153504Smarcel{
58134458Siedowse	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
59134458Siedowse	struct aat2870_data *aat2870 = ri->aat2870;
60134458Siedowse
61134458Siedowse	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
62134458Siedowse			       ri->enable_mask);
63134458Siedowse}
64134458Siedowse
65134458Siedowsestatic int aat2870_ldo_disable(struct regulator_dev *rdev)
66134458Siedowse{
67134458Siedowse	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
68134458Siedowse	struct aat2870_data *aat2870 = ri->aat2870;
69134458Siedowse
70134458Siedowse	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
71134458Siedowse}
72134458Siedowse
73134458Siedowsestatic int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
74134458Siedowse{
75134458Siedowse	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
76134458Siedowse	struct aat2870_data *aat2870 = ri->aat2870;
77134458Siedowse	u8 val;
78134458Siedowse	int ret;
79134458Siedowse
80134458Siedowse	ret = aat2870->read(aat2870, ri->enable_addr, &val);
81223695Sdfr	if (ret)
82134458Siedowse		return ret;
83134458Siedowse
84153504Smarcel	return val & ri->enable_mask ? 1 : 0;
85134458Siedowse}
86134458Siedowse
87134458Siedowsestatic const struct regulator_ops aat2870_ldo_ops = {
88134458Siedowse	.list_voltage = regulator_list_voltage_table,
89134458Siedowse	.map_voltage = regulator_map_voltage_ascend,
90134458Siedowse	.set_voltage_sel = aat2870_ldo_set_voltage_sel,
91134458Siedowse	.get_voltage_sel = aat2870_ldo_get_voltage_sel,
92134458Siedowse	.enable = aat2870_ldo_enable,
93134458Siedowse	.disable = aat2870_ldo_disable,
94134458Siedowse	.is_enabled = aat2870_ldo_is_enabled,
95134458Siedowse};
96134458Siedowse
97134458Siedowsestatic const unsigned int aat2870_ldo_voltages[] = {
98134458Siedowse	1200000, 1300000, 1500000, 1600000,
99134458Siedowse	1800000, 2000000, 2200000, 2500000,
100134458Siedowse	2600000, 2700000, 2800000, 2900000,
101134458Siedowse	3000000, 3100000, 3200000, 3300000,
102134458Siedowse};
103134458Siedowse
104134458Siedowse#define AAT2870_LDO(ids)				\
105134458Siedowse	{						\
106134458Siedowse		.desc = {				\
107134458Siedowse			.name = #ids,			\
108134458Siedowse			.id = AAT2870_ID_##ids,		\
109134458Siedowse			.n_voltages = ARRAY_SIZE(aat2870_ldo_voltages),	\
110134458Siedowse			.volt_table = aat2870_ldo_voltages, \
111134458Siedowse			.ops = &aat2870_ldo_ops,	\
112134458Siedowse			.type = REGULATOR_VOLTAGE,	\
113134458Siedowse			.owner = THIS_MODULE,		\
114134458Siedowse		},					\
115134458Siedowse	}
116134458Siedowse
117134458Siedowsestatic struct aat2870_regulator aat2870_regulators[] = {
118134458Siedowse	AAT2870_LDO(LDOA),
119134458Siedowse	AAT2870_LDO(LDOB),
120134458Siedowse	AAT2870_LDO(LDOC),
121134458Siedowse	AAT2870_LDO(LDOD),
122134458Siedowse};
123134458Siedowse
124134458Siedowsestatic struct aat2870_regulator *aat2870_get_regulator(int id)
125134458Siedowse{
126134458Siedowse	struct aat2870_regulator *ri = NULL;
127134458Siedowse	int i;
128134458Siedowse
129134458Siedowse	for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
130134458Siedowse		ri = &aat2870_regulators[i];
131134458Siedowse		if (ri->desc.id == id)
132134458Siedowse			break;
133134458Siedowse	}
134134458Siedowse
135134458Siedowse	if (i == ARRAY_SIZE(aat2870_regulators))
136134458Siedowse		return NULL;
137134458Siedowse
138134458Siedowse	ri->enable_addr = AAT2870_LDO_EN;
139134458Siedowse	ri->enable_shift = id - AAT2870_ID_LDOA;
140134458Siedowse	ri->enable_mask = 0x1 << ri->enable_shift;
141153504Smarcel
142134458Siedowse	ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
143134458Siedowse			   AAT2870_LDO_CD : AAT2870_LDO_AB;
144134458Siedowse	ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
145134458Siedowse	ri->voltage_mask = 0xF << ri->voltage_shift;
146134458Siedowse
147134458Siedowse	return ri;
148134458Siedowse}
149134458Siedowse
150134458Siedowsestatic int aat2870_regulator_probe(struct platform_device *pdev)
151134458Siedowse{
152134458Siedowse	struct aat2870_regulator *ri;
153134458Siedowse	struct regulator_config config = { };
154134458Siedowse	struct regulator_dev *rdev;
155134458Siedowse
156134458Siedowse	ri = aat2870_get_regulator(pdev->id);
157134458Siedowse	if (!ri) {
158134458Siedowse		dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
159134458Siedowse		return -EINVAL;
160134458Siedowse	}
161134458Siedowse	ri->aat2870 = dev_get_drvdata(pdev->dev.parent);
162134458Siedowse
163134458Siedowse	config.dev = &pdev->dev;
164134458Siedowse	config.driver_data = ri;
165134458Siedowse	config.init_data = dev_get_platdata(&pdev->dev);
166134458Siedowse
167134458Siedowse	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
168134458Siedowse	if (IS_ERR(rdev)) {
169134458Siedowse		dev_err(&pdev->dev, "Failed to register regulator %s\n",
170134458Siedowse			ri->desc.name);
171134458Siedowse		return PTR_ERR(rdev);
172134458Siedowse	}
173134458Siedowse	platform_set_drvdata(pdev, rdev);
174134458Siedowse
175134458Siedowse	return 0;
176134458Siedowse}
177134458Siedowse
178134458Siedowsestatic struct platform_driver aat2870_regulator_driver = {
179134458Siedowse	.driver = {
180134458Siedowse		.name	= "aat2870-regulator",
181134458Siedowse		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
182134458Siedowse	},
183134458Siedowse	.probe	= aat2870_regulator_probe,
184134458Siedowse};
185134458Siedowse
186134458Siedowsestatic int __init aat2870_regulator_init(void)
187134458Siedowse{
188134458Siedowse	return platform_driver_register(&aat2870_regulator_driver);
189134458Siedowse}
190134458Siedowsesubsys_initcall(aat2870_regulator_init);
191134458Siedowse
192134458Siedowsestatic void __exit aat2870_regulator_exit(void)
193134458Siedowse{
194134458Siedowse	platform_driver_unregister(&aat2870_regulator_driver);
195134458Siedowse}
196241036Sandreastmodule_exit(aat2870_regulator_exit);
197241036Sandreast
198241036SandreastMODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
199241036SandreastMODULE_LICENSE("GPL");
200241036SandreastMODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
201241036SandreastMODULE_ALIAS("platform:aat2870-regulator");
202241036Sandreast