Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2017 Spreadtrum Communications Inc.
  4 */
  5
  6#include <linux/module.h>
  7#include <linux/of.h>
  8#include <linux/platform_device.h>
  9#include <linux/regmap.h>
 10#include <linux/regulator/driver.h>
 11#include <linux/regulator/of_regulator.h>
 12
 13/*
 14 * SC2731 regulator lock register
 15 */
 16#define SC2731_PWR_WR_PROT		0xf0c
 17#define SC2731_WR_UNLOCK_VALUE		0x6e7f
 18
 19/*
 20 * SC2731 enable register
 21 */
 22#define SC2731_POWER_PD_SW		0xc28
 23#define SC2731_LDO_CAMA0_PD		0xcfc
 24#define SC2731_LDO_CAMA1_PD		0xd04
 25#define SC2731_LDO_CAMMOT_PD		0xd0c
 26#define SC2731_LDO_VLDO_PD		0xd6c
 27#define SC2731_LDO_EMMCCORE_PD		0xd2c
 28#define SC2731_LDO_SDCORE_PD		0xd74
 29#define SC2731_LDO_SDIO_PD		0xd70
 30#define SC2731_LDO_WIFIPA_PD		0xd4c
 31#define SC2731_LDO_USB33_PD		0xd5c
 32#define SC2731_LDO_CAMD0_PD		0xd7c
 33#define SC2731_LDO_CAMD1_PD		0xd84
 34#define SC2731_LDO_CON_PD		0xd8c
 35#define SC2731_LDO_CAMIO_PD		0xd94
 36#define SC2731_LDO_SRAM_PD		0xd78
 37
 38/*
 39 * SC2731 enable mask
 40 */
 41#define SC2731_DCDC_CPU0_PD_MASK	BIT(4)
 42#define SC2731_DCDC_CPU1_PD_MASK	BIT(3)
 43#define SC2731_DCDC_RF_PD_MASK		BIT(11)
 44#define SC2731_LDO_CAMA0_PD_MASK	BIT(0)
 45#define SC2731_LDO_CAMA1_PD_MASK	BIT(0)
 46#define SC2731_LDO_CAMMOT_PD_MASK	BIT(0)
 47#define SC2731_LDO_VLDO_PD_MASK		BIT(0)
 48#define SC2731_LDO_EMMCCORE_PD_MASK	BIT(0)
 49#define SC2731_LDO_SDCORE_PD_MASK	BIT(0)
 50#define SC2731_LDO_SDIO_PD_MASK		BIT(0)
 51#define SC2731_LDO_WIFIPA_PD_MASK	BIT(0)
 52#define SC2731_LDO_USB33_PD_MASK	BIT(0)
 53#define SC2731_LDO_CAMD0_PD_MASK	BIT(0)
 54#define SC2731_LDO_CAMD1_PD_MASK	BIT(0)
 55#define SC2731_LDO_CON_PD_MASK		BIT(0)
 56#define SC2731_LDO_CAMIO_PD_MASK	BIT(0)
 57#define SC2731_LDO_SRAM_PD_MASK		BIT(0)
 58
 59/*
 60 * SC2731 vsel register
 61 */
 62#define SC2731_DCDC_CPU0_VOL		0xc54
 63#define SC2731_DCDC_CPU1_VOL		0xc64
 64#define SC2731_DCDC_RF_VOL		0xcb8
 65#define SC2731_LDO_CAMA0_VOL		0xd00
 66#define SC2731_LDO_CAMA1_VOL		0xd08
 67#define SC2731_LDO_CAMMOT_VOL		0xd10
 68#define SC2731_LDO_VLDO_VOL		0xd28
 69#define SC2731_LDO_EMMCCORE_VOL		0xd30
 70#define SC2731_LDO_SDCORE_VOL		0xd38
 71#define SC2731_LDO_SDIO_VOL		0xd40
 72#define SC2731_LDO_WIFIPA_VOL		0xd50
 73#define SC2731_LDO_USB33_VOL		0xd60
 74#define SC2731_LDO_CAMD0_VOL		0xd80
 75#define SC2731_LDO_CAMD1_VOL		0xd88
 76#define SC2731_LDO_CON_VOL		0xd90
 77#define SC2731_LDO_CAMIO_VOL		0xd98
 78#define SC2731_LDO_SRAM_VOL		0xdB0
 79
 80/*
 81 * SC2731 vsel register mask
 82 */
 83#define SC2731_DCDC_CPU0_VOL_MASK	GENMASK(8, 0)
 84#define SC2731_DCDC_CPU1_VOL_MASK	GENMASK(8, 0)
 85#define SC2731_DCDC_RF_VOL_MASK		GENMASK(8, 0)
 86#define SC2731_LDO_CAMA0_VOL_MASK	GENMASK(7, 0)
 87#define SC2731_LDO_CAMA1_VOL_MASK	GENMASK(7, 0)
 88#define SC2731_LDO_CAMMOT_VOL_MASK	GENMASK(7, 0)
 89#define SC2731_LDO_VLDO_VOL_MASK	GENMASK(7, 0)
 90#define SC2731_LDO_EMMCCORE_VOL_MASK	GENMASK(7, 0)
 91#define SC2731_LDO_SDCORE_VOL_MASK	GENMASK(7, 0)
 92#define SC2731_LDO_SDIO_VOL_MASK	GENMASK(7, 0)
 93#define SC2731_LDO_WIFIPA_VOL_MASK	GENMASK(7, 0)
 94#define SC2731_LDO_USB33_VOL_MASK	GENMASK(7, 0)
 95#define SC2731_LDO_CAMD0_VOL_MASK	GENMASK(6, 0)
 96#define SC2731_LDO_CAMD1_VOL_MASK	GENMASK(6, 0)
 97#define SC2731_LDO_CON_VOL_MASK		GENMASK(6, 0)
 98#define SC2731_LDO_CAMIO_VOL_MASK	GENMASK(6, 0)
 99#define SC2731_LDO_SRAM_VOL_MASK	GENMASK(6, 0)
