18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * isl9305 - Intersil ISL9305 DCDC regulator
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2014 Linaro Ltd
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Mark Brown <broonie@kernel.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/err.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_data/isl9305.h>
158c2ecf20Sopenharmony_ci#include <linux/regmap.h>
168c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
178c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Registers
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci#define ISL9305_DCD1OUT          0x0
248c2ecf20Sopenharmony_ci#define ISL9305_DCD2OUT          0x1
258c2ecf20Sopenharmony_ci#define ISL9305_LDO1OUT          0x2
268c2ecf20Sopenharmony_ci#define ISL9305_LDO2OUT          0x3
278c2ecf20Sopenharmony_ci#define ISL9305_DCD_PARAMETER    0x4
288c2ecf20Sopenharmony_ci#define ISL9305_SYSTEM_PARAMETER 0x5
298c2ecf20Sopenharmony_ci#define ISL9305_DCD_SRCTL        0x6
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define ISL9305_MAX_REG ISL9305_DCD_SRCTL
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * DCD_PARAMETER
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define ISL9305_DCD_PHASE   0x40
378c2ecf20Sopenharmony_ci#define ISL9305_DCD2_ULTRA  0x20
388c2ecf20Sopenharmony_ci#define ISL9305_DCD1_ULTRA  0x10
398c2ecf20Sopenharmony_ci#define ISL9305_DCD2_BLD    0x08
408c2ecf20Sopenharmony_ci#define ISL9305_DCD1_BLD    0x04
418c2ecf20Sopenharmony_ci#define ISL9305_DCD2_MODE   0x02
428c2ecf20Sopenharmony_ci#define ISL9305_DCD1_MODE   0x01
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * SYSTEM_PARAMETER
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci#define ISL9305_I2C_EN      0x40
488c2ecf20Sopenharmony_ci#define ISL9305_DCDPOR_MASK 0x30
498c2ecf20Sopenharmony_ci#define ISL9305_LDO2_EN     0x08
508c2ecf20Sopenharmony_ci#define ISL9305_LDO1_EN     0x04
518c2ecf20Sopenharmony_ci#define ISL9305_DCD2_EN     0x02
528c2ecf20Sopenharmony_ci#define ISL9305_DCD1_EN     0x01
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * DCD_SRCTL
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_ci#define ISL9305_DCD2SR_MASK 0xc0
588c2ecf20Sopenharmony_ci#define ISL9305_DCD1SR_MASK 0x07
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic const struct regulator_ops isl9305_ops = {
618c2ecf20Sopenharmony_ci	.enable = regulator_enable_regmap,
628c2ecf20Sopenharmony_ci	.disable = regulator_disable_regmap,
638c2ecf20Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
648c2ecf20Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
658c2ecf20Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
668c2ecf20Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic const struct regulator_desc isl9305_regulators[] = {
708c2ecf20Sopenharmony_ci	[ISL9305_DCD1] = {
718c2ecf20Sopenharmony_ci		.name =		"DCD1",
728c2ecf20Sopenharmony_ci		.of_match =	of_match_ptr("dcd1"),
738c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),
748c2ecf20Sopenharmony_ci		.n_voltages =	0x70,
758c2ecf20Sopenharmony_ci		.min_uV =	825000,
768c2ecf20Sopenharmony_ci		.uV_step =	25000,
778c2ecf20Sopenharmony_ci		.vsel_reg =	ISL9305_DCD1OUT,
788c2ecf20Sopenharmony_ci		.vsel_mask =	0x7f,
798c2ecf20Sopenharmony_ci		.enable_reg =	ISL9305_SYSTEM_PARAMETER,
808c2ecf20Sopenharmony_ci		.enable_mask =	ISL9305_DCD1_EN,
818c2ecf20Sopenharmony_ci		.supply_name =	"VINDCD1",
828c2ecf20Sopenharmony_ci		.ops =		&isl9305_ops,
838c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
848c2ecf20Sopenharmony_ci	},
858c2ecf20Sopenharmony_ci	[ISL9305_DCD2] = {
868c2ecf20Sopenharmony_ci		.name =		"DCD2",
878c2ecf20Sopenharmony_ci		.of_match =	of_match_ptr("dcd2"),
888c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),
898c2ecf20Sopenharmony_ci		.n_voltages =	0x70,
908c2ecf20Sopenharmony_ci		.min_uV =	825000,
918c2ecf20Sopenharmony_ci		.uV_step =	25000,
928c2ecf20Sopenharmony_ci		.vsel_reg =	ISL9305_DCD2OUT,
938c2ecf20Sopenharmony_ci		.vsel_mask =	0x7f,
948c2ecf20Sopenharmony_ci		.enable_reg =	ISL9305_SYSTEM_PARAMETER,
958c2ecf20Sopenharmony_ci		.enable_mask =	ISL9305_DCD2_EN,
968c2ecf20Sopenharmony_ci		.supply_name =	"VINDCD2",
978c2ecf20Sopenharmony_ci		.ops =		&isl9305_ops,
988c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
998c2ecf20Sopenharmony_ci	},
1008c2ecf20Sopenharmony_ci	[ISL9305_LDO1] = {
1018c2ecf20Sopenharmony_ci		.name =		"LDO1",
1028c2ecf20Sopenharmony_ci		.of_match =	of_match_ptr("ldo1"),
1038c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),
1048c2ecf20Sopenharmony_ci		.n_voltages =	0x37,
1058c2ecf20Sopenharmony_ci		.min_uV =	900000,
1068c2ecf20Sopenharmony_ci		.uV_step =	50000,
1078c2ecf20Sopenharmony_ci		.vsel_reg =	ISL9305_LDO1OUT,
1088c2ecf20Sopenharmony_ci		.vsel_mask =	0x3f,
1098c2ecf20Sopenharmony_ci		.enable_reg =	ISL9305_SYSTEM_PARAMETER,
1108c2ecf20Sopenharmony_ci		.enable_mask =	ISL9305_LDO1_EN,
1118c2ecf20Sopenharmony_ci		.supply_name =	"VINLDO1",
1128c2ecf20Sopenharmony_ci		.ops =		&isl9305_ops,
1138c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
1148c2ecf20Sopenharmony_ci	},
1158c2ecf20Sopenharmony_ci	[ISL9305_LDO2] = {
1168c2ecf20Sopenharmony_ci		.name =		"LDO2",
1178c2ecf20Sopenharmony_ci		.of_match =	of_match_ptr("ldo2"),
1188c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),
1198c2ecf20Sopenharmony_ci		.n_voltages =	0x37,
1208c2ecf20Sopenharmony_ci		.min_uV =	900000,
1218c2ecf20Sopenharmony_ci		.uV_step =	50000,
1228c2ecf20Sopenharmony_ci		.vsel_reg =	ISL9305_LDO2OUT,
1238c2ecf20Sopenharmony_ci		.vsel_mask =	0x3f,
1248c2ecf20Sopenharmony_ci		.enable_reg =	ISL9305_SYSTEM_PARAMETER,
1258c2ecf20Sopenharmony_ci		.enable_mask =	ISL9305_LDO2_EN,
1268c2ecf20Sopenharmony_ci		.supply_name =	"VINLDO2",
1278c2ecf20Sopenharmony_ci		.ops =		&isl9305_ops,
1288c2ecf20Sopenharmony_ci		.owner =	THIS_MODULE,
1298c2ecf20Sopenharmony_ci	},
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic const struct regmap_config isl9305_regmap = {
1338c2ecf20Sopenharmony_ci	.reg_bits = 8,
1348c2ecf20Sopenharmony_ci	.val_bits = 8,
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	.max_register = ISL9305_MAX_REG,
1378c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int isl9305_i2c_probe(struct i2c_client *i2c)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct regulator_config config = { };
1438c2ecf20Sopenharmony_ci	struct isl9305_pdata *pdata = i2c->dev.platform_data;
1448c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
1458c2ecf20Sopenharmony_ci	struct regmap *regmap;
1468c2ecf20Sopenharmony_ci	int i, ret;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap);
1498c2ecf20Sopenharmony_ci	if (IS_ERR(regmap)) {
1508c2ecf20Sopenharmony_ci		ret = PTR_ERR(regmap);
1518c2ecf20Sopenharmony_ci		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
1528c2ecf20Sopenharmony_ci		return ret;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	config.dev = &i2c->dev;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) {
1588c2ecf20Sopenharmony_ci		if (pdata)
1598c2ecf20Sopenharmony_ci			config.init_data = pdata->init_data[i];
1608c2ecf20Sopenharmony_ci		else
1618c2ecf20Sopenharmony_ci			config.init_data = NULL;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		rdev = devm_regulator_register(&i2c->dev,
1648c2ecf20Sopenharmony_ci					       &isl9305_regulators[i],
1658c2ecf20Sopenharmony_ci					       &config);
1668c2ecf20Sopenharmony_ci		if (IS_ERR(rdev)) {
1678c2ecf20Sopenharmony_ci			ret = PTR_ERR(rdev);
1688c2ecf20Sopenharmony_ci			dev_err(&i2c->dev, "Failed to register %s: %d\n",
1698c2ecf20Sopenharmony_ci				isl9305_regulators[i].name, ret);
1708c2ecf20Sopenharmony_ci			return ret;
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return 0;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
1788c2ecf20Sopenharmony_cistatic const struct of_device_id isl9305_dt_ids[] = {
1798c2ecf20Sopenharmony_ci	{ .compatible = "isl,isl9305" }, /* for backward compat., don't use */
1808c2ecf20Sopenharmony_ci	{ .compatible = "isil,isl9305" },
1818c2ecf20Sopenharmony_ci	{ .compatible = "isl,isl9305h" }, /* for backward compat., don't use */
1828c2ecf20Sopenharmony_ci	{ .compatible = "isil,isl9305h" },
1838c2ecf20Sopenharmony_ci	{},
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, isl9305_dt_ids);
1868c2ecf20Sopenharmony_ci#endif
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic const struct i2c_device_id isl9305_i2c_id[] = {
1898c2ecf20Sopenharmony_ci	{ "isl9305", },
1908c2ecf20Sopenharmony_ci	{ "isl9305h", },
1918c2ecf20Sopenharmony_ci	{ }
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, isl9305_i2c_id);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic struct i2c_driver isl9305_regulator_driver = {
1968c2ecf20Sopenharmony_ci	.driver = {
1978c2ecf20Sopenharmony_ci		.name = "isl9305",
1988c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(isl9305_dt_ids),
1998c2ecf20Sopenharmony_ci	},
2008c2ecf20Sopenharmony_ci	.probe_new = isl9305_i2c_probe,
2018c2ecf20Sopenharmony_ci	.id_table = isl9305_i2c_id,
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cimodule_i2c_driver(isl9305_regulator_driver);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark Brown");
2078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator");
2088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
209