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

lochnagar-regulator.c (7388B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Lochnagar regulator driver
      4//
      5// Copyright (c) 2017-2018 Cirrus Logic, Inc. and
      6//                         Cirrus Logic International Semiconductor Ltd.
      7//
      8// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
      9
     10#include <linux/bitops.h>
     11#include <linux/device.h>
     12#include <linux/err.h>
     13#include <linux/module.h>
     14#include <linux/mutex.h>
     15#include <linux/of.h>
     16#include <linux/of_device.h>
     17#include <linux/platform_device.h>
     18#include <linux/regmap.h>
     19#include <linux/regulator/driver.h>
     20#include <linux/regulator/machine.h>
     21#include <linux/regulator/of_regulator.h>
     22
     23#include <linux/mfd/lochnagar.h>
     24#include <linux/mfd/lochnagar1_regs.h>
     25#include <linux/mfd/lochnagar2_regs.h>
     26
     27static const struct regulator_ops lochnagar_micvdd_ops = {
     28	.enable = regulator_enable_regmap,
     29	.disable = regulator_disable_regmap,
     30	.is_enabled = regulator_is_enabled_regmap,
     31
     32	.list_voltage = regulator_list_voltage_linear_range,
     33	.map_voltage = regulator_map_voltage_linear_range,
     34
     35	.get_voltage_sel = regulator_get_voltage_sel_regmap,
     36	.set_voltage_sel = regulator_set_voltage_sel_regmap,
     37};
     38
     39static const struct linear_range lochnagar_micvdd_ranges[] = {
     40	REGULATOR_LINEAR_RANGE(1000000, 0,    0xC, 50000),
     41	REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
     42};
     43
     44static int lochnagar_micbias_enable(struct regulator_dev *rdev)
     45{
     46	struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
     47	int ret;
     48
     49	mutex_lock(&lochnagar->analogue_config_lock);
     50
     51	ret = regulator_enable_regmap(rdev);
     52	if (ret < 0)
     53		goto err;
     54
     55	ret = lochnagar_update_config(lochnagar);
     56
     57err:
     58	mutex_unlock(&lochnagar->analogue_config_lock);
     59
     60	return ret;
     61}
     62
     63static int lochnagar_micbias_disable(struct regulator_dev *rdev)
     64{
     65	struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
     66	int ret;
     67
     68	mutex_lock(&lochnagar->analogue_config_lock);
     69
     70	ret = regulator_disable_regmap(rdev);
     71	if (ret < 0)
     72		goto err;
     73
     74	ret = lochnagar_update_config(lochnagar);
     75
     76err:
     77	mutex_unlock(&lochnagar->analogue_config_lock);
     78
     79	return ret;
     80}
     81
     82static const struct regulator_ops lochnagar_micbias_ops = {
     83	.enable = lochnagar_micbias_enable,
     84	.disable = lochnagar_micbias_disable,
     85	.is_enabled = regulator_is_enabled_regmap,
     86};
     87
     88static const struct regulator_ops lochnagar_vddcore_ops = {
     89	.enable = regulator_enable_regmap,
     90	.disable = regulator_disable_regmap,
     91	.is_enabled = regulator_is_enabled_regmap,
     92
     93	.list_voltage = regulator_list_voltage_linear_range,
     94	.map_voltage = regulator_map_voltage_linear_range,
     95
     96	.get_voltage_sel = regulator_get_voltage_sel_regmap,
     97	.set_voltage_sel = regulator_set_voltage_sel_regmap,
     98};
     99
    100static const struct linear_range lochnagar_vddcore_ranges[] = {
    101	REGULATOR_LINEAR_RANGE(600000, 0,    0x7, 0),
    102	REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
    103};
    104
    105enum lochnagar_regulators {
    106	LOCHNAGAR_MICVDD,
    107	LOCHNAGAR_MIC1VDD,
    108	LOCHNAGAR_MIC2VDD,
    109	LOCHNAGAR_VDDCORE,
    110};
    111
    112static int lochnagar_micbias_of_parse(struct device_node *np,
    113				      const struct regulator_desc *desc,
    114				      struct regulator_config *config)
    115{
    116	struct lochnagar *lochnagar = config->driver_data;
    117	int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
    118		    LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
    119	int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
    120	unsigned int val;
    121	int ret;
    122
    123	ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
    124	if (ret >= 0) {
    125		mutex_lock(&lochnagar->analogue_config_lock);
    126		ret = regmap_update_bits(lochnagar->regmap,
    127					 LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
    128					 mask, val << shift);
    129		mutex_unlock(&lochnagar->analogue_config_lock);
    130		if (ret < 0) {
    131			dev_err(lochnagar->dev,
    132				"Failed to update micbias source: %d\n", ret);
    133			return ret;
    134		}
    135	}
    136
    137	return 0;
    138}
    139
    140static const struct regulator_desc lochnagar_regulators[] = {
    141	[LOCHNAGAR_MICVDD] = {
    142		.name = "MICVDD",
    143		.supply_name = "SYSVDD",
    144		.type = REGULATOR_VOLTAGE,
    145		.n_voltages = 32,
    146		.ops = &lochnagar_micvdd_ops,
    147
    148		.id = LOCHNAGAR_MICVDD,
    149		.of_match = of_match_ptr("MICVDD"),
    150
    151		.enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
    152		.enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
    153		.vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
    154		.vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
    155
    156		.linear_ranges = lochnagar_micvdd_ranges,
    157		.n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
    158
    159		.enable_time = 3000,
    160		.ramp_delay = 1000,
    161
    162		.owner = THIS_MODULE,
    163	},
    164	[LOCHNAGAR_MIC1VDD] = {
    165		.name = "MIC1VDD",
    166		.supply_name = "MICBIAS1",
    167		.type = REGULATOR_VOLTAGE,
    168		.ops = &lochnagar_micbias_ops,
    169
    170		.id = LOCHNAGAR_MIC1VDD,
    171		.of_match = of_match_ptr("MIC1VDD"),
    172		.of_parse_cb = lochnagar_micbias_of_parse,
    173
    174		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
    175		.enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
    176
    177		.owner = THIS_MODULE,
    178	},
    179	[LOCHNAGAR_MIC2VDD] = {
    180		.name = "MIC2VDD",
    181		.supply_name = "MICBIAS2",
    182		.type = REGULATOR_VOLTAGE,
    183		.ops = &lochnagar_micbias_ops,
    184
    185		.id = LOCHNAGAR_MIC2VDD,
    186		.of_match = of_match_ptr("MIC2VDD"),
    187		.of_parse_cb = lochnagar_micbias_of_parse,
    188
    189		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
    190		.enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
    191
    192		.owner = THIS_MODULE,
    193	},
    194	[LOCHNAGAR_VDDCORE] = {
    195		.name = "VDDCORE",
    196		.supply_name = "SYSVDD",
    197		.type = REGULATOR_VOLTAGE,
    198		.n_voltages = 66,
    199		.ops = &lochnagar_vddcore_ops,
    200
    201		.id = LOCHNAGAR_VDDCORE,
    202		.of_match = of_match_ptr("VDDCORE"),
    203
    204		.enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
    205		.enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
    206		.vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
    207		.vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
    208
    209		.linear_ranges = lochnagar_vddcore_ranges,
    210		.n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
    211
    212		.enable_time = 3000,
    213		.ramp_delay = 1000,
    214		.off_on_delay = 15000,
    215
    216		.owner = THIS_MODULE,
    217	},
    218};
    219
    220static const struct of_device_id lochnagar_of_match[] = {
    221	{
    222		.compatible = "cirrus,lochnagar2-micvdd",
    223		.data = &lochnagar_regulators[LOCHNAGAR_MICVDD],
    224	},
    225	{
    226		.compatible = "cirrus,lochnagar2-mic1vdd",
    227		.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
    228	},
    229	{
    230		.compatible = "cirrus,lochnagar2-mic2vdd",
    231		.data = &lochnagar_regulators[LOCHNAGAR_MIC2VDD],
    232	},
    233	{
    234		.compatible = "cirrus,lochnagar2-vddcore",
    235		.data = &lochnagar_regulators[LOCHNAGAR_VDDCORE],
    236	},
    237	{}
    238};
    239MODULE_DEVICE_TABLE(of, lochnagar_of_match);
    240
    241static int lochnagar_regulator_probe(struct platform_device *pdev)
    242{
    243	struct device *dev = &pdev->dev;
    244	struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
    245	struct regulator_config config = { };
    246	const struct of_device_id *of_id;
    247	const struct regulator_desc *desc;
    248	struct regulator_dev *rdev;
    249	int ret;
    250
    251	config.dev = dev;
    252	config.regmap = lochnagar->regmap;
    253	config.driver_data = lochnagar;
    254
    255	of_id = of_match_device(lochnagar_of_match, dev);
    256	if (!of_id)
    257		return -EINVAL;
    258
    259	desc = of_id->data;
    260
    261	rdev = devm_regulator_register(dev, desc, &config);
    262	if (IS_ERR(rdev)) {
    263		ret = PTR_ERR(rdev);
    264		dev_err(dev, "Failed to register %s regulator: %d\n",
    265			desc->name, ret);
    266		return ret;
    267	}
    268
    269	return 0;
    270}
    271
    272static struct platform_driver lochnagar_regulator_driver = {
    273	.driver = {
    274		.name = "lochnagar-regulator",
    275		.of_match_table = of_match_ptr(lochnagar_of_match),
    276	},
    277
    278	.probe = lochnagar_regulator_probe,
    279};
    280module_platform_driver(lochnagar_regulator_driver);
    281
    282MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
    283MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
    284MODULE_LICENSE("GPL v2");
    285MODULE_ALIAS("platform:lochnagar-regulator");