diff options
Diffstat (limited to 'drivers/regulator/pwm-regulator.c')
| -rw-r--r-- | drivers/regulator/pwm-regulator.c | 40 | 
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index fafa3488e960..666bc3bb52ef 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -20,6 +20,7 @@  #include <linux/of.h>  #include <linux/of_device.h>  #include <linux/pwm.h> +#include <linux/gpio/consumer.h>  struct pwm_regulator_data {  	/*  Shared */ @@ -38,6 +39,9 @@ struct pwm_regulator_data {  	/* Continuous voltage */  	int volt_uV; + +	/* Enable GPIO */ +	struct gpio_desc *enb_gpio;  };  struct pwm_voltages { @@ -94,6 +98,9 @@ static int pwm_regulator_enable(struct regulator_dev *dev)  {  	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); +	if (drvdata->enb_gpio) +		gpiod_set_value_cansleep(drvdata->enb_gpio, 1); +  	return pwm_enable(drvdata->pwm);  } @@ -103,6 +110,9 @@ static int pwm_regulator_disable(struct regulator_dev *dev)  	pwm_disable(drvdata->pwm); +	if (drvdata->enb_gpio) +		gpiod_set_value_cansleep(drvdata->enb_gpio, 0); +  	return 0;  } @@ -110,6 +120,9 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev)  {  	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); +	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio)) +		return false; +  	return pwm_is_enabled(drvdata->pwm);  } @@ -132,6 +145,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,  	unsigned int duty_pulse;  	u64 req_period;  	u32 rem; +	int old_uV = pwm_regulator_get_voltage(rdev);  	int ret;  	pwm_get_args(drvdata->pwm, &pargs); @@ -159,15 +173,14 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,  		return ret;  	} -	ret = pwm_enable(drvdata->pwm); -	if (ret) { -		dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret); -		return ret; -	}  	drvdata->volt_uV = min_uV; -	/* Delay required by PWM regulator to settle to the new voltage */ -	usleep_range(ramp_delay, ramp_delay + 1000); +	if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev)) +		return 0; + +	/* Ramp delay is in uV/uS. Adjust to uS and delay */ +	ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay); +	usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10));  	return 0;  } @@ -253,6 +266,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)  	struct regulator_dev *regulator;  	struct regulator_config config = { };  	struct device_node *np = pdev->dev.of_node; +	enum gpiod_flags gpio_flags;  	int ret;  	if (!np) { @@ -290,6 +304,18 @@ static int pwm_regulator_probe(struct platform_device *pdev)  		return ret;  	} +	if (init_data->constraints.boot_on || init_data->constraints.always_on) +		gpio_flags = GPIOD_OUT_HIGH; +	else +		gpio_flags = GPIOD_OUT_LOW; +	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", +						    gpio_flags); +	if (IS_ERR(drvdata->enb_gpio)) { +		ret = PTR_ERR(drvdata->enb_gpio); +		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret); +		return ret; +	} +  	/*  	 * FIXME: pwm_apply_args() should be removed when switching to the  	 * atomic PWM API.  |