Переглянути джерело

Merge tag 'pwm-modernization' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator into for-4.8/regulator

regulator: Provide a branch for moderninzation of the PWM code

There's a new, improved PWM API which allows a lot of improvements in
the PWM regulator driver.  Since the bulk of the changes are in the PWM
API this is being managed in the PWM tree, merge pending regulator API
changes to allow this to be resolved more easily.
Thierry Reding 9 роки тому
батько
коміт
6fa231b778

+ 6 - 1
Documentation/devicetree/bindings/regulator/pwm-regulator.txt

@@ -38,13 +38,18 @@ NB: To be clear, if voltage-table is provided, then the device will be used
 in Voltage Table Mode.  If no voltage-table is provided, then the device will
 in Voltage Table Mode.  If no voltage-table is provided, then the device will
 be used in Continuous Voltage Mode.
 be used in Continuous Voltage Mode.
 
 
+Optional properties:
+--------------------
+- enable-gpios:		GPIO to use to enable/disable the regulator
+
 Any property defined as part of the core regulator binding can also be used.
 Any property defined as part of the core regulator binding can also be used.
 (See: ../regulator/regulator.txt)
 (See: ../regulator/regulator.txt)
 
 
-Continuous Voltage Example:
+Continuous Voltage With Enable GPIO Example:
 	pwm_regulator {
 	pwm_regulator {
 		compatible = "pwm-regulator;
 		compatible = "pwm-regulator;
 		pwms = <&pwm1 0 8448 0>;
 		pwms = <&pwm1 0 8448 0>;
+		enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
 		regulator-min-microvolt = <1016000>;
 		regulator-min-microvolt = <1016000>;
 		regulator-max-microvolt = <1114000>;
 		regulator-max-microvolt = <1114000>;
 		regulator-name = "vdd_logic";
 		regulator-name = "vdd_logic";

+ 33 - 7
drivers/regulator/pwm-regulator.c

@@ -20,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/pwm.h>
 #include <linux/pwm.h>
+#include <linux/gpio/consumer.h>
 
 
 struct pwm_regulator_data {
 struct pwm_regulator_data {
 	/*  Shared */
 	/*  Shared */
@@ -38,6 +39,9 @@ struct pwm_regulator_data {
 
 
 	/* Continuous voltage */
 	/* Continuous voltage */
 	int volt_uV;
 	int volt_uV;
+
+	/* Enable GPIO */
+	struct gpio_desc *enb_gpio;
 };
 };
 
 
 struct pwm_voltages {
 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);
 	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);
 	return pwm_enable(drvdata->pwm);
 }
 }
 
 
@@ -103,6 +110,9 @@ static int pwm_regulator_disable(struct regulator_dev *dev)
 
 
 	pwm_disable(drvdata->pwm);
 	pwm_disable(drvdata->pwm);
 
 
+	if (drvdata->enb_gpio)
+		gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
+
 	return 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);
 	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);
 	return pwm_is_enabled(drvdata->pwm);
 }
 }
 
 
@@ -132,6 +145,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
 	unsigned int duty_pulse;
 	unsigned int duty_pulse;
 	u64 req_period;
 	u64 req_period;
 	u32 rem;
 	u32 rem;
+	int old_uV = pwm_regulator_get_voltage(rdev);
 	int ret;
 	int ret;
 
 
 	pwm_get_args(drvdata->pwm, &pargs);
 	pwm_get_args(drvdata->pwm, &pargs);
@@ -159,15 +173,14 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
 		return ret;
 		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;
 	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;
 	return 0;
 }
 }
@@ -253,6 +266,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)
 	struct regulator_dev *regulator;
 	struct regulator_dev *regulator;
 	struct regulator_config config = { };
 	struct regulator_config config = { };
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *np = pdev->dev.of_node;
+	enum gpiod_flags gpio_flags;
 	int ret;
 	int ret;
 
 
 	if (!np) {
 	if (!np) {
@@ -290,6 +304,18 @@ static int pwm_regulator_probe(struct platform_device *pdev)
 		return ret;
 		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
 	 * FIXME: pwm_apply_args() should be removed when switching to the
 	 * atomic PWM API.
 	 * atomic PWM API.