0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/err.h>
0015 #include <linux/mutex.h>
0016 #include <linux/module.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/regulator/userspace-consumer.h>
0020 #include <linux/slab.h>
0021
0022 struct userspace_consumer_data {
0023 const char *name;
0024
0025 struct mutex lock;
0026 bool enabled;
0027
0028 int num_supplies;
0029 struct regulator_bulk_data *supplies;
0030 };
0031
0032 static ssize_t name_show(struct device *dev,
0033 struct device_attribute *attr, char *buf)
0034 {
0035 struct userspace_consumer_data *data = dev_get_drvdata(dev);
0036
0037 return sprintf(buf, "%s\n", data->name);
0038 }
0039
0040 static ssize_t state_show(struct device *dev,
0041 struct device_attribute *attr, char *buf)
0042 {
0043 struct userspace_consumer_data *data = dev_get_drvdata(dev);
0044
0045 if (data->enabled)
0046 return sprintf(buf, "enabled\n");
0047
0048 return sprintf(buf, "disabled\n");
0049 }
0050
0051 static ssize_t state_store(struct device *dev, struct device_attribute *attr,
0052 const char *buf, size_t count)
0053 {
0054 struct userspace_consumer_data *data = dev_get_drvdata(dev);
0055 bool enabled;
0056 int ret;
0057
0058
0059
0060
0061
0062 if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1"))
0063 enabled = true;
0064 else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0"))
0065 enabled = false;
0066 else {
0067 dev_err(dev, "Configuring invalid mode\n");
0068 return count;
0069 }
0070
0071 mutex_lock(&data->lock);
0072 if (enabled != data->enabled) {
0073 if (enabled)
0074 ret = regulator_bulk_enable(data->num_supplies,
0075 data->supplies);
0076 else
0077 ret = regulator_bulk_disable(data->num_supplies,
0078 data->supplies);
0079
0080 if (ret == 0)
0081 data->enabled = enabled;
0082 else
0083 dev_err(dev, "Failed to configure state: %d\n", ret);
0084 }
0085 mutex_unlock(&data->lock);
0086
0087 return count;
0088 }
0089
0090 static DEVICE_ATTR_RO(name);
0091 static DEVICE_ATTR_RW(state);
0092
0093 static struct attribute *attributes[] = {
0094 &dev_attr_name.attr,
0095 &dev_attr_state.attr,
0096 NULL,
0097 };
0098
0099 static const struct attribute_group attr_group = {
0100 .attrs = attributes,
0101 };
0102
0103 static int regulator_userspace_consumer_probe(struct platform_device *pdev)
0104 {
0105 struct regulator_userspace_consumer_data *pdata;
0106 struct userspace_consumer_data *drvdata;
0107 int ret;
0108
0109 pdata = dev_get_platdata(&pdev->dev);
0110 if (!pdata)
0111 return -EINVAL;
0112
0113 drvdata = devm_kzalloc(&pdev->dev,
0114 sizeof(struct userspace_consumer_data),
0115 GFP_KERNEL);
0116 if (drvdata == NULL)
0117 return -ENOMEM;
0118
0119 drvdata->name = pdata->name;
0120 drvdata->num_supplies = pdata->num_supplies;
0121 drvdata->supplies = pdata->supplies;
0122
0123 mutex_init(&drvdata->lock);
0124
0125 ret = devm_regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
0126 drvdata->supplies);
0127 if (ret) {
0128 dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
0129 return ret;
0130 }
0131
0132 ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
0133 if (ret != 0)
0134 return ret;
0135
0136 if (pdata->init_on) {
0137 ret = regulator_bulk_enable(drvdata->num_supplies,
0138 drvdata->supplies);
0139 if (ret) {
0140 dev_err(&pdev->dev,
0141 "Failed to set initial state: %d\n", ret);
0142 goto err_enable;
0143 }
0144 }
0145
0146 drvdata->enabled = pdata->init_on;
0147 platform_set_drvdata(pdev, drvdata);
0148
0149 return 0;
0150
0151 err_enable:
0152 sysfs_remove_group(&pdev->dev.kobj, &attr_group);
0153
0154 return ret;
0155 }
0156
0157 static int regulator_userspace_consumer_remove(struct platform_device *pdev)
0158 {
0159 struct userspace_consumer_data *data = platform_get_drvdata(pdev);
0160
0161 sysfs_remove_group(&pdev->dev.kobj, &attr_group);
0162
0163 if (data->enabled)
0164 regulator_bulk_disable(data->num_supplies, data->supplies);
0165
0166 return 0;
0167 }
0168
0169 static struct platform_driver regulator_userspace_consumer_driver = {
0170 .probe = regulator_userspace_consumer_probe,
0171 .remove = regulator_userspace_consumer_remove,
0172 .driver = {
0173 .name = "reg-userspace-consumer",
0174 },
0175 };
0176
0177 module_platform_driver(regulator_userspace_consumer_driver);
0178
0179 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
0180 MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
0181 MODULE_LICENSE("GPL");