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

mp886x.c (8756B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// MP8867/MP8869 regulator driver
      4//
      5// Copyright (C) 2020 Synaptics Incorporated
      6//
      7// Author: Jisheng Zhang <jszhang@kernel.org>
      8
      9#include <linux/gpio/consumer.h>
     10#include <linux/i2c.h>
     11#include <linux/module.h>
     12#include <linux/of_device.h>
     13#include <linux/regmap.h>
     14#include <linux/regulator/driver.h>
     15#include <linux/regulator/of_regulator.h>
     16
     17#define MP886X_VSEL		0x00
     18#define  MP886X_V_BOOT		(1 << 7)
     19#define MP886X_SYSCNTLREG1	0x01
     20#define  MP886X_MODE		(1 << 0)
     21#define  MP886X_SLEW_SHIFT	3
     22#define  MP886X_SLEW_MASK	(0x7 << MP886X_SLEW_SHIFT)
     23#define  MP886X_GO		(1 << 6)
     24#define  MP886X_EN		(1 << 7)
     25#define MP8869_SYSCNTLREG2	0x02
     26
     27struct mp886x_cfg_info {
     28	const struct regulator_ops *rops;
     29	const unsigned int slew_rates[8];
     30	const int switch_freq[4];
     31	const u8 fs_reg;
     32	const u8 fs_shift;
     33};
     34
     35struct mp886x_device_info {
     36	struct device *dev;
     37	struct regulator_desc desc;
     38	struct regulator_init_data *regulator;
     39	struct gpio_desc *en_gpio;
     40	const struct mp886x_cfg_info *ci;
     41	u32 r[2];
     42	unsigned int sel;
     43};
     44
     45static void mp886x_set_switch_freq(struct mp886x_device_info *di,
     46				   struct regmap *regmap,
     47				   u32 freq)
     48{
     49	const struct mp886x_cfg_info *ci = di->ci;
     50	int i;
     51
     52	for (i = 0; i < ARRAY_SIZE(ci->switch_freq); i++) {
     53		if (freq == ci->switch_freq[i]) {
     54			regmap_update_bits(regmap, ci->fs_reg,
     55				  0x3 << ci->fs_shift, i << ci->fs_shift);
     56			return;
     57		}
     58	}
     59
     60	dev_err(di->dev, "invalid frequency %d\n", freq);
     61}
     62
     63static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode)
     64{
     65	switch (mode) {
     66	case REGULATOR_MODE_FAST:
     67		regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
     68				   MP886X_MODE, MP886X_MODE);
     69		break;
     70	case REGULATOR_MODE_NORMAL:
     71		regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
     72				   MP886X_MODE, 0);
     73		break;
     74	default:
     75		return -EINVAL;
     76	}
     77	return 0;
     78}
     79
     80static unsigned int mp886x_get_mode(struct regulator_dev *rdev)
     81{
     82	u32 val;
     83	int ret;
     84
     85	ret = regmap_read(rdev->regmap, MP886X_SYSCNTLREG1, &val);
     86	if (ret < 0)
     87		return ret;
     88	if (val & MP886X_MODE)
     89		return REGULATOR_MODE_FAST;
     90	else
     91		return REGULATOR_MODE_NORMAL;
     92}
     93
     94static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
     95{
     96	int ret;
     97
     98	ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
     99				 MP886X_GO, MP886X_GO);
    100	if (ret < 0)
    101		return ret;
    102
    103	sel <<= ffs(rdev->desc->vsel_mask) - 1;
    104	return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
    105				  MP886X_V_BOOT | rdev->desc->vsel_mask, sel);
    106}
    107
    108static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2)
    109{
    110	u32 tmp = uv * r1 / r2;
    111
    112	return uv + tmp;
    113}
    114
    115static int mp8869_get_voltage_sel(struct regulator_dev *rdev)
    116{
    117	struct mp886x_device_info *di = rdev_get_drvdata(rdev);
    118	int ret, uv;
    119	unsigned int val;
    120	bool fbloop;
    121
    122	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
    123	if (ret)
    124		return ret;
    125
    126	fbloop = val & MP886X_V_BOOT;
    127	if (fbloop) {
    128		uv = rdev->desc->min_uV;
    129		uv = mp8869_scale(uv, di->r[0], di->r[1]);
    130		return regulator_map_voltage_linear(rdev, uv, uv);
    131	}
    132
    133	val &= rdev->desc->vsel_mask;
    134	val >>= ffs(rdev->desc->vsel_mask) - 1;
    135
    136	return val;
    137}
    138
    139static const struct regulator_ops mp8869_regulator_ops = {
    140	.set_voltage_sel = mp8869_set_voltage_sel,
    141	.get_voltage_sel = mp8869_get_voltage_sel,
    142	.set_voltage_time_sel = regulator_set_voltage_time_sel,
    143	.map_voltage = regulator_map_voltage_linear,
    144	.list_voltage = regulator_list_voltage_linear,
    145	.enable = regulator_enable_regmap,
    146	.disable = regulator_disable_regmap,
    147	.is_enabled = regulator_is_enabled_regmap,
    148	.set_mode = mp886x_set_mode,
    149	.get_mode = mp886x_get_mode,
    150	.set_ramp_delay = regulator_set_ramp_delay_regmap,
    151};
    152
    153static const struct mp886x_cfg_info mp8869_ci = {
    154	.rops = &mp8869_regulator_ops,
    155	.slew_rates = {
    156		40000,
    157		30000,
    158		20000,
    159		10000,
    160		5000,
    161		2500,
    162		1250,
    163		625,
    164	},
    165	.switch_freq = {
    166		500000,
    167		750000,
    168		1000000,
    169		1250000,
    170	},
    171	.fs_reg = MP8869_SYSCNTLREG2,
    172	.fs_shift = 4,
    173};
    174
    175static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
    176{
    177	struct mp886x_device_info *di = rdev_get_drvdata(rdev);
    178	int ret, delta;
    179
    180	ret = mp8869_set_voltage_sel(rdev, sel);
    181	if (ret < 0)
    182		return ret;
    183
    184	delta = di->sel - sel;
    185	if (abs(delta) <= 5)
    186		ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
    187					 MP886X_GO, 0);
    188	di->sel = sel;
    189
    190	return ret;
    191}
    192
    193static int mp8867_get_voltage_sel(struct regulator_dev *rdev)
    194{
    195	struct mp886x_device_info *di = rdev_get_drvdata(rdev);
    196	int ret, uv;
    197	unsigned int val;
    198	bool fbloop;
    199
    200	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
    201	if (ret)
    202		return ret;
    203
    204	fbloop = val & MP886X_V_BOOT;
    205
    206	val &= rdev->desc->vsel_mask;
    207	val >>= ffs(rdev->desc->vsel_mask) - 1;
    208
    209	if (fbloop) {
    210		uv = regulator_list_voltage_linear(rdev, val);
    211		uv = mp8869_scale(uv, di->r[0], di->r[1]);
    212		return regulator_map_voltage_linear(rdev, uv, uv);
    213	}
    214
    215	return val;
    216}
    217
    218static const struct regulator_ops mp8867_regulator_ops = {
    219	.set_voltage_sel = mp8867_set_voltage_sel,
    220	.get_voltage_sel = mp8867_get_voltage_sel,
    221	.set_voltage_time_sel = regulator_set_voltage_time_sel,
    222	.map_voltage = regulator_map_voltage_linear,
    223	.list_voltage = regulator_list_voltage_linear,
    224	.enable = regulator_enable_regmap,
    225	.disable = regulator_disable_regmap,
    226	.is_enabled = regulator_is_enabled_regmap,
    227	.set_mode = mp886x_set_mode,
    228	.get_mode = mp886x_get_mode,
    229	.set_ramp_delay = regulator_set_ramp_delay_regmap,
    230};
    231
    232static const struct mp886x_cfg_info mp8867_ci = {
    233	.rops = &mp8867_regulator_ops,
    234	.slew_rates = {
    235		64000,
    236		32000,
    237		16000,
    238		8000,
    239		4000,
    240		2000,
    241		1000,
    242		500,
    243	},
    244	.switch_freq = {
    245		500000,
    246		750000,
    247		1000000,
    248		1500000,
    249	},
    250	.fs_reg = MP886X_SYSCNTLREG1,
    251	.fs_shift = 1,
    252};
    253
    254static int mp886x_regulator_register(struct mp886x_device_info *di,
    255				     struct regulator_config *config)
    256{
    257	struct regulator_desc *rdesc = &di->desc;
    258	struct regulator_dev *rdev;
    259
    260	rdesc->name = "mp886x-reg";
    261	rdesc->supply_name = "vin";
    262	rdesc->ops = di->ci->rops;
    263	rdesc->type = REGULATOR_VOLTAGE;
    264	rdesc->n_voltages = 128;
    265	rdesc->enable_reg = MP886X_SYSCNTLREG1;
    266	rdesc->enable_mask = MP886X_EN;
    267	rdesc->min_uV = 600000;
    268	rdesc->uV_step = 10000;
    269	rdesc->vsel_reg = MP886X_VSEL;
    270	rdesc->vsel_mask = 0x3f;
    271	rdesc->ramp_reg = MP886X_SYSCNTLREG1;
    272	rdesc->ramp_mask = MP886X_SLEW_MASK;
    273	rdesc->ramp_delay_table = di->ci->slew_rates;
    274	rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates);
    275	rdesc->owner = THIS_MODULE;
    276
    277	rdev = devm_regulator_register(di->dev, &di->desc, config);
    278	if (IS_ERR(rdev))
    279		return PTR_ERR(rdev);
    280	di->sel = rdesc->ops->get_voltage_sel(rdev);
    281	return 0;
    282}
    283
    284static const struct regmap_config mp886x_regmap_config = {
    285	.reg_bits = 8,
    286	.val_bits = 8,
    287};
    288
    289static int mp886x_i2c_probe(struct i2c_client *client)
    290{
    291	struct device *dev = &client->dev;
    292	struct device_node *np = dev->of_node;
    293	struct mp886x_device_info *di;
    294	struct regulator_config config = { };
    295	struct regmap *regmap;
    296	u32 freq;
    297	int ret;
    298
    299	di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL);
    300	if (!di)
    301		return -ENOMEM;
    302
    303	di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
    304	if (!di->regulator) {
    305		dev_err(dev, "Platform data not found!\n");
    306		return -EINVAL;
    307	}
    308
    309	ret = of_property_read_u32_array(np, "mps,fb-voltage-divider",
    310					 di->r, 2);
    311	if (ret)
    312		return ret;
    313
    314	di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
    315	if (IS_ERR(di->en_gpio))
    316		return PTR_ERR(di->en_gpio);
    317
    318	di->ci = of_device_get_match_data(dev);
    319	di->dev = dev;
    320
    321	regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config);
    322	if (IS_ERR(regmap)) {
    323		dev_err(dev, "Failed to allocate regmap!\n");
    324		return PTR_ERR(regmap);
    325	}
    326	i2c_set_clientdata(client, di);
    327
    328	config.dev = di->dev;
    329	config.init_data = di->regulator;
    330	config.regmap = regmap;
    331	config.driver_data = di;
    332	config.of_node = np;
    333
    334	if (!of_property_read_u32(np, "mps,switch-frequency-hz", &freq))
    335		mp886x_set_switch_freq(di, regmap, freq);
    336
    337	ret = mp886x_regulator_register(di, &config);
    338	if (ret < 0)
    339		dev_err(dev, "Failed to register regulator!\n");
    340	return ret;
    341}
    342
    343static const struct of_device_id mp886x_dt_ids[] = {
    344	{
    345		.compatible = "mps,mp8867",
    346		.data = &mp8867_ci
    347	},
    348	{
    349		.compatible = "mps,mp8869",
    350		.data = &mp8869_ci
    351	},
    352	{ }
    353};
    354MODULE_DEVICE_TABLE(of, mp886x_dt_ids);
    355
    356static const struct i2c_device_id mp886x_id[] = {
    357	{ "mp886x", },
    358	{ },
    359};
    360MODULE_DEVICE_TABLE(i2c, mp886x_id);
    361
    362static struct i2c_driver mp886x_regulator_driver = {
    363	.driver = {
    364		.name = "mp886x-regulator",
    365		.of_match_table = of_match_ptr(mp886x_dt_ids),
    366	},
    367	.probe_new = mp886x_i2c_probe,
    368	.id_table = mp886x_id,
    369};
    370module_i2c_driver(mp886x_regulator_driver);
    371
    372MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
    373MODULE_DESCRIPTION("MP886x regulator driver");
    374MODULE_LICENSE("GPL v2");