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

max20086-regulator.c (8107B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2//
      3// max20086-regulator.c - MAX20086-MAX20089 camera power protector driver
      4//
      5// Copyright (C) 2022 Laurent Pinchart <laurent.pinchart@idesonboard.com>
      6// Copyright (C) 2018 Avnet, Inc.
      7
      8#include <linux/err.h>
      9#include <linux/gpio.h>
     10#include <linux/gpio/consumer.h>
     11#include <linux/i2c.h>
     12#include <linux/module.h>
     13#include <linux/regmap.h>
     14#include <linux/regulator/driver.h>
     15#include <linux/regulator/machine.h>
     16#include <linux/regulator/of_regulator.h>
     17#include <linux/slab.h>
     18
     19/* Register Offset */
     20#define MAX20086_REG_MASK		0x00
     21#define MAX20086_REG_CONFIG		0x01
     22#define	MAX20086_REG_ID			0x02
     23#define	MAX20086_REG_STAT1		0x03
     24#define	MAX20086_REG_STAT2_L		0x04
     25#define	MAX20086_REG_STAT2_H		0x05
     26#define	MAX20086_REG_ADC1		0x06
     27#define	MAX20086_REG_ADC2		0x07
     28#define	MAX20086_REG_ADC3		0x08
     29#define	MAX20086_REG_ADC4		0x09
     30
     31/* DEVICE IDs */
     32#define MAX20086_DEVICE_ID_MAX20086	0x40
     33#define MAX20086_DEVICE_ID_MAX20087	0x20
     34#define MAX20086_DEVICE_ID_MAX20088	0x10
     35#define MAX20086_DEVICE_ID_MAX20089	0x00
     36#define DEVICE_ID_MASK			0xf0
     37
     38/* Register bits */
     39#define MAX20086_EN_MASK		0x0f
     40#define MAX20086_EN_OUT1		0x01
     41#define MAX20086_EN_OUT2		0x02
     42#define MAX20086_EN_OUT3		0x04
     43#define MAX20086_EN_OUT4		0x08
     44#define MAX20086_INT_DISABLE_ALL	0x3f
     45
     46#define MAX20086_MAX_REGULATORS		4
     47
     48struct max20086_chip_info {
     49	u8 id;
     50	unsigned int num_outputs;
     51};
     52
     53struct max20086_regulator {
     54	struct device_node *of_node;
     55	struct regulator_init_data *init_data;
     56	const struct regulator_desc *desc;
     57	struct regulator_dev *rdev;
     58};
     59
     60struct max20086 {
     61	struct device *dev;
     62	struct regmap *regmap;
     63	struct gpio_desc *ena_gpiod;
     64
     65	const struct max20086_chip_info *info;
     66
     67	struct max20086_regulator regulators[MAX20086_MAX_REGULATORS];
     68};
     69
     70static const struct regulator_ops max20086_buck_ops = {
     71	.enable = regulator_enable_regmap,
     72	.disable = regulator_disable_regmap,
     73	.is_enabled = regulator_is_enabled_regmap,
     74};
     75
     76#define MAX20086_REGULATOR_DESC(n)		\
     77{						\
     78	.name = "OUT"#n,			\
     79	.supply_name = "in",			\
     80	.id = (n) - 1,				\
     81	.ops = &max20086_buck_ops,		\
     82	.type = REGULATOR_VOLTAGE,		\
     83	.owner = THIS_MODULE,			\
     84	.enable_reg = MAX20086_REG_CONFIG,	\
     85	.enable_mask = 1 << ((n) - 1),		\
     86	.enable_val = 1 << ((n) - 1),		\
     87	.disable_val = 0,			\
     88}
     89
     90static const char * const max20086_output_names[] = {
     91	"OUT1",
     92	"OUT2",
     93	"OUT3",
     94	"OUT4",
     95};
     96
     97static const struct regulator_desc max20086_regulators[] = {
     98	MAX20086_REGULATOR_DESC(1),
     99	MAX20086_REGULATOR_DESC(2),
    100	MAX20086_REGULATOR_DESC(3),
    101	MAX20086_REGULATOR_DESC(4),
    102};
    103
    104static int max20086_regulators_register(struct max20086 *chip)
    105{
    106	unsigned int i;
    107
    108	for (i = 0; i < chip->info->num_outputs; i++) {
    109		struct max20086_regulator *reg = &chip->regulators[i];
    110		struct regulator_config config = { };
    111		struct regulator_dev *rdev;
    112
    113		config.dev = chip->dev;
    114		config.init_data = reg->init_data;
    115		config.driver_data = chip;
    116		config.of_node = reg->of_node;
    117		config.regmap = chip->regmap;
    118		config.ena_gpiod = chip->ena_gpiod;
    119
    120		rdev = devm_regulator_register(chip->dev, reg->desc, &config);
    121		if (IS_ERR(rdev)) {
    122			dev_err(chip->dev,
    123				"Failed to register regulator output %s\n",
    124				reg->desc->name);
    125			return PTR_ERR(rdev);
    126		}
    127
    128		reg->rdev = rdev;
    129	}
    130
    131	return 0;
    132}
    133
    134static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
    135{
    136	struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { };
    137	struct device_node *node;
    138	unsigned int i;
    139	int ret;
    140
    141	node = of_get_child_by_name(chip->dev->of_node, "regulators");
    142	if (!node) {
    143		dev_err(chip->dev, "regulators node not found\n");
    144		return -ENODEV;
    145	}
    146
    147	for (i = 0; i < chip->info->num_outputs; ++i)
    148		matches[i].name = max20086_output_names[i];
    149
    150	ret = of_regulator_match(chip->dev, node, matches,
    151				 chip->info->num_outputs);
    152	of_node_put(node);
    153	if (ret < 0) {
    154		dev_err(chip->dev, "Failed to match regulators\n");
    155		return -EINVAL;
    156	}
    157
    158	*boot_on = false;
    159
    160	for (i = 0; i < chip->info->num_outputs; i++) {
    161		struct max20086_regulator *reg = &chip->regulators[i];
    162
    163		reg->init_data = matches[i].init_data;
    164		reg->of_node = matches[i].of_node;
    165		reg->desc = &max20086_regulators[i];
    166
    167		if (reg->init_data) {
    168			if (reg->init_data->constraints.always_on ||
    169			    reg->init_data->constraints.boot_on)
    170				*boot_on = true;
    171		}
    172	}
    173
    174	return 0;
    175}
    176
    177static int max20086_detect(struct max20086 *chip)
    178{
    179	unsigned int data;
    180	int ret;
    181
    182	ret = regmap_read(chip->regmap, MAX20086_REG_ID, &data);
    183	if (ret < 0) {
    184		dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret);
    185		return ret;
    186	}
    187
    188	if ((data & DEVICE_ID_MASK) != chip->info->id) {
    189		dev_err(chip->dev, "Invalid device ID 0x%02x\n", data);
    190		return -ENXIO;
    191	}
    192
    193	return 0;
    194}
    195
    196static bool max20086_gen_is_writeable_reg(struct device *dev, unsigned int reg)
    197{
    198	switch (reg) {
    199	case MAX20086_REG_MASK:
    200	case MAX20086_REG_CONFIG:
    201		return true;
    202	default:
    203		return false;
    204	}
    205}
    206
    207static const struct regmap_config max20086_regmap_config = {
    208	.reg_bits = 8,
    209	.val_bits = 8,
    210	.writeable_reg = max20086_gen_is_writeable_reg,
    211	.max_register = 0x9,
    212	.cache_type = REGCACHE_NONE,
    213};
    214
    215static int max20086_i2c_probe(struct i2c_client *i2c)
    216{
    217	struct max20086 *chip;
    218	enum gpiod_flags flags;
    219	bool boot_on;
    220	int ret;
    221
    222	chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
    223	if (!chip)
    224		return -ENOMEM;
    225
    226	chip->dev = &i2c->dev;
    227	chip->info = device_get_match_data(chip->dev);
    228
    229	i2c_set_clientdata(i2c, chip);
    230
    231	chip->regmap = devm_regmap_init_i2c(i2c, &max20086_regmap_config);
    232	if (IS_ERR(chip->regmap)) {
    233		ret = PTR_ERR(chip->regmap);
    234		dev_err(chip->dev, "Failed to allocate register map: %d\n", ret);
    235		return ret;
    236	}
    237
    238	ret = max20086_parse_regulators_dt(chip, &boot_on);
    239	if (ret < 0)
    240		return ret;
    241
    242	ret = max20086_detect(chip);
    243	if (ret < 0)
    244		return ret;
    245
    246	/* Until IRQ support is added, just disable all interrupts. */
    247	ret = regmap_update_bits(chip->regmap, MAX20086_REG_MASK,
    248				 MAX20086_INT_DISABLE_ALL,
    249				 MAX20086_INT_DISABLE_ALL);
    250	if (ret < 0) {
    251		dev_err(chip->dev, "Failed to disable interrupts: %d\n", ret);
    252		return ret;
    253	}
    254
    255	/*
    256	 * Get the enable GPIO. If any of the outputs is marked as being
    257	 * enabled at boot, request the GPIO with an initial high state to
    258	 * avoid disabling outputs that may have been turned on by the boot
    259	 * loader. Otherwise, request it with a low state to enter lower-power
    260	 * shutdown.
    261	 */
    262	flags = boot_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
    263	chip->ena_gpiod = devm_gpiod_get(chip->dev, "enable", flags);
    264	if (IS_ERR(chip->ena_gpiod)) {
    265		ret = PTR_ERR(chip->ena_gpiod);
    266		dev_err(chip->dev, "Failed to get enable GPIO: %d\n", ret);
    267		return ret;
    268	}
    269
    270	ret = max20086_regulators_register(chip);
    271	if (ret < 0) {
    272		dev_err(chip->dev, "Failed to register regulators: %d\n", ret);
    273		return ret;
    274	}
    275
    276	return 0;
    277}
    278
    279static const struct i2c_device_id max20086_i2c_id[] = {
    280	{ "max20086" },
    281	{ "max20087" },
    282	{ "max20088" },
    283	{ "max20089" },
    284	{ /* Sentinel */ },
    285};
    286
    287MODULE_DEVICE_TABLE(i2c, max20086_i2c_id);
    288
    289static const struct of_device_id max20086_dt_ids[] = {
    290	{
    291		.compatible = "maxim,max20086",
    292		.data = &(const struct max20086_chip_info) {
    293			.id = MAX20086_DEVICE_ID_MAX20086,
    294			.num_outputs = 4,
    295		}
    296	}, {
    297		.compatible = "maxim,max20087",
    298		.data = &(const struct max20086_chip_info) {
    299			.id = MAX20086_DEVICE_ID_MAX20087,
    300			.num_outputs = 4,
    301		}
    302	}, {
    303		.compatible = "maxim,max20088",
    304		.data = &(const struct max20086_chip_info) {
    305			.id = MAX20086_DEVICE_ID_MAX20088,
    306			.num_outputs = 2,
    307		}
    308	}, {
    309		.compatible = "maxim,max20089",
    310		.data = &(const struct max20086_chip_info) {
    311			.id = MAX20086_DEVICE_ID_MAX20089,
    312			.num_outputs = 2,
    313		}
    314	},
    315	{ /* Sentinel */ },
    316};
    317
    318MODULE_DEVICE_TABLE(of, max20086_dt_ids);
    319
    320static struct i2c_driver max20086_regulator_driver = {
    321	.driver = {
    322		.name = "max20086",
    323		.of_match_table = of_match_ptr(max20086_dt_ids),
    324	},
    325	.probe_new = max20086_i2c_probe,
    326	.id_table = max20086_i2c_id,
    327};
    328
    329module_i2c_driver(max20086_regulator_driver);
    330
    331MODULE_AUTHOR("Watson Chow <watson.chow@avnet.com>");
    332MODULE_DESCRIPTION("MAX20086-MAX20089 Camera Power Protector Driver");
    333MODULE_LICENSE("GPL");