Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: userspace-consumer: Handle regulator-output DT nodes

In addition to adding some fairly simple OF support code, we make some
slight adjustments to the userspace-consumer driver to properly
support use with regulator-output hardware:

- We now do an exclusive get of the supply regulators so as to
prevent regulator_init_complete_work from automatically disabling
them.

- Instead of assuming that the supply is initially disabled, we now
query its state to determine the initial value of drvdata->enabled.

Signed-off-by: Zev Weiss <zev@bewilderbeest.net>
Link: https://lore.kernel.org/r/20221031233704.22575-4-zev@bewilderbeest.net
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Zev Weiss and committed by
Mark Brown
5c51d4af 14b8ad4c

+54 -7
+53 -7
drivers/regulator/userspace-consumer.c
··· 14 14 #include <linux/err.h> 15 15 #include <linux/mutex.h> 16 16 #include <linux/module.h> 17 + #include <linux/of.h> 17 18 #include <linux/platform_device.h> 18 19 #include <linux/regulator/consumer.h> 19 20 #include <linux/regulator/userspace-consumer.h> ··· 25 24 26 25 struct mutex lock; 27 26 bool enabled; 27 + bool no_autoswitch; 28 28 29 29 int num_supplies; 30 30 struct regulator_bulk_data *supplies; ··· 98 96 NULL, 99 97 }; 100 98 99 + static umode_t attr_visible(struct kobject *kobj, struct attribute *attr, int idx) 100 + { 101 + struct device *dev = kobj_to_dev(kobj); 102 + struct userspace_consumer_data *data = dev_get_drvdata(dev); 103 + 104 + /* If a name hasn't been set, don't bother with the attribute */ 105 + if (attr == &dev_attr_name.attr && !data->name) 106 + return 0; 107 + 108 + return attr->mode; 109 + } 110 + 101 111 static const struct attribute_group attr_group = { 102 112 .attrs = attributes, 113 + .is_visible = attr_visible, 103 114 }; 104 115 105 116 static int regulator_userspace_consumer_probe(struct platform_device *pdev) 106 117 { 118 + struct regulator_userspace_consumer_data tmpdata; 107 119 struct regulator_userspace_consumer_data *pdata; 108 120 struct userspace_consumer_data *drvdata; 109 121 int ret; 110 122 111 123 pdata = dev_get_platdata(&pdev->dev); 112 - if (!pdata) 124 + if (!pdata) { 125 + if (!pdev->dev.of_node) 126 + return -EINVAL; 127 + 128 + pdata = &tmpdata; 129 + memset(pdata, 0, sizeof(*pdata)); 130 + 131 + pdata->no_autoswitch = true; 132 + pdata->num_supplies = 1; 133 + pdata->supplies = devm_kzalloc(&pdev->dev, sizeof(*pdata->supplies), GFP_KERNEL); 134 + if (!pdata->supplies) 135 + return -ENOMEM; 136 + pdata->supplies[0].supply = "vout"; 137 + } 138 + 139 + if (pdata->num_supplies < 1) { 140 + dev_err(&pdev->dev, "At least one supply required\n"); 113 141 return -EINVAL; 142 + } 114 143 115 144 drvdata = devm_kzalloc(&pdev->dev, 116 145 sizeof(struct userspace_consumer_data), ··· 152 119 drvdata->name = pdata->name; 153 120 drvdata->num_supplies = pdata->num_supplies; 154 121 drvdata->supplies = pdata->supplies; 122 + drvdata->no_autoswitch = pdata->no_autoswitch; 155 123 156 124 mutex_init(&drvdata->lock); 157 125 158 - ret = devm_regulator_bulk_get(&pdev->dev, drvdata->num_supplies, 159 - drvdata->supplies); 126 + ret = devm_regulator_bulk_get_exclusive(&pdev->dev, drvdata->num_supplies, 127 + drvdata->supplies); 160 128 if (ret) { 161 129 dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); 162 130 return ret; 163 131 } 164 132 133 + platform_set_drvdata(pdev, drvdata); 134 + 165 135 ret = sysfs_create_group(&pdev->dev.kobj, &attr_group); 166 136 if (ret != 0) 167 137 return ret; 168 138 169 - if (pdata->init_on) { 139 + if (pdata->init_on && !pdata->no_autoswitch) { 170 140 ret = regulator_bulk_enable(drvdata->num_supplies, 171 141 drvdata->supplies); 172 142 if (ret) { ··· 179 143 } 180 144 } 181 145 182 - drvdata->enabled = pdata->init_on; 183 - platform_set_drvdata(pdev, drvdata); 146 + ret = regulator_is_enabled(pdata->supplies[0].consumer); 147 + if (ret < 0) { 148 + dev_err(&pdev->dev, "Failed to get regulator status\n"); 149 + goto err_enable; 150 + } 151 + drvdata->enabled = !!ret; 184 152 185 153 return 0; 186 154 ··· 200 160 201 161 sysfs_remove_group(&pdev->dev.kobj, &attr_group); 202 162 203 - if (data->enabled) 163 + if (data->enabled && !data->no_autoswitch) 204 164 regulator_bulk_disable(data->num_supplies, data->supplies); 205 165 206 166 return 0; 207 167 } 168 + 169 + static const struct of_device_id regulator_userspace_consumer_of_match[] = { 170 + { .compatible = "regulator-output", }, 171 + {}, 172 + }; 208 173 209 174 static struct platform_driver regulator_userspace_consumer_driver = { 210 175 .probe = regulator_userspace_consumer_probe, 211 176 .remove = regulator_userspace_consumer_remove, 212 177 .driver = { 213 178 .name = "reg-userspace-consumer", 179 + .of_match_table = regulator_userspace_consumer_of_match, 214 180 }, 215 181 }; 216 182
+1
include/linux/regulator/userspace-consumer.h
··· 21 21 struct regulator_bulk_data *supplies; 22 22 23 23 bool init_on; 24 + bool no_autoswitch; 24 25 }; 25 26 26 27 #endif /* __REGULATOR_PLATFORM_CONSUMER_H_ */