diff options
Diffstat (limited to 'drivers/regulator/pwm-regulator.c')
| -rw-r--r-- | drivers/regulator/pwm-regulator.c | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index b9eeaff1c661..7434b6b22d32 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -10,11 +10,11 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pwm.h> #include <linux/gpio/consumer.h> @@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, pwm_set_relative_duty_cycle(&pstate, drvdata->duty_cycle_table[selector].dutycycle, 100); - ret = pwm_apply_state(drvdata->pwm, &pstate); + ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; @@ -157,7 +157,17 @@ static int pwm_regulator_get_voltage(struct regulator_dev *rdev) pwm_get_state(drvdata->pwm, &pstate); + if (!pstate.enabled) { + if (pstate.polarity == PWM_POLARITY_INVERSED) + pstate.duty_cycle = pstate.period; + else + pstate.duty_cycle = 0; + } + voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit); + if (voltage < min(max_uV_duty, min_uV_duty) || + voltage > max(max_uV_duty, min_uV_duty)) + return -ENOTRECOVERABLE; /* * The dutycycle for min_uV might be greater than the one for max_uV. @@ -216,7 +226,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit); - ret = pwm_apply_state(drvdata->pwm, &pstate); + ret = pwm_apply_might_sleep(drvdata->pwm, &pstate); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); return ret; @@ -261,11 +271,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev, of_find_property(np, "voltage-table", &length); if ((length < sizeof(*duty_cycle_table)) || - (length % sizeof(*duty_cycle_table))) { - dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", - length); - return -EINVAL; - } + (length % sizeof(*duty_cycle_table))) + return dev_err_probe(&pdev->dev, -EINVAL, + "voltage-table length(%d) is invalid\n", + length); duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); if (!duty_cycle_table) @@ -274,10 +283,9 @@ static int pwm_regulator_init_table(struct platform_device *pdev, ret = of_property_read_u32_array(np, "voltage-table", (u32 *)duty_cycle_table, length / sizeof(u32)); - if (ret) { - dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to read voltage-table\n"); drvdata->state = -ENOTRECOVERABLE; drvdata->duty_cycle_table = duty_cycle_table; @@ -313,6 +321,32 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, return 0; } +static int pwm_regulator_init_boot_on(struct platform_device *pdev, + struct pwm_regulator_data *drvdata, + const struct regulator_init_data *init_data) +{ + struct pwm_state pstate; + + if (!init_data->constraints.boot_on || drvdata->enb_gpio) + return 0; + + pwm_get_state(drvdata->pwm, &pstate); + if (pstate.enabled) + return 0; + + /* + * Update the duty cycle so the output does not change + * when the regulator core enables the regulator (and + * thus the PWM channel). + */ + if (pstate.polarity == PWM_POLARITY_INVERSED) + pstate.duty_cycle = pstate.period; + else + pstate.duty_cycle = 0; + + return pwm_apply_might_sleep(drvdata->pwm, &pstate); +} + static int pwm_regulator_probe(struct platform_device *pdev) { const struct regulator_init_data *init_data; @@ -323,10 +357,9 @@ static int pwm_regulator_probe(struct platform_device *pdev) enum gpiod_flags gpio_flags; int ret; - if (!np) { - dev_err(&pdev->dev, "Device Tree node missing\n"); - return -EINVAL; - } + if (!np) + return dev_err_probe(&pdev->dev, -EINVAL, + "Device Tree node missing\n"); drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) @@ -334,7 +367,7 @@ static int pwm_regulator_probe(struct platform_device *pdev) memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc)); - if (of_find_property(np, "voltage-table", NULL)) + if (of_property_present(np, "voltage-table")) ret = pwm_regulator_init_table(pdev, drvdata); else ret = pwm_regulator_init_continuous(pdev, drvdata); @@ -364,21 +397,25 @@ static int pwm_regulator_probe(struct platform_device *pdev) 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; + return dev_err_probe(&pdev->dev, ret, "Failed to get enable GPIO\n"); } ret = pwm_adjust_config(drvdata->pwm); if (ret) return ret; + ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to apply boot_on settings\n"); + regulator = devm_regulator_register(&pdev->dev, &drvdata->desc, &config); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); - dev_err(&pdev->dev, "Failed to register regulator %s: %d\n", - drvdata->desc.name, ret); - return ret; + return dev_err_probe(&pdev->dev, ret, + "Failed to register regulator %s\n", + drvdata->desc.name); } return 0; @@ -393,6 +430,7 @@ MODULE_DEVICE_TABLE(of, pwm_of_match); static struct platform_driver pwm_regulator_driver = { .driver = { .name = "pwm-regulator", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(pwm_of_match), }, .probe = pwm_regulator_probe, |