100
101enum sc2731_regulator_id {
102	SC2731_BUCK_CPU0,
103	SC2731_BUCK_CPU1,
104	SC2731_BUCK_RF,
105	SC2731_LDO_CAMA0,
106	SC2731_LDO_CAMA1,
107	SC2731_LDO_CAMMOT,
108	SC2731_LDO_VLDO,
109	SC2731_LDO_EMMCCORE,
110	SC2731_LDO_SDCORE,
111	SC2731_LDO_SDIO,
112	SC2731_LDO_WIFIPA,
113	SC2731_LDO_USB33,
114	SC2731_LDO_CAMD0,
115	SC2731_LDO_CAMD1,
116	SC2731_LDO_CON,
117	SC2731_LDO_CAMIO,
118	SC2731_LDO_SRAM,
119};
120
121static const struct regulator_ops sc2731_regu_linear_ops = {
122	.enable = regulator_enable_regmap,
123	.disable = regulator_disable_regmap,
124	.is_enabled = regulator_is_enabled_regmap,
125	.list_voltage = regulator_list_voltage_linear,
126	.get_voltage_sel = regulator_get_voltage_sel_regmap,
127	.set_voltage_sel = regulator_set_voltage_sel_regmap,
128};
129
130#define SC2731_REGU_LINEAR(_id, en_reg, en_mask, vreg, vmask,	\
131			  vstep, vmin, vmax) {			\
132	.name			= #_id,				\
133	.of_match		= of_match_ptr(#_id),		\
134	.ops			= &sc2731_regu_linear_ops,	\
135	.type			= REGULATOR_VOLTAGE,		\
136	.id			= SC2731_##_id,			\
137	.owner			= THIS_MODULE,			\
138	.min_uV			= vmin,				\
139	.n_voltages		= ((vmax) - (vmin)) / (vstep) + 1,	\
140	.uV_step		= vstep,			\
141	.enable_is_inverted	= true,				\
142	.enable_val		= 0,				\
143	.enable_reg		= en_reg,			\
144	.enable_mask		= en_mask,			\
145	.vsel_reg		= vreg,				\
146	.vsel_mask		= vmask,			\
147}
148
149static const struct regulator_desc regulators[] = {
150	SC2731_REGU_LINEAR(BUCK_CPU0, SC2731_POWER_PD_SW,
151			   SC2731_DCDC_CPU0_PD_MASK, SC2731_DCDC_CPU0_VOL,
152			   SC2731_DCDC_CPU0_VOL_MASK, 3125, 400000, 1996875),
153	SC2731_REGU_LINEAR(BUCK_CPU1, SC2731_POWER_PD_SW,
154			   SC2731_DCDC_CPU1_PD_MASK, SC2731_DCDC_CPU1_VOL,
155			   SC2731_DCDC_CPU1_VOL_MASK, 3125, 400000, 1996875),
156	SC2731_REGU_LINEAR(BUCK_RF, SC2731_POWER_PD_SW, SC2731_DCDC_RF_PD_MASK,
157			   SC2731_DCDC_RF_VOL, SC2731_DCDC_RF_VOL_MASK,
158			   3125, 600000, 2196875),
159	SC2731_REGU_LINEAR(LDO_CAMA0, SC2731_LDO_CAMA0_PD,
160			   SC2731_LDO_CAMA0_PD_MASK, SC2731_LDO_CAMA0_VOL,
161			   SC2731_LDO_CAMA0_VOL_MASK, 10000, 1200000, 3750000),
162	SC2731_REGU_LINEAR(LDO_CAMA1, SC2731_LDO_CAMA1_PD,
163			   SC2731_LDO_CAMA1_PD_MASK, SC2731_LDO_CAMA1_VOL,
164			   SC2731_LDO_CAMA1_VOL_MASK, 10000, 1200000, 3750000),
165	SC2731_REGU_LINEAR(LDO_CAMMOT, SC2731_LDO_CAMMOT_PD,
166			   SC2731_LDO_CAMMOT_PD_MASK, SC2731_LDO_CAMMOT_VOL,
167			   SC2731_LDO_CAMMOT_VOL_MASK, 10000, 1200000, 3750000),
168	SC2731_REGU_LINEAR(LDO_VLDO, SC2731_LDO_VLDO_PD,
169			   SC2731_LDO_VLDO_PD_MASK, SC2731_LDO_VLDO_VOL,
170			   SC2731_LDO_VLDO_VOL_MASK, 10000, 1200000, 3750000),
171	SC2731_REGU_LINEAR(LDO_EMMCCORE, SC2731_LDO_EMMCCORE_PD,
172			   SC2731_LDO_EMMCCORE_PD_MASK, SC2731_LDO_EMMCCORE_VOL,
173			   SC2731_LDO_EMMCCORE_VOL_MASK, 10000, 1200000,
174			   3750000),
175	SC2731_REGU_LINEAR(LDO_SDCORE, SC2731_LDO_SDCORE_PD,
176			   SC2731_LDO_SDCORE_PD_MASK, SC2731_LDO_SDCORE_VOL,
177			   SC2731_LDO_SDCORE_VOL_MASK, 10000, 1200000, 3750000),
178	SC2731_REGU_LINEAR(LDO_SDIO, SC2731_LDO_SDIO_PD,
179			   SC2731_LDO_SDIO_PD_MASK, SC2731_LDO_SDIO_VOL,
180			   SC2731_LDO_SDIO_VOL_MASK, 10000, 1200000, 3750000),
181	SC2731_REGU_LINEAR(LDO_WIFIPA, SC2731_LDO_WIFIPA_PD,
182			   SC2731_LDO_WIFIPA_PD_MASK, SC2731_LDO_WIFIPA_VOL,
183			   SC2731_LDO_WIFIPA_VOL_MASK, 10000, 1200000, 3750000),
184	SC2731_REGU_LINEAR(LDO_USB33, SC2731_LDO_USB33_PD,
185			   SC2731_LDO_USB33_PD_MASK, SC2731_LDO_USB33_VOL,
186			   SC2731_LDO_USB33_VOL_MASK, 10000, 1200000, 3750000),
187	SC2731_REGU_LINEAR(LDO_CAMD0, SC2731_LDO_CAMD0_PD,
188			   SC2731_LDO_CAMD0_PD_MASK, SC2731_LDO_CAMD0_VOL,
189			   SC2731_LDO_CAMD0_VOL_MASK, 6250, 1000000, 1793750),
190	SC2731_REGU_LINEAR(LDO_CAMD1, SC2731_LDO_CAMD1_PD,
191			   SC2731_LDO_CAMD1_PD_MASK, SC2731_LDO_CAMD1_VOL,
192			   SC2731_LDO_CAMD1_VOL_MASK, 6250, 1000000, 1793750),
193	SC2731_REGU_LINEAR(LDO_CON, SC2731_LDO_CON_PD,
194			   SC2731_LDO_CON_PD_MASK, SC2731_LDO_CON_VOL,
195			   SC2731_LDO_CON_VOL_MASK, 6250, 1000000, 1793750),
196	SC2731_REGU_LINEAR(LDO_CAMIO, SC2731_LDO_CAMIO_PD,
197			   SC2731_LDO_CAMIO_PD_MASK, SC2731_LDO_CAMIO_VOL,
198			   SC2731_LDO_CAMIO_VOL_MASK, 6250, 1000000, 1793750),
199	SC2731_REGU_LINEAR(LDO_SRAM, SC2731_LDO_SRAM_PD,
200			   SC2731_LDO_SRAM_PD_MASK, SC2731_LDO_SRAM_VOL,
201			   SC2731_LDO_SRAM_VOL_MASK, 6250, 1000000, 1793750),
202};
203
204static int sc2731_regulator_unlock(struct regmap *regmap)
205{
206	return regmap_write(regmap, SC2731_PWR_WR_PROT,
207			    SC2731_WR_UNLOCK_VALUE);
208}
209
210static int sc2731_regulator_probe(struct platform_device *pdev)
211{
212	int i, ret;
213	struct regmap *regmap;
214	struct regulator_config config = { };
215	struct regulator_dev *rdev;
216
217	regmap = dev_get_regmap(pdev->dev.parent, NULL);
218	if (!regmap) {
219		dev_err(&pdev->dev, "failed to get regmap.\n");
220		return -ENODEV;
221	}
222
223	ret = sc2731_regulator_unlock(regmap);
224	if (ret) {
225		dev_err(&pdev->dev, "failed to release regulator lock\n");
226		return ret;
227	}
228
229	config.dev = &pdev->dev;
230	config.regmap = regmap;
231
232	for (i = 0; i < ARRAY_SIZE(regulators); i++) {
233		rdev = devm_regulator_register(&pdev->dev, &regulators[i],
234					       &config);
235		if (IS_ERR(rdev)) {
236			dev_err(&pdev->dev, "failed to register regulator %s\n",
237				regulators[i].name);
238			return PTR_ERR(rdev);
239		}
240	}
241
242	return 0;
243}
244
245static struct platform_driver sc2731_regulator_driver = {
246	.driver = {
247		.name = "sc27xx-regulator",
248	},
249	.probe = sc2731_regulator_probe,
250};
251
252module_platform_driver(sc2731_regulator_driver);
253
254MODULE_AUTHOR("Chen Junhui <erick.chen@spreadtrum.com>");
255MODULE_DESCRIPTION("Spreadtrum SC2731 regulator driver");
256MODULE_LICENSE("GPL v2");