18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Regulator driver for PWM Regulators
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 - STMicroelectronics Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Lee Jones <lee.jones@linaro.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
148c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h>
168c2ecf20Sopenharmony_ci#include <linux/of.h>
178c2ecf20Sopenharmony_ci#include <linux/of_device.h>
188c2ecf20Sopenharmony_ci#include <linux/pwm.h>
198c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct pwm_continuous_reg_data {
228c2ecf20Sopenharmony_ci	unsigned int min_uV_dutycycle;
238c2ecf20Sopenharmony_ci	unsigned int max_uV_dutycycle;
248c2ecf20Sopenharmony_ci	unsigned int dutycycle_unit;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct pwm_regulator_data {
288c2ecf20Sopenharmony_ci	/*  Shared */
298c2ecf20Sopenharmony_ci	struct pwm_device *pwm;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	/* Voltage table */
328c2ecf20Sopenharmony_ci	struct pwm_voltages *duty_cycle_table;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/* Continuous mode info */
358c2ecf20Sopenharmony_ci	struct pwm_continuous_reg_data continuous;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* regulator descriptor */
388c2ecf20Sopenharmony_ci	struct regulator_desc desc;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	int state;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/* Enable GPIO */
438c2ecf20Sopenharmony_ci	struct gpio_desc *enb_gpio;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistruct pwm_voltages {
478c2ecf20Sopenharmony_ci	unsigned int uV;
488c2ecf20Sopenharmony_ci	unsigned int dutycycle;
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/*
528c2ecf20Sopenharmony_ci * Voltage table call-backs
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_cistatic void pwm_regulator_init_state(struct regulator_dev *rdev)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
578c2ecf20Sopenharmony_ci	struct pwm_state pwm_state;
588c2ecf20Sopenharmony_ci	unsigned int dutycycle;
598c2ecf20Sopenharmony_ci	int i;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	pwm_get_state(drvdata->pwm, &pwm_state);
628c2ecf20Sopenharmony_ci	dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->desc->n_voltages; i++) {
658c2ecf20Sopenharmony_ci		if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {
668c2ecf20Sopenharmony_ci			drvdata->state = i;
678c2ecf20Sopenharmony_ci			return;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (drvdata->state < 0)
778c2ecf20Sopenharmony_ci		pwm_regulator_init_state(rdev);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return drvdata->state;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
838c2ecf20Sopenharmony_ci					 unsigned selector)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
868c2ecf20Sopenharmony_ci	struct pwm_state pstate;
878c2ecf20Sopenharmony_ci	int ret;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	pwm_init_state(drvdata->pwm, &pstate);
908c2ecf20Sopenharmony_ci	pwm_set_relative_duty_cycle(&pstate,
918c2ecf20Sopenharmony_ci			drvdata->duty_cycle_table[selector].dutycycle, 100);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ret = pwm_apply_state(drvdata->pwm, &pstate);
948c2ecf20Sopenharmony_ci	if (ret) {
958c2ecf20Sopenharmony_ci		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
968c2ecf20Sopenharmony_ci		return ret;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	drvdata->state = selector;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int pwm_regulator_list_voltage(struct regulator_dev *rdev,
1058c2ecf20Sopenharmony_ci				      unsigned selector)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (selector >= rdev->desc->n_voltages)
1108c2ecf20Sopenharmony_ci		return -EINVAL;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return drvdata->duty_cycle_table[selector].uV;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int pwm_regulator_enable(struct regulator_dev *dev)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return pwm_enable(drvdata->pwm);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int pwm_regulator_disable(struct regulator_dev *dev)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	pwm_disable(drvdata->pwm);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int pwm_regulator_is_enabled(struct regulator_dev *dev)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
1408c2ecf20Sopenharmony_ci		return false;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return pwm_is_enabled(drvdata->pwm);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int pwm_regulator_get_voltage(struct regulator_dev *rdev)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1488c2ecf20Sopenharmony_ci	unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
1498c2ecf20Sopenharmony_ci	unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
1508c2ecf20Sopenharmony_ci	unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
1518c2ecf20Sopenharmony_ci	int min_uV = rdev->constraints->min_uV;
1528c2ecf20Sopenharmony_ci	int max_uV = rdev->constraints->max_uV;
1538c2ecf20Sopenharmony_ci	int diff_uV = max_uV - min_uV;
1548c2ecf20Sopenharmony_ci	struct pwm_state pstate;
1558c2ecf20Sopenharmony_ci	unsigned int diff_duty;
1568c2ecf20Sopenharmony_ci	unsigned int voltage;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	pwm_get_state(drvdata->pwm, &pstate);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/*
1638c2ecf20Sopenharmony_ci	 * The dutycycle for min_uV might be greater than the one for max_uV.
1648c2ecf20Sopenharmony_ci	 * This is happening when the user needs an inversed polarity, but the
1658c2ecf20Sopenharmony_ci	 * PWM device does not support inversing it in hardware.
1668c2ecf20Sopenharmony_ci	 */
1678c2ecf20Sopenharmony_ci	if (max_uV_duty < min_uV_duty) {
1688c2ecf20Sopenharmony_ci		voltage = min_uV_duty - voltage;
1698c2ecf20Sopenharmony_ci		diff_duty = min_uV_duty - max_uV_duty;
1708c2ecf20Sopenharmony_ci	} else {
1718c2ecf20Sopenharmony_ci		voltage = voltage - min_uV_duty;
1728c2ecf20Sopenharmony_ci		diff_duty = max_uV_duty - min_uV_duty;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return voltage + min_uV;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int pwm_regulator_set_voltage(struct regulator_dev *rdev,
1818c2ecf20Sopenharmony_ci				     int req_min_uV, int req_max_uV,
1828c2ecf20Sopenharmony_ci				     unsigned int *selector)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1858c2ecf20Sopenharmony_ci	unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
1868c2ecf20Sopenharmony_ci	unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
1878c2ecf20Sopenharmony_ci	unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
1888c2ecf20Sopenharmony_ci	int min_uV = rdev->constraints->min_uV;
1898c2ecf20Sopenharmony_ci	int max_uV = rdev->constraints->max_uV;
1908c2ecf20Sopenharmony_ci	int diff_uV = max_uV - min_uV;
1918c2ecf20Sopenharmony_ci	struct pwm_state pstate;
1928c2ecf20Sopenharmony_ci	unsigned int diff_duty;
1938c2ecf20Sopenharmony_ci	unsigned int dutycycle;
1948c2ecf20Sopenharmony_ci	int ret;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	pwm_init_state(drvdata->pwm, &pstate);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * The dutycycle for min_uV might be greater than the one for max_uV.
2008c2ecf20Sopenharmony_ci	 * This is happening when the user needs an inversed polarity, but the
2018c2ecf20Sopenharmony_ci	 * PWM device does not support inversing it in hardware.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if (max_uV_duty < min_uV_duty)
2048c2ecf20Sopenharmony_ci		diff_duty = min_uV_duty - max_uV_duty;
2058c2ecf20Sopenharmony_ci	else
2068c2ecf20Sopenharmony_ci		diff_duty = max_uV_duty - min_uV_duty;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *
2098c2ecf20Sopenharmony_ci					  diff_duty,
2108c2ecf20Sopenharmony_ci					  diff_uV);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (max_uV_duty < min_uV_duty)
2138c2ecf20Sopenharmony_ci		dutycycle = min_uV_duty - dutycycle;
2148c2ecf20Sopenharmony_ci	else
2158c2ecf20Sopenharmony_ci		dutycycle = min_uV_duty + dutycycle;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ret = pwm_apply_state(drvdata->pwm, &pstate);
2208c2ecf20Sopenharmony_ci	if (ret) {
2218c2ecf20Sopenharmony_ci		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
2228c2ecf20Sopenharmony_ci		return ret;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic const struct regulator_ops pwm_regulator_voltage_table_ops = {
2298c2ecf20Sopenharmony_ci	.set_voltage_sel = pwm_regulator_set_voltage_sel,
2308c2ecf20Sopenharmony_ci	.get_voltage_sel = pwm_regulator_get_voltage_sel,
2318c2ecf20Sopenharmony_ci	.list_voltage    = pwm_regulator_list_voltage,
2328c2ecf20Sopenharmony_ci	.map_voltage     = regulator_map_voltage_iterate,
2338c2ecf20Sopenharmony_ci	.enable          = pwm_regulator_enable,
2348c2ecf20Sopenharmony_ci	.disable         = pwm_regulator_disable,
2358c2ecf20Sopenharmony_ci	.is_enabled      = pwm_regulator_is_enabled,
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic const struct regulator_ops pwm_regulator_voltage_continuous_ops = {
2398c2ecf20Sopenharmony_ci	.get_voltage = pwm_regulator_get_voltage,
2408c2ecf20Sopenharmony_ci	.set_voltage = pwm_regulator_set_voltage,
2418c2ecf20Sopenharmony_ci	.enable          = pwm_regulator_enable,
2428c2ecf20Sopenharmony_ci	.disable         = pwm_regulator_disable,
2438c2ecf20Sopenharmony_ci	.is_enabled      = pwm_regulator_is_enabled,
2448c2ecf20Sopenharmony_ci};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic const struct regulator_desc pwm_regulator_desc = {
2478c2ecf20Sopenharmony_ci	.name		= "pwm-regulator",
2488c2ecf20Sopenharmony_ci	.type		= REGULATOR_VOLTAGE,
2498c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
2508c2ecf20Sopenharmony_ci	.supply_name    = "pwm",
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int pwm_regulator_init_table(struct platform_device *pdev,
2548c2ecf20Sopenharmony_ci				    struct pwm_regulator_data *drvdata)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
2578c2ecf20Sopenharmony_ci	struct pwm_voltages *duty_cycle_table;
2588c2ecf20Sopenharmony_ci	unsigned int length = 0;
2598c2ecf20Sopenharmony_ci	int ret;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	of_find_property(np, "voltage-table", &length);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if ((length < sizeof(*duty_cycle_table)) ||
2648c2ecf20Sopenharmony_ci	    (length % sizeof(*duty_cycle_table))) {
2658c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
2668c2ecf20Sopenharmony_ci			length);
2678c2ecf20Sopenharmony_ci		return -EINVAL;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
2718c2ecf20Sopenharmony_ci	if (!duty_cycle_table)
2728c2ecf20Sopenharmony_ci		return -ENOMEM;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = of_property_read_u32_array(np, "voltage-table",
2758c2ecf20Sopenharmony_ci					 (u32 *)duty_cycle_table,
2768c2ecf20Sopenharmony_ci					 length / sizeof(u32));
2778c2ecf20Sopenharmony_ci	if (ret) {
2788c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
2798c2ecf20Sopenharmony_ci		return ret;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	drvdata->state			= -ENOTRECOVERABLE;
2838c2ecf20Sopenharmony_ci	drvdata->duty_cycle_table	= duty_cycle_table;
2848c2ecf20Sopenharmony_ci	drvdata->desc.ops = &pwm_regulator_voltage_table_ops;
2858c2ecf20Sopenharmony_ci	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	return 0;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int pwm_regulator_init_continuous(struct platform_device *pdev,
2918c2ecf20Sopenharmony_ci					 struct pwm_regulator_data *drvdata)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	u32 dutycycle_range[2] = { 0, 100 };
2948c2ecf20Sopenharmony_ci	u32 dutycycle_unit = 100;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops;
2978c2ecf20Sopenharmony_ci	drvdata->desc.continuous_voltage_range = true;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	of_property_read_u32_array(pdev->dev.of_node,
3008c2ecf20Sopenharmony_ci				   "pwm-dutycycle-range",
3018c2ecf20Sopenharmony_ci				   dutycycle_range, 2);
3028c2ecf20Sopenharmony_ci	of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",
3038c2ecf20Sopenharmony_ci			     &dutycycle_unit);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (dutycycle_range[0] > dutycycle_unit ||
3068c2ecf20Sopenharmony_ci	    dutycycle_range[1] > dutycycle_unit)
3078c2ecf20Sopenharmony_ci		return -EINVAL;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	drvdata->continuous.dutycycle_unit = dutycycle_unit;
3108c2ecf20Sopenharmony_ci	drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];
3118c2ecf20Sopenharmony_ci	drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return 0;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int pwm_regulator_probe(struct platform_device *pdev)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	const struct regulator_init_data *init_data;
3198c2ecf20Sopenharmony_ci	struct pwm_regulator_data *drvdata;
3208c2ecf20Sopenharmony_ci	struct regulator_dev *regulator;
3218c2ecf20Sopenharmony_ci	struct regulator_config config = { };
3228c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
3238c2ecf20Sopenharmony_ci	enum gpiod_flags gpio_flags;
3248c2ecf20Sopenharmony_ci	int ret;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!np) {
3278c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Device Tree node missing\n");
3288c2ecf20Sopenharmony_ci		return -EINVAL;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
3328c2ecf20Sopenharmony_ci	if (!drvdata)
3338c2ecf20Sopenharmony_ci		return -ENOMEM;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (of_find_property(np, "voltage-table", NULL))
3388c2ecf20Sopenharmony_ci		ret = pwm_regulator_init_table(pdev, drvdata);
3398c2ecf20Sopenharmony_ci	else
3408c2ecf20Sopenharmony_ci		ret = pwm_regulator_init_continuous(pdev, drvdata);
3418c2ecf20Sopenharmony_ci	if (ret)
3428c2ecf20Sopenharmony_ci		return ret;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	init_data = of_get_regulator_init_data(&pdev->dev, np,
3458c2ecf20Sopenharmony_ci					       &drvdata->desc);
3468c2ecf20Sopenharmony_ci	if (!init_data)
3478c2ecf20Sopenharmony_ci		return -ENOMEM;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	config.of_node = np;
3508c2ecf20Sopenharmony_ci	config.dev = &pdev->dev;
3518c2ecf20Sopenharmony_ci	config.driver_data = drvdata;
3528c2ecf20Sopenharmony_ci	config.init_data = init_data;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
3558c2ecf20Sopenharmony_ci	if (IS_ERR(drvdata->pwm)) {
3568c2ecf20Sopenharmony_ci		ret = PTR_ERR(drvdata->pwm);
3578c2ecf20Sopenharmony_ci		if (ret == -EPROBE_DEFER)
3588c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev,
3598c2ecf20Sopenharmony_ci				"Failed to get PWM, deferring probe\n");
3608c2ecf20Sopenharmony_ci		else
3618c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
3628c2ecf20Sopenharmony_ci		return ret;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (init_data->constraints.boot_on || init_data->constraints.always_on)
3668c2ecf20Sopenharmony_ci		gpio_flags = GPIOD_OUT_HIGH;
3678c2ecf20Sopenharmony_ci	else
3688c2ecf20Sopenharmony_ci		gpio_flags = GPIOD_OUT_LOW;
3698c2ecf20Sopenharmony_ci	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
3708c2ecf20Sopenharmony_ci						    gpio_flags);
3718c2ecf20Sopenharmony_ci	if (IS_ERR(drvdata->enb_gpio)) {
3728c2ecf20Sopenharmony_ci		ret = PTR_ERR(drvdata->enb_gpio);
3738c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
3748c2ecf20Sopenharmony_ci		return ret;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	ret = pwm_adjust_config(drvdata->pwm);
3788c2ecf20Sopenharmony_ci	if (ret)
3798c2ecf20Sopenharmony_ci		return ret;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	regulator = devm_regulator_register(&pdev->dev,
3828c2ecf20Sopenharmony_ci					    &drvdata->desc, &config);
3838c2ecf20Sopenharmony_ci	if (IS_ERR(regulator)) {
3848c2ecf20Sopenharmony_ci		ret = PTR_ERR(regulator);
3858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
3868c2ecf20Sopenharmony_ci			drvdata->desc.name, ret);
3878c2ecf20Sopenharmony_ci		return ret;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return 0;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused pwm_of_match[] = {
3948c2ecf20Sopenharmony_ci	{ .compatible = "pwm-regulator" },
3958c2ecf20Sopenharmony_ci	{ },
3968c2ecf20Sopenharmony_ci};
3978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pwm_of_match);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic struct platform_driver pwm_regulator_driver = {
4008c2ecf20Sopenharmony_ci	.driver = {
4018c2ecf20Sopenharmony_ci		.name		= "pwm-regulator",
4028c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(pwm_of_match),
4038c2ecf20Sopenharmony_ci	},
4048c2ecf20Sopenharmony_ci	.probe = pwm_regulator_probe,
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cimodule_platform_driver(pwm_regulator_driver);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
4118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PWM Regulator Driver");
4128c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pwm-regulator");
413