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

da9210-regulator.c (6309B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// da9210-regulator.c - Regulator device driver for DA9210
      4// Copyright (C) 2013  Dialog Semiconductor Ltd.
      5
      6#include <linux/err.h>
      7#include <linux/i2c.h>
      8#include <linux/module.h>
      9#include <linux/interrupt.h>
     10#include <linux/irq.h>
     11#include <linux/regulator/driver.h>
     12#include <linux/regulator/machine.h>
     13#include <linux/of_device.h>
     14#include <linux/regulator/of_regulator.h>
     15#include <linux/regmap.h>
     16
     17#include "da9210-regulator.h"
     18
     19struct da9210 {
     20	struct regulator_dev *rdev;
     21	struct regmap *regmap;
     22};
     23
     24static const struct regmap_config da9210_regmap_config = {
     25	.reg_bits = 8,
     26	.val_bits = 8,
     27};
     28
     29static const struct regulator_ops da9210_buck_ops = {
     30	.enable = regulator_enable_regmap,
     31	.disable = regulator_disable_regmap,
     32	.is_enabled = regulator_is_enabled_regmap,
     33	.set_voltage_sel = regulator_set_voltage_sel_regmap,
     34	.get_voltage_sel = regulator_get_voltage_sel_regmap,
     35	.list_voltage = regulator_list_voltage_linear,
     36	.set_current_limit = regulator_set_current_limit_regmap,
     37	.get_current_limit = regulator_get_current_limit_regmap,
     38};
     39
     40/* Default limits measured in millivolts and milliamps */
     41#define DA9210_MIN_MV		300
     42#define DA9210_MAX_MV		1570
     43#define DA9210_STEP_MV		10
     44
     45/* Current limits for buck (uA) indices corresponds with register values */
     46static const unsigned int da9210_buck_limits[] = {
     47	1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000,
     48	3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000
     49};
     50
     51static const struct regulator_desc da9210_reg = {
     52	.name = "DA9210",
     53	.id = 0,
     54	.ops = &da9210_buck_ops,
     55	.type = REGULATOR_VOLTAGE,
     56	.n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1,
     57	.min_uV = (DA9210_MIN_MV * 1000),
     58	.uV_step = (DA9210_STEP_MV * 1000),
     59	.vsel_reg = DA9210_REG_VBUCK_A,
     60	.vsel_mask = DA9210_VBUCK_MASK,
     61	.enable_reg = DA9210_REG_BUCK_CONT,
     62	.enable_mask = DA9210_BUCK_EN,
     63	.owner = THIS_MODULE,
     64	.curr_table = da9210_buck_limits,
     65	.n_current_limits = ARRAY_SIZE(da9210_buck_limits),
     66	.csel_reg = DA9210_REG_BUCK_ILIM,
     67	.csel_mask = DA9210_BUCK_ILIM_MASK,
     68};
     69
     70static irqreturn_t da9210_irq_handler(int irq, void *data)
     71{
     72	struct da9210 *chip = data;
     73	unsigned int val, handled = 0;
     74	int error, ret = IRQ_NONE;
     75
     76	error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val);
     77	if (error < 0)
     78		goto error_i2c;
     79
     80	if (val & DA9210_E_OVCURR) {
     81		regulator_notifier_call_chain(chip->rdev,
     82					      REGULATOR_EVENT_OVER_CURRENT,
     83					      NULL);
     84		handled |= DA9210_E_OVCURR;
     85	}
     86	if (val & DA9210_E_NPWRGOOD) {
     87		regulator_notifier_call_chain(chip->rdev,
     88					      REGULATOR_EVENT_UNDER_VOLTAGE,
     89					      NULL);
     90		handled |= DA9210_E_NPWRGOOD;
     91	}
     92	if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) {
     93		regulator_notifier_call_chain(chip->rdev,
     94					      REGULATOR_EVENT_OVER_TEMP, NULL);
     95		handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT);
     96	}
     97	if (val & DA9210_E_VMAX) {
     98		regulator_notifier_call_chain(chip->rdev,
     99					      REGULATOR_EVENT_REGULATION_OUT,
    100					      NULL);
    101		handled |= DA9210_E_VMAX;
    102	}
    103
    104	if (handled) {
    105		/* Clear handled events */
    106		error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled);
    107		if (error < 0)
    108			goto error_i2c;
    109
    110		ret = IRQ_HANDLED;
    111	}
    112
    113	return ret;
    114
    115error_i2c:
    116	dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error);
    117	return ret;
    118}
    119
    120/*
    121 * I2C driver interface functions
    122 */
    123
    124static const struct of_device_id __maybe_unused da9210_dt_ids[] = {
    125	{ .compatible = "dlg,da9210", },
    126	{ }
    127};
    128MODULE_DEVICE_TABLE(of, da9210_dt_ids);
    129
    130static int da9210_i2c_probe(struct i2c_client *i2c)
    131{
    132	struct da9210 *chip;
    133	struct device *dev = &i2c->dev;
    134	struct da9210_pdata *pdata = dev_get_platdata(dev);
    135	struct regulator_dev *rdev = NULL;
    136	struct regulator_config config = { };
    137	int error;
    138	const struct of_device_id *match;
    139
    140	if (i2c->dev.of_node && !pdata) {
    141		match = of_match_device(of_match_ptr(da9210_dt_ids),
    142						&i2c->dev);
    143		if (!match) {
    144			dev_err(&i2c->dev, "Error: No device match found\n");
    145			return -ENODEV;
    146		}
    147	}
    148
    149	chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
    150	if (!chip)
    151		return -ENOMEM;
    152
    153	chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
    154	if (IS_ERR(chip->regmap)) {
    155		error = PTR_ERR(chip->regmap);
    156		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
    157			error);
    158		return error;
    159	}
    160
    161	config.dev = &i2c->dev;
    162	config.init_data = pdata ? &pdata->da9210_constraints :
    163		of_get_regulator_init_data(dev, dev->of_node, &da9210_reg);
    164	config.driver_data = chip;
    165	config.regmap = chip->regmap;
    166	config.of_node = dev->of_node;
    167
    168	/* Mask all interrupt sources to deassert interrupt line */
    169	error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0);
    170	if (!error)
    171		error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0);
    172	if (error) {
    173		dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error);
    174		return error;
    175	}
    176
    177	rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);
    178	if (IS_ERR(rdev)) {
    179		dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
    180		return PTR_ERR(rdev);
    181	}
    182
    183	chip->rdev = rdev;
    184	if (i2c->irq) {
    185		error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
    186						  da9210_irq_handler,
    187						  IRQF_TRIGGER_LOW |
    188						  IRQF_ONESHOT | IRQF_SHARED,
    189						  "da9210", chip);
    190		if (error) {
    191			dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n",
    192				i2c->irq, error);
    193			return error;
    194		}
    195
    196		error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B,
    197					 DA9210_M_OVCURR | DA9210_M_NPWRGOOD |
    198					 DA9210_M_TEMP_WARN |
    199					 DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0);
    200		if (error < 0) {
    201			dev_err(&i2c->dev, "Failed to update mask reg: %d\n",
    202				error);
    203			return error;
    204		}
    205	} else {
    206		dev_warn(&i2c->dev, "No IRQ configured\n");
    207	}
    208
    209	i2c_set_clientdata(i2c, chip);
    210
    211	return 0;
    212}
    213
    214static const struct i2c_device_id da9210_i2c_id[] = {
    215	{"da9210", 0},
    216	{},
    217};
    218
    219MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);
    220
    221static struct i2c_driver da9210_regulator_driver = {
    222	.driver = {
    223		.name = "da9210",
    224		.of_match_table = of_match_ptr(da9210_dt_ids),
    225	},
    226	.probe_new = da9210_i2c_probe,
    227	.id_table = da9210_i2c_id,
    228};
    229
    230module_i2c_driver(da9210_regulator_driver);
    231
    232MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
    233MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210");
    234MODULE_LICENSE("GPL v2");