cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mt6315-regulator.c (8179B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2021 MediaTek Inc.
      4
      5#include <linux/module.h>
      6#include <linux/of_device.h>
      7#include <linux/regmap.h>
      8#include <linux/regulator/driver.h>
      9#include <linux/regulator/machine.h>
     10#include <linux/regulator/mt6315-regulator.h>
     11#include <linux/regulator/of_regulator.h>
     12#include <linux/spmi.h>
     13
     14#define MT6315_BUCK_MODE_AUTO		0
     15#define MT6315_BUCK_MODE_FORCE_PWM	1
     16#define MT6315_BUCK_MODE_LP		2
     17
     18struct mt6315_regulator_info {
     19	struct regulator_desc desc;
     20	u32 status_reg;
     21	u32 lp_mode_mask;
     22	u32 lp_mode_shift;
     23};
     24
     25struct mt_regulator_init_data {
     26	u32 modeset_mask[MT6315_VBUCK_MAX];
     27};
     28
     29struct mt6315_chip {
     30	struct device *dev;
     31	struct regmap *regmap;
     32};
     33
     34#define MT_BUCK(_name, _bid, _vsel)				\
     35[_bid] = {							\
     36	.desc = {						\
     37		.name = _name,					\
     38		.of_match = of_match_ptr(_name),		\
     39		.regulators_node = "regulators",		\
     40		.ops = &mt6315_volt_range_ops,			\
     41		.type = REGULATOR_VOLTAGE,			\
     42		.id = _bid,					\
     43		.owner = THIS_MODULE,				\
     44		.n_voltages = 0xc0,				\
     45		.linear_ranges = mt_volt_range1,		\
     46		.n_linear_ranges = ARRAY_SIZE(mt_volt_range1),	\
     47		.vsel_reg = _vsel,				\
     48		.vsel_mask = 0xff,				\
     49		.enable_reg = MT6315_BUCK_TOP_CON0,		\
     50		.enable_mask = BIT(_bid),			\
     51		.of_map_mode = mt6315_map_mode,			\
     52	},							\
     53	.status_reg = _bid##_DBG4,				\
     54	.lp_mode_mask = BIT(_bid),				\
     55	.lp_mode_shift = _bid,					\
     56}
     57
     58static const struct linear_range mt_volt_range1[] = {
     59	REGULATOR_LINEAR_RANGE(0, 0, 0xbf, 6250),
     60};
     61
     62static unsigned int mt6315_map_mode(unsigned int mode)
     63{
     64	switch (mode) {
     65	case MT6315_BUCK_MODE_AUTO:
     66		return REGULATOR_MODE_NORMAL;
     67	case MT6315_BUCK_MODE_FORCE_PWM:
     68		return REGULATOR_MODE_FAST;
     69	case MT6315_BUCK_MODE_LP:
     70		return REGULATOR_MODE_IDLE;
     71	default:
     72		return REGULATOR_MODE_INVALID;
     73	}
     74}
     75
     76static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
     77{
     78	struct mt_regulator_init_data *init = rdev_get_drvdata(rdev);
     79	const struct mt6315_regulator_info *info;
     80	int ret, regval;
     81	u32 modeset_mask;
     82
     83	info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
     84	modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
     85	ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_4PHASE_ANA_CON42, &regval);
     86	if (ret != 0) {
     87		dev_err(&rdev->dev, "Failed to get mode: %d\n", ret);
     88		return ret;
     89	}
     90
     91	if ((regval & modeset_mask) == modeset_mask)
     92		return REGULATOR_MODE_FAST;
     93
     94	ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_CON1, &regval);
     95	if (ret != 0) {
     96		dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
     97		return ret;
     98	}
     99
    100	if (regval & info->lp_mode_mask)
    101		return REGULATOR_MODE_IDLE;
    102	else
    103		return REGULATOR_MODE_NORMAL;
    104}
    105
    106static int mt6315_regulator_set_mode(struct regulator_dev *rdev,
    107				     u32 mode)
    108{
    109	struct mt_regulator_init_data *init = rdev_get_drvdata(rdev);
    110	const struct mt6315_regulator_info *info;
    111	int ret, val, curr_mode;
    112	u32 modeset_mask;
    113
    114	info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
    115	modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
    116	curr_mode = mt6315_regulator_get_mode(rdev);
    117	switch (mode) {
    118	case REGULATOR_MODE_FAST:
    119		ret = regmap_update_bits(rdev->regmap,
    120					 MT6315_BUCK_TOP_4PHASE_ANA_CON42,
    121					 modeset_mask,
    122					 modeset_mask);
    123		break;
    124	case REGULATOR_MODE_NORMAL:
    125		if (curr_mode == REGULATOR_MODE_FAST) {
    126			ret = regmap_update_bits(rdev->regmap,
    127						 MT6315_BUCK_TOP_4PHASE_ANA_CON42,
    128						 modeset_mask,
    129						 0);
    130		} else if (curr_mode == REGULATOR_MODE_IDLE) {
    131			ret = regmap_update_bits(rdev->regmap,
    132						 MT6315_BUCK_TOP_CON1,
    133						 info->lp_mode_mask,
    134						 0);
    135			usleep_range(100, 110);
    136		} else {
    137			ret = -EINVAL;
    138		}
    139		break;
    140	case REGULATOR_MODE_IDLE:
    141		val = MT6315_BUCK_MODE_LP >> 1;
    142		val <<= info->lp_mode_shift;
    143		ret = regmap_update_bits(rdev->regmap,
    144					 MT6315_BUCK_TOP_CON1,
    145					 info->lp_mode_mask,
    146					 val);
    147		break;
    148	default:
    149		ret = -EINVAL;
    150		dev_err(&rdev->dev, "Unsupported mode: %d\n", mode);
    151		break;
    152	}
    153
    154	if (ret != 0) {
    155		dev_err(&rdev->dev, "Failed to set mode: %d\n", ret);
    156		return ret;
    157	}
    158
    159	return 0;
    160}
    161
    162static int mt6315_get_status(struct regulator_dev *rdev)
    163{
    164	const struct mt6315_regulator_info *info;
    165	int ret;
    166	u32 regval;
    167
    168	info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
    169	ret = regmap_read(rdev->regmap, info->status_reg, &regval);
    170	if (ret < 0) {
    171		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
    172		return ret;
    173	}
    174
    175	return (regval & BIT(0)) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
    176}
    177
    178static const struct regulator_ops mt6315_volt_range_ops = {
    179	.list_voltage = regulator_list_voltage_linear_range,
    180	.map_voltage = regulator_map_voltage_linear_range,
    181	.set_voltage_sel = regulator_set_voltage_sel_regmap,
    182	.get_voltage_sel = regulator_get_voltage_sel_regmap,
    183	.set_voltage_time_sel = regulator_set_voltage_time_sel,
    184	.enable = regulator_enable_regmap,
    185	.disable = regulator_disable_regmap,
    186	.is_enabled = regulator_is_enabled_regmap,
    187	.get_status = mt6315_get_status,
    188	.set_mode = mt6315_regulator_set_mode,
    189	.get_mode = mt6315_regulator_get_mode,
    190};
    191
    192static const struct mt6315_regulator_info mt6315_regulators[MT6315_VBUCK_MAX] = {
    193	MT_BUCK("vbuck1", MT6315_VBUCK1, MT6315_BUCK_TOP_ELR0),
    194	MT_BUCK("vbuck2", MT6315_VBUCK2, MT6315_BUCK_TOP_ELR2),
    195	MT_BUCK("vbuck3", MT6315_VBUCK3, MT6315_BUCK_TOP_ELR4),
    196	MT_BUCK("vbuck4", MT6315_VBUCK4, MT6315_BUCK_TOP_ELR6),
    197};
    198
    199static const struct regmap_config mt6315_regmap_config = {
    200	.reg_bits	= 16,
    201	.val_bits	= 8,
    202	.max_register	= 0x16d0,
    203	.fast_io	= true,
    204};
    205
    206static const struct of_device_id mt6315_of_match[] = {
    207	{
    208		.compatible = "mediatek,mt6315-regulator",
    209	}, {
    210		/* sentinel */
    211	},
    212};
    213MODULE_DEVICE_TABLE(of, mt6315_of_match);
    214
    215static int mt6315_regulator_probe(struct spmi_device *pdev)
    216{
    217	struct device *dev = &pdev->dev;
    218	struct regmap *regmap;
    219	struct mt6315_chip *chip;
    220	struct mt_regulator_init_data *init_data;
    221	struct regulator_config config = {};
    222	struct regulator_dev *rdev;
    223	int i;
    224
    225	regmap = devm_regmap_init_spmi_ext(pdev, &mt6315_regmap_config);
    226	if (IS_ERR(regmap))
    227		return PTR_ERR(regmap);
    228
    229	chip = devm_kzalloc(dev, sizeof(struct mt6315_chip), GFP_KERNEL);
    230	if (!chip)
    231		return -ENOMEM;
    232
    233	init_data = devm_kzalloc(dev, sizeof(struct mt_regulator_init_data), GFP_KERNEL);
    234	if (!init_data)
    235		return -ENOMEM;
    236
    237	switch (pdev->usid) {
    238	case MT6315_PP:
    239		init_data->modeset_mask[MT6315_VBUCK1] = BIT(MT6315_VBUCK1) | BIT(MT6315_VBUCK2) |
    240							 BIT(MT6315_VBUCK4);
    241		break;
    242	case MT6315_SP:
    243	case MT6315_RP:
    244		init_data->modeset_mask[MT6315_VBUCK1] = BIT(MT6315_VBUCK1) | BIT(MT6315_VBUCK2);
    245		break;
    246	default:
    247		init_data->modeset_mask[MT6315_VBUCK1] = BIT(MT6315_VBUCK1);
    248		break;
    249	}
    250	for (i = MT6315_VBUCK2; i < MT6315_VBUCK_MAX; i++)
    251		init_data->modeset_mask[i] = BIT(i);
    252
    253	chip->dev = dev;
    254	chip->regmap = regmap;
    255	dev_set_drvdata(dev, chip);
    256
    257	config.dev = dev;
    258	config.regmap = regmap;
    259	for (i = MT6315_VBUCK1; i < MT6315_VBUCK_MAX; i++) {
    260		config.driver_data = init_data;
    261		rdev = devm_regulator_register(dev, &mt6315_regulators[i].desc, &config);
    262		if (IS_ERR(rdev)) {
    263			dev_err(dev, "Failed to register %s\n",
    264				mt6315_regulators[i].desc.name);
    265			return PTR_ERR(rdev);
    266		}
    267	}
    268
    269	return 0;
    270}
    271
    272static void mt6315_regulator_shutdown(struct spmi_device *pdev)
    273{
    274	struct mt6315_chip *chip = dev_get_drvdata(&pdev->dev);
    275	int ret = 0;
    276
    277	ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY_H, PROTECTION_KEY_H);
    278	ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY, PROTECTION_KEY);
    279	ret |= regmap_update_bits(chip->regmap, MT6315_TOP2_ELR7, 1, 1);
    280	ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY, 0);
    281	ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY_H, 0);
    282	if (ret < 0)
    283		dev_err(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n",
    284			   pdev->usid, ret);
    285}
    286
    287static struct spmi_driver mt6315_regulator_driver = {
    288	.driver		= {
    289		.name	= "mt6315-regulator",
    290		.of_match_table = mt6315_of_match,
    291	},
    292	.probe = mt6315_regulator_probe,
    293	.shutdown = mt6315_regulator_shutdown,
    294};
    295
    296module_spmi_driver(mt6315_regulator_driver);
    297
    298MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
    299MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6315 PMIC");
    300MODULE_LICENSE("GPL");