162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (c) 2015 MediaTek Inc.
462306a36Sopenharmony_ci// Author: Henry Chen <henryc.chen@mediatek.com>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/err.h>
762306a36Sopenharmony_ci#include <linux/i2c.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/interrupt.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/regmap.h>
1262306a36Sopenharmony_ci#include <linux/regulator/driver.h>
1362306a36Sopenharmony_ci#include <linux/regulator/machine.h>
1462306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
1562306a36Sopenharmony_ci#include <linux/regulator/mt6311.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include "mt6311-regulator.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const struct regmap_config mt6311_regmap_config = {
2062306a36Sopenharmony_ci	.reg_bits = 8,
2162306a36Sopenharmony_ci	.val_bits = 8,
2262306a36Sopenharmony_ci	.max_register = MT6311_FQMTR_CON4,
2362306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Default limits measured in millivolts and milliamps */
2762306a36Sopenharmony_ci#define MT6311_MIN_UV		600000
2862306a36Sopenharmony_ci#define MT6311_MAX_UV		1393750
2962306a36Sopenharmony_ci#define MT6311_STEP_UV		6250
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic const struct regulator_ops mt6311_buck_ops = {
3262306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
3362306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
3462306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
3562306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
3662306a36Sopenharmony_ci	.set_voltage_time_sel = regulator_set_voltage_time_sel,
3762306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
3862306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
3962306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct regulator_ops mt6311_ldo_ops = {
4362306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
4462306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
4562306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define MT6311_BUCK(_id) \
4962306a36Sopenharmony_ci{\
5062306a36Sopenharmony_ci	.name = #_id,\
5162306a36Sopenharmony_ci	.ops = &mt6311_buck_ops,\
5262306a36Sopenharmony_ci	.of_match = of_match_ptr(#_id),\
5362306a36Sopenharmony_ci	.regulators_node = of_match_ptr("regulators"),\
5462306a36Sopenharmony_ci	.type = REGULATOR_VOLTAGE,\
5562306a36Sopenharmony_ci	.id = MT6311_ID_##_id,\
5662306a36Sopenharmony_ci	.n_voltages = (MT6311_MAX_UV - MT6311_MIN_UV) / MT6311_STEP_UV + 1,\
5762306a36Sopenharmony_ci	.min_uV = MT6311_MIN_UV,\
5862306a36Sopenharmony_ci	.uV_step = MT6311_STEP_UV,\
5962306a36Sopenharmony_ci	.owner = THIS_MODULE,\
6062306a36Sopenharmony_ci	.enable_reg = MT6311_VDVFS11_CON9,\
6162306a36Sopenharmony_ci	.enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\
6262306a36Sopenharmony_ci	.vsel_reg = MT6311_VDVFS11_CON12,\
6362306a36Sopenharmony_ci	.vsel_mask = MT6311_PMIC_VDVFS11_VOSEL_MASK,\
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define MT6311_LDO(_id) \
6762306a36Sopenharmony_ci{\
6862306a36Sopenharmony_ci	.name = #_id,\
6962306a36Sopenharmony_ci	.ops = &mt6311_ldo_ops,\
7062306a36Sopenharmony_ci	.of_match = of_match_ptr(#_id),\
7162306a36Sopenharmony_ci	.regulators_node = of_match_ptr("regulators"),\
7262306a36Sopenharmony_ci	.type = REGULATOR_VOLTAGE,\
7362306a36Sopenharmony_ci	.id = MT6311_ID_##_id,\
7462306a36Sopenharmony_ci	.owner = THIS_MODULE,\
7562306a36Sopenharmony_ci	.enable_reg = MT6311_LDO_CON3,\
7662306a36Sopenharmony_ci	.enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic const struct regulator_desc mt6311_regulators[] = {
8062306a36Sopenharmony_ci	MT6311_BUCK(VDVFS),
8162306a36Sopenharmony_ci	MT6311_LDO(VBIASN),
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/*
8562306a36Sopenharmony_ci * I2C driver interface functions
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistatic int mt6311_i2c_probe(struct i2c_client *i2c)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct regulator_config config = { };
9062306a36Sopenharmony_ci	struct regulator_dev *rdev;
9162306a36Sopenharmony_ci	struct regmap *regmap;
9262306a36Sopenharmony_ci	int i, ret;
9362306a36Sopenharmony_ci	unsigned int data;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config);
9662306a36Sopenharmony_ci	if (IS_ERR(regmap)) {
9762306a36Sopenharmony_ci		ret = PTR_ERR(regmap);
9862306a36Sopenharmony_ci		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
9962306a36Sopenharmony_ci			ret);
10062306a36Sopenharmony_ci		return ret;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ret = regmap_read(regmap, MT6311_SWCID, &data);
10462306a36Sopenharmony_ci	if (ret < 0) {
10562306a36Sopenharmony_ci		dev_err(&i2c->dev, "Failed to read DEVICE_ID reg: %d\n", ret);
10662306a36Sopenharmony_ci		return ret;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	switch (data) {
11062306a36Sopenharmony_ci	case MT6311_E1_CID_CODE:
11162306a36Sopenharmony_ci	case MT6311_E2_CID_CODE:
11262306a36Sopenharmony_ci	case MT6311_E3_CID_CODE:
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci	default:
11562306a36Sopenharmony_ci		dev_err(&i2c->dev, "Unsupported device id = 0x%x.\n", data);
11662306a36Sopenharmony_ci		return -ENODEV;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (i = 0; i < MT6311_MAX_REGULATORS; i++) {
12062306a36Sopenharmony_ci		config.dev = &i2c->dev;
12162306a36Sopenharmony_ci		config.regmap = regmap;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		rdev = devm_regulator_register(&i2c->dev,
12462306a36Sopenharmony_ci			&mt6311_regulators[i], &config);
12562306a36Sopenharmony_ci		if (IS_ERR(rdev)) {
12662306a36Sopenharmony_ci			dev_err(&i2c->dev,
12762306a36Sopenharmony_ci				"Failed to register MT6311 regulator\n");
12862306a36Sopenharmony_ci			return PTR_ERR(rdev);
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic const struct i2c_device_id mt6311_i2c_id[] = {
13662306a36Sopenharmony_ci	{"mt6311", 0},
13762306a36Sopenharmony_ci	{},
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mt6311_i2c_id);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#ifdef CONFIG_OF
14262306a36Sopenharmony_cistatic const struct of_device_id mt6311_dt_ids[] = {
14362306a36Sopenharmony_ci	{ .compatible = "mediatek,mt6311-regulator",
14462306a36Sopenharmony_ci	  .data = &mt6311_i2c_id[0] },
14562306a36Sopenharmony_ci	{},
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mt6311_dt_ids);
14862306a36Sopenharmony_ci#endif
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic struct i2c_driver mt6311_regulator_driver = {
15162306a36Sopenharmony_ci	.driver = {
15262306a36Sopenharmony_ci		.name = "mt6311",
15362306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
15462306a36Sopenharmony_ci		.of_match_table = of_match_ptr(mt6311_dt_ids),
15562306a36Sopenharmony_ci	},
15662306a36Sopenharmony_ci	.probe = mt6311_i2c_probe,
15762306a36Sopenharmony_ci	.id_table = mt6311_i2c_id,
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cimodule_i2c_driver(mt6311_regulator_driver);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciMODULE_AUTHOR("Henry Chen <henryc.chen@mediatek.com>");
16362306a36Sopenharmony_ciMODULE_DESCRIPTION("Regulator device driver for Mediatek MT6311");
16462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
165