brintos

brintos / linux-shallow public Read only

0
0
Text · 11.6 KiB · 7434b6b Raw
445 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Regulator driver for PWM Regulators4 *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/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/machine.h>16#include <linux/regulator/of_regulator.h>17#include <linux/of.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-backs53 */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_might_sleep(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	if (!pstate.enabled) {161		if (pstate.polarity == PWM_POLARITY_INVERSED)162			pstate.duty_cycle = pstate.period;163		else164			pstate.duty_cycle = 0;165	}166 167	voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);168	if (voltage < min(max_uV_duty, min_uV_duty) ||169	    voltage > max(max_uV_duty, min_uV_duty))170		return -ENOTRECOVERABLE;171 172	/*173	 * The dutycycle for min_uV might be greater than the one for max_uV.174	 * This is happening when the user needs an inversed polarity, but the175	 * PWM device does not support inversing it in hardware.176	 */177	if (max_uV_duty < min_uV_duty) {178		voltage = min_uV_duty - voltage;179		diff_duty = min_uV_duty - max_uV_duty;180	} else {181		voltage = voltage - min_uV_duty;182		diff_duty = max_uV_duty - min_uV_duty;183	}184 185	voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);186 187	return voltage + min_uV;188}189 190static int pwm_regulator_set_voltage(struct regulator_dev *rdev,191				     int req_min_uV, int req_max_uV,192				     unsigned int *selector)193{194	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);195	unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;196	unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;197	unsigned int duty_unit = drvdata->continuous.dutycycle_unit;198	int min_uV = rdev->constraints->min_uV;199	int max_uV = rdev->constraints->max_uV;200	int diff_uV = max_uV - min_uV;201	struct pwm_state pstate;202	unsigned int diff_duty;203	unsigned int dutycycle;204	int ret;205 206	pwm_init_state(drvdata->pwm, &pstate);207 208	/*209	 * The dutycycle for min_uV might be greater than the one for max_uV.210	 * This is happening when the user needs an inversed polarity, but the211	 * PWM device does not support inversing it in hardware.212	 */213	if (max_uV_duty < min_uV_duty)214		diff_duty = min_uV_duty - max_uV_duty;215	else216		diff_duty = max_uV_duty - min_uV_duty;217 218	dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *219					  diff_duty,220					  diff_uV);221 222	if (max_uV_duty < min_uV_duty)223		dutycycle = min_uV_duty - dutycycle;224	else225		dutycycle = min_uV_duty + dutycycle;226 227	pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);228 229	ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);230	if (ret) {231		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);232		return ret;233	}234 235	return 0;236}237 238static const struct regulator_ops pwm_regulator_voltage_table_ops = {239	.set_voltage_sel = pwm_regulator_set_voltage_sel,240	.get_voltage_sel = pwm_regulator_get_voltage_sel,241	.list_voltage    = pwm_regulator_list_voltage,242	.map_voltage     = regulator_map_voltage_iterate,243	.enable          = pwm_regulator_enable,244	.disable         = pwm_regulator_disable,245	.is_enabled      = pwm_regulator_is_enabled,246};247 248static const struct regulator_ops pwm_regulator_voltage_continuous_ops = {249	.get_voltage = pwm_regulator_get_voltage,250	.set_voltage = pwm_regulator_set_voltage,251	.enable          = pwm_regulator_enable,252	.disable         = pwm_regulator_disable,253	.is_enabled      = pwm_regulator_is_enabled,254};255 256static const struct regulator_desc pwm_regulator_desc = {257	.name		= "pwm-regulator",258	.type		= REGULATOR_VOLTAGE,259	.owner		= THIS_MODULE,260	.supply_name    = "pwm",261};262 263static int pwm_regulator_init_table(struct platform_device *pdev,264				    struct pwm_regulator_data *drvdata)265{266	struct device_node *np = pdev->dev.of_node;267	struct pwm_voltages *duty_cycle_table;268	unsigned int length = 0;269	int ret;270 271	of_find_property(np, "voltage-table", &length);272 273	if ((length < sizeof(*duty_cycle_table)) ||274	    (length % sizeof(*duty_cycle_table)))275		return dev_err_probe(&pdev->dev, -EINVAL,276				     "voltage-table length(%d) is invalid\n",277				     length);278 279	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);280	if (!duty_cycle_table)281		return -ENOMEM;282 283	ret = of_property_read_u32_array(np, "voltage-table",284					 (u32 *)duty_cycle_table,285					 length / sizeof(u32));286	if (ret)287		return dev_err_probe(&pdev->dev, ret,288				     "Failed to read voltage-table\n");289 290	drvdata->state			= -ENOTRECOVERABLE;291	drvdata->duty_cycle_table	= duty_cycle_table;292	drvdata->desc.ops = &pwm_regulator_voltage_table_ops;293	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);294 295	return 0;296}297 298static int pwm_regulator_init_continuous(struct platform_device *pdev,299					 struct pwm_regulator_data *drvdata)300{301	u32 dutycycle_range[2] = { 0, 100 };302	u32 dutycycle_unit = 100;303 304	drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops;305	drvdata->desc.continuous_voltage_range = true;306 307	of_property_read_u32_array(pdev->dev.of_node,308				   "pwm-dutycycle-range",309				   dutycycle_range, 2);310	of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",311			     &dutycycle_unit);312 313	if (dutycycle_range[0] > dutycycle_unit ||314	    dutycycle_range[1] > dutycycle_unit)315		return -EINVAL;316 317	drvdata->continuous.dutycycle_unit = dutycycle_unit;318	drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];319	drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];320 321	return 0;322}323 324static int pwm_regulator_init_boot_on(struct platform_device *pdev,325				      struct pwm_regulator_data *drvdata,326				      const struct regulator_init_data *init_data)327{328	struct pwm_state pstate;329 330	if (!init_data->constraints.boot_on || drvdata->enb_gpio)331		return 0;332 333	pwm_get_state(drvdata->pwm, &pstate);334	if (pstate.enabled)335		return 0;336 337	/*338	 * Update the duty cycle so the output does not change339	 * when the regulator core enables the regulator (and340	 * thus the PWM channel).341	 */342	if (pstate.polarity == PWM_POLARITY_INVERSED)343		pstate.duty_cycle = pstate.period;344	else345		pstate.duty_cycle = 0;346 347	return pwm_apply_might_sleep(drvdata->pwm, &pstate);348}349 350static int pwm_regulator_probe(struct platform_device *pdev)351{352	const struct regulator_init_data *init_data;353	struct pwm_regulator_data *drvdata;354	struct regulator_dev *regulator;355	struct regulator_config config = { };356	struct device_node *np = pdev->dev.of_node;357	enum gpiod_flags gpio_flags;358	int ret;359 360	if (!np)361		return dev_err_probe(&pdev->dev, -EINVAL,362				     "Device Tree node missing\n");363 364	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);365	if (!drvdata)366		return -ENOMEM;367 368	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));369 370	if (of_property_present(np, "voltage-table"))371		ret = pwm_regulator_init_table(pdev, drvdata);372	else373		ret = pwm_regulator_init_continuous(pdev, drvdata);374	if (ret)375		return ret;376 377	init_data = of_get_regulator_init_data(&pdev->dev, np,378					       &drvdata->desc);379	if (!init_data)380		return -ENOMEM;381 382	config.of_node = np;383	config.dev = &pdev->dev;384	config.driver_data = drvdata;385	config.init_data = init_data;386 387	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);388	if (IS_ERR(drvdata->pwm))389		return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->pwm),390				     "Failed to get PWM\n");391 392	if (init_data->constraints.boot_on || init_data->constraints.always_on)393		gpio_flags = GPIOD_OUT_HIGH;394	else395		gpio_flags = GPIOD_OUT_LOW;396	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",397						    gpio_flags);398	if (IS_ERR(drvdata->enb_gpio)) {399		ret = PTR_ERR(drvdata->enb_gpio);400		return dev_err_probe(&pdev->dev, ret, "Failed to get enable GPIO\n");401	}402 403	ret = pwm_adjust_config(drvdata->pwm);404	if (ret)405		return ret;406 407	ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data);408	if (ret)409		return dev_err_probe(&pdev->dev, ret,410				     "Failed to apply boot_on settings\n");411 412	regulator = devm_regulator_register(&pdev->dev,413					    &drvdata->desc, &config);414	if (IS_ERR(regulator)) {415		ret = PTR_ERR(regulator);416		return dev_err_probe(&pdev->dev, ret,417				     "Failed to register regulator %s\n",418				     drvdata->desc.name);419	}420 421	return 0;422}423 424static const struct of_device_id __maybe_unused pwm_of_match[] = {425	{ .compatible = "pwm-regulator" },426	{ },427};428MODULE_DEVICE_TABLE(of, pwm_of_match);429 430static struct platform_driver pwm_regulator_driver = {431	.driver = {432		.name		= "pwm-regulator",433		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,434		.of_match_table = of_match_ptr(pwm_of_match),435	},436	.probe = pwm_regulator_probe,437};438 439module_platform_driver(pwm_regulator_driver);440 441MODULE_LICENSE("GPL");442MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");443MODULE_DESCRIPTION("PWM Regulator Driver");444MODULE_ALIAS("platform:pwm-regulator");445