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