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

pwm-regulator.c (10754B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Regulator driver for PWM Regulators
      4 *
      5 * Copyright (C) 2014 - STMicroelectronics Inc.
      6 *
      7 * Author: Lee Jones <lee.jones@linaro.org>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/init.h>
     12#include <linux/err.h>
     13#include <linux/regulator/driver.h>
     14#include <linux/regulator/machine.h>
     15#include <linux/regulator/of_regulator.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18#include <linux/pwm.h>
     19#include <linux/gpio/consumer.h>
     20
     21struct pwm_continuous_reg_data {
     22	unsigned int min_uV_dutycycle;
     23	unsigned int max_uV_dutycycle;
     24	unsigned int dutycycle_unit;
     25};
     26
     27struct pwm_regulator_data {
     28	/*  Shared */
     29	struct pwm_device *pwm;
     30
     31	/* Voltage table */
     32	struct pwm_voltages *duty_cycle_table;
     33
     34	/* Continuous mode info */
     35	struct pwm_continuous_reg_data continuous;
     36
     37	/* regulator descriptor */
     38	struct regulator_desc desc;
     39
     40	int state;
     41
     42	/* Enable GPIO */
     43	struct gpio_desc *enb_gpio;
     44};
     45
     46struct pwm_voltages {
     47	unsigned int uV;
     48	unsigned int dutycycle;
     49};
     50
     51/*
     52 * Voltage table call-backs
     53 */
     54static void pwm_regulator_init_state(struct regulator_dev *rdev)
     55{
     56	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
     57	struct pwm_state pwm_state;
     58	unsigned int dutycycle;
     59	int i;
     60
     61	pwm_get_state(drvdata->pwm, &pwm_state);
     62	dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);
     63
     64	for (i = 0; i < rdev->desc->n_voltages; i++) {
     65		if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {
     66			drvdata->state = i;
     67			return;
     68		}
     69	}
     70}
     71
     72static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
     73{
     74	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
     75
     76	if (drvdata->state < 0)
     77		pwm_regulator_init_state(rdev);
     78
     79	return drvdata->state;
     80}
     81
     82static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
     83					 unsigned selector)
     84{
     85	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
     86	struct pwm_state pstate;
     87	int ret;
     88
     89	pwm_init_state(drvdata->pwm, &pstate);
     90	pwm_set_relative_duty_cycle(&pstate,
     91			drvdata->duty_cycle_table[selector].dutycycle, 100);
     92
     93	ret = pwm_apply_state(drvdata->pwm, &pstate);
     94	if (ret) {
     95		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
     96		return ret;
     97	}
     98
     99	drvdata->state = selector;
    100
    101	return 0;
    102}
    103
    104static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
    105				      unsigned selector)
    106{
    107	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
    108
    109	if (selector >= rdev->desc->n_voltages)
    110		return -EINVAL;
    111
    112	return drvdata->duty_cycle_table[selector].uV;
    113}
    114
    115static int pwm_regulator_enable(struct regulator_dev *dev)
    116{
    117	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
    118
    119	gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
    120
    121	return pwm_enable(drvdata->pwm);
    122}
    123
    124static int pwm_regulator_disable(struct regulator_dev *dev)
    125{
    126	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
    127
    128	pwm_disable(drvdata->pwm);
    129
    130	gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
    131
    132	return 0;
    133}
    134
    135static int pwm_regulator_is_enabled(struct regulator_dev *dev)
    136{
    137	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
    138
    139	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
    140		return false;
    141
    142	return pwm_is_enabled(drvdata->pwm);
    143}
    144
    145static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
    146{
    147	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
    148	unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
    149	unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
    150	unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
    151	int min_uV = rdev->constraints->min_uV;
    152	int max_uV = rdev->constraints->max_uV;
    153	int diff_uV = max_uV - min_uV;
    154	struct pwm_state pstate;
    155	unsigned int diff_duty;
    156	unsigned int voltage;
    157
    158	pwm_get_state(drvdata->pwm, &pstate);
    159
    160	voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);
    161
    162	/*
    163	 * The dutycycle for min_uV might be greater than the one for max_uV.
    164	 * This is happening when the user needs an inversed polarity, but the
    165	 * PWM device does not support inversing it in hardware.
    166	 */
    167	if (max_uV_duty < min_uV_duty) {
    168		voltage = min_uV_duty - voltage;
    169		diff_duty = min_uV_duty - max_uV_duty;
    170	} else {
    171		voltage = voltage - min_uV_duty;
    172		diff_duty = max_uV_duty - min_uV_duty;
    173	}
    174
    175	voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);
    176
    177	return voltage + min_uV;
    178}
    179
    180static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
    181				     int req_min_uV, int req_max_uV,
    182				     unsigned int *selector)
    183{
    184	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
    185	unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
    186	unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
    187	unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
    188	int min_uV = rdev->constraints->min_uV;
    189	int max_uV = rdev->constraints->max_uV;
    190	int diff_uV = max_uV - min_uV;
    191	struct pwm_state pstate;
    192	unsigned int diff_duty;
    193	unsigned int dutycycle;
    194	int ret;
    195
    196	pwm_init_state(drvdata->pwm, &pstate);
    197
    198	/*
    199	 * The dutycycle for min_uV might be greater than the one for max_uV.
    200	 * This is happening when the user needs an inversed polarity, but the
    201	 * PWM device does not support inversing it in hardware.
    202	 */
    203	if (max_uV_duty < min_uV_duty)
    204		diff_duty = min_uV_duty - max_uV_duty;
    205	else
    206		diff_duty = max_uV_duty - min_uV_duty;
    207
    208	dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *
    209					  diff_duty,
    210					  diff_uV);
    211
    212	if (max_uV_duty < min_uV_duty)
    213		dutycycle = min_uV_duty - dutycycle;
    214	else
    215		dutycycle = min_uV_duty + dutycycle;
    216
    217	pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
    218
    219	ret = pwm_apply_state(drvdata->pwm, &pstate);
    220	if (ret) {
    221		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
    222		return ret;
    223	}
    224
    225	return 0;
    226}
    227
    228static const struct regulator_ops pwm_regulator_voltage_table_ops = {
    229	.set_voltage_sel = pwm_regulator_set_voltage_sel,
    230	.get_voltage_sel = pwm_regulator_get_voltage_sel,
    231	.list_voltage    = pwm_regulator_list_voltage,
    232	.map_voltage     = regulator_map_voltage_iterate,
    233	.enable          = pwm_regulator_enable,
    234	.disable         = pwm_regulator_disable,
    235	.is_enabled      = pwm_regulator_is_enabled,
    236};
    237
    238static const struct regulator_ops pwm_regulator_voltage_continuous_ops = {
    239	.get_voltage = pwm_regulator_get_voltage,
    240	.set_voltage = pwm_regulator_set_voltage,
    241	.enable          = pwm_regulator_enable,
    242	.disable         = pwm_regulator_disable,
    243	.is_enabled      = pwm_regulator_is_enabled,
    244};
    245
    246static const struct regulator_desc pwm_regulator_desc = {
    247	.name		= "pwm-regulator",
    248	.type		= REGULATOR_VOLTAGE,
    249	.owner		= THIS_MODULE,
    250	.supply_name    = "pwm",
    251};
    252
    253static int pwm_regulator_init_table(struct platform_device *pdev,
    254				    struct pwm_regulator_data *drvdata)
    255{
    256	struct device_node *np = pdev->dev.of_node;
    257	struct pwm_voltages *duty_cycle_table;
    258	unsigned int length = 0;
    259	int ret;
    260
    261	of_find_property(np, "voltage-table", &length);
    262
    263	if ((length < sizeof(*duty_cycle_table)) ||
    264	    (length % sizeof(*duty_cycle_table))) {
    265		dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
    266			length);
    267		return -EINVAL;
    268	}
    269
    270	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
    271	if (!duty_cycle_table)
    272		return -ENOMEM;
    273
    274	ret = of_property_read_u32_array(np, "voltage-table",
    275					 (u32 *)duty_cycle_table,
    276					 length / sizeof(u32));
    277	if (ret) {
    278		dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
    279		return ret;
    280	}
    281
    282	drvdata->state			= -ENOTRECOVERABLE;
    283	drvdata->duty_cycle_table	= duty_cycle_table;
    284	drvdata->desc.ops = &pwm_regulator_voltage_table_ops;
    285	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
    286
    287	return 0;
    288}
    289
    290static int pwm_regulator_init_continuous(struct platform_device *pdev,
    291					 struct pwm_regulator_data *drvdata)
    292{
    293	u32 dutycycle_range[2] = { 0, 100 };
    294	u32 dutycycle_unit = 100;
    295
    296	drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops;
    297	drvdata->desc.continuous_voltage_range = true;
    298
    299	of_property_read_u32_array(pdev->dev.of_node,
    300				   "pwm-dutycycle-range",
    301				   dutycycle_range, 2);
    302	of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",
    303			     &dutycycle_unit);
    304
    305	if (dutycycle_range[0] > dutycycle_unit ||
    306	    dutycycle_range[1] > dutycycle_unit)
    307		return -EINVAL;
    308
    309	drvdata->continuous.dutycycle_unit = dutycycle_unit;
    310	drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];
    311	drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];
    312
    313	return 0;
    314}
    315
    316static int pwm_regulator_probe(struct platform_device *pdev)
    317{
    318	const struct regulator_init_data *init_data;
    319	struct pwm_regulator_data *drvdata;
    320	struct regulator_dev *regulator;
    321	struct regulator_config config = { };
    322	struct device_node *np = pdev->dev.of_node;
    323	enum gpiod_flags gpio_flags;
    324	int ret;
    325
    326	if (!np) {
    327		dev_err(&pdev->dev, "Device Tree node missing\n");
    328		return -EINVAL;
    329	}
    330
    331	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
    332	if (!drvdata)
    333		return -ENOMEM;
    334
    335	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
    336
    337	if (of_find_property(np, "voltage-table", NULL))
    338		ret = pwm_regulator_init_table(pdev, drvdata);
    339	else
    340		ret = pwm_regulator_init_continuous(pdev, drvdata);
    341	if (ret)
    342		return ret;
    343
    344	init_data = of_get_regulator_init_data(&pdev->dev, np,
    345					       &drvdata->desc);
    346	if (!init_data)
    347		return -ENOMEM;
    348
    349	config.of_node = np;
    350	config.dev = &pdev->dev;
    351	config.driver_data = drvdata;
    352	config.init_data = init_data;
    353
    354	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
    355	if (IS_ERR(drvdata->pwm))
    356		return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->pwm),
    357				     "Failed to get PWM\n");
    358
    359	if (init_data->constraints.boot_on || init_data->constraints.always_on)
    360		gpio_flags = GPIOD_OUT_HIGH;
    361	else
    362		gpio_flags = GPIOD_OUT_LOW;
    363	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
    364						    gpio_flags);
    365	if (IS_ERR(drvdata->enb_gpio)) {
    366		ret = PTR_ERR(drvdata->enb_gpio);
    367		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
    368		return ret;
    369	}
    370
    371	ret = pwm_adjust_config(drvdata->pwm);
    372	if (ret)
    373		return ret;
    374
    375	regulator = devm_regulator_register(&pdev->dev,
    376					    &drvdata->desc, &config);
    377	if (IS_ERR(regulator)) {
    378		ret = PTR_ERR(regulator);
    379		dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
    380			drvdata->desc.name, ret);
    381		return ret;
    382	}
    383
    384	return 0;
    385}
    386
    387static const struct of_device_id __maybe_unused pwm_of_match[] = {
    388	{ .compatible = "pwm-regulator" },
    389	{ },
    390};
    391MODULE_DEVICE_TABLE(of, pwm_of_match);
    392
    393static struct platform_driver pwm_regulator_driver = {
    394	.driver = {
    395		.name		= "pwm-regulator",
    396		.of_match_table = of_match_ptr(pwm_of_match),
    397	},
    398	.probe = pwm_regulator_probe,
    399};
    400
    401module_platform_driver(pwm_regulator_driver);
    402
    403MODULE_LICENSE("GPL");
    404MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
    405MODULE_DESCRIPTION("PWM Regulator Driver");
    406MODULE_ALIAS("platform:pwm-regulator");