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

regulator: add userspace-consumer driver

The userspace-consumer driver allows control of voltage and current
regulator state from userspace. This is required for fine-grained
power management of devices that are completely controller by userspace
applications, e.g. a GPS transciever connected to a serial port.

Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

authored by

Mike Rapoport and committed by
Liam Girdwood
1d98cccf 55f4fa4e

+236
+10
drivers/regulator/Kconfig
··· 47 47 48 48 If unsure, say no. 49 49 50 + config REGULATOR_USERSPACE_CONSUMER 51 + tristate "Userspace regulator consumer support" 52 + default n 53 + help 54 + There are some classes of devices that are controlled entirely 55 + from user space. Usersapce consumer driver provides ability to 56 + control power supplies for such devices. 57 + 58 + If unsure, say no. 59 + 50 60 config REGULATOR_BQ24022 51 61 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" 52 62 default n
+1
drivers/regulator/Makefile
··· 6 6 obj-$(CONFIG_REGULATOR) += core.o 7 7 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o 8 8 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o 9 + obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o 9 10 10 11 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o 11 12 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+200
drivers/regulator/userspace-consumer.c
··· 1 + /* 2 + * userspace-consumer.c 3 + * 4 + * Copyright 2009 CompuLab, Ltd. 5 + * 6 + * Author: Mike Rapoport <mike@compulab.co.il> 7 + * 8 + * Based of virtual consumer driver: 9 + * Copyright 2008 Wolfson Microelectronics PLC. 10 + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License as 14 + * published by the Free Software Foundation; either version 2 of the 15 + * License, or (at your option) any later version. 16 + * 17 + */ 18 + 19 + #include <linux/err.h> 20 + #include <linux/mutex.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/regulator/consumer.h> 23 + #include <linux/regulator/userspace-consumer.h> 24 + 25 + struct userspace_consumer_data { 26 + const char *name; 27 + 28 + struct mutex lock; 29 + bool enabled; 30 + 31 + int num_supplies; 32 + struct regulator_bulk_data *supplies; 33 + }; 34 + 35 + static ssize_t show_name(struct device *dev, 36 + struct device_attribute *attr, char *buf) 37 + { 38 + struct userspace_consumer_data *data = dev_get_drvdata(dev); 39 + 40 + return sprintf(buf, "%s\n", data->name); 41 + } 42 + 43 + static ssize_t show_state(struct device *dev, 44 + struct device_attribute *attr, char *buf) 45 + { 46 + struct userspace_consumer_data *data = dev_get_drvdata(dev); 47 + 48 + if (data->enabled) 49 + return sprintf(buf, "enabled\n"); 50 + 51 + return sprintf(buf, "disabled\n"); 52 + } 53 + 54 + static ssize_t set_state(struct device *dev, struct device_attribute *attr, 55 + const char *buf, size_t count) 56 + { 57 + struct userspace_consumer_data *data = dev_get_drvdata(dev); 58 + bool enabled; 59 + int ret; 60 + 61 + /* 62 + * sysfs_streq() doesn't need the \n's, but we add them so the strings 63 + * will be shared with show_state(), above. 64 + */ 65 + if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1")) 66 + enabled = true; 67 + else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0")) 68 + enabled = false; 69 + else { 70 + dev_err(dev, "Configuring invalid mode\n"); 71 + return count; 72 + } 73 + 74 + mutex_lock(&data->lock); 75 + if (enabled != data->enabled) { 76 + if (enabled) 77 + ret = regulator_bulk_enable(data->num_supplies, 78 + data->supplies); 79 + else 80 + ret = regulator_bulk_disable(data->num_supplies, 81 + data->supplies); 82 + 83 + if (ret == 0) 84 + data->enabled = enabled; 85 + else 86 + dev_err(dev, "Failed to configure state: %d\n", ret); 87 + } 88 + mutex_unlock(&data->lock); 89 + 90 + return count; 91 + } 92 + 93 + static DEVICE_ATTR(name, 0444, show_name, NULL); 94 + static DEVICE_ATTR(state, 0644, show_state, set_state); 95 + 96 + static struct device_attribute *attributes[] = { 97 + &dev_attr_name, 98 + &dev_attr_state, 99 + }; 100 + 101 + static int regulator_userspace_consumer_probe(struct platform_device *pdev) 102 + { 103 + struct regulator_userspace_consumer_data *pdata; 104 + struct userspace_consumer_data *drvdata; 105 + int ret, i; 106 + 107 + pdata = pdev->dev.platform_data; 108 + if (!pdata) 109 + return -EINVAL; 110 + 111 + drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL); 112 + if (drvdata == NULL) 113 + return -ENOMEM; 114 + 115 + drvdata->name = pdata->name; 116 + drvdata->num_supplies = pdata->num_supplies; 117 + drvdata->supplies = pdata->supplies; 118 + 119 + mutex_init(&drvdata->lock); 120 + 121 + ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies, 122 + drvdata->supplies); 123 + if (ret) { 124 + dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); 125 + goto err_alloc_supplies; 126 + } 127 + 128 + for (i = 0; i < ARRAY_SIZE(attributes); i++) { 129 + ret = device_create_file(&pdev->dev, attributes[i]); 130 + if (ret != 0) 131 + goto err_create_attrs; 132 + } 133 + 134 + if (pdata->init_on) 135 + ret = regulator_bulk_enable(drvdata->num_supplies, 136 + drvdata->supplies); 137 + 138 + drvdata->enabled = pdata->init_on; 139 + 140 + if (ret) { 141 + dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret); 142 + goto err_create_attrs; 143 + } 144 + 145 + platform_set_drvdata(pdev, drvdata); 146 + 147 + return 0; 148 + 149 + err_create_attrs: 150 + for (i = 0; i < ARRAY_SIZE(attributes); i++) 151 + device_remove_file(&pdev->dev, attributes[i]); 152 + 153 + regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); 154 + 155 + err_alloc_supplies: 156 + kfree(drvdata); 157 + return ret; 158 + } 159 + 160 + static int regulator_userspace_consumer_remove(struct platform_device *pdev) 161 + { 162 + struct userspace_consumer_data *data = platform_get_drvdata(pdev); 163 + int i; 164 + 165 + for (i = 0; i < ARRAY_SIZE(attributes); i++) 166 + device_remove_file(&pdev->dev, attributes[i]); 167 + 168 + if (data->enabled) 169 + regulator_bulk_disable(data->num_supplies, data->supplies); 170 + 171 + regulator_bulk_free(data->num_supplies, data->supplies); 172 + kfree(data); 173 + 174 + return 0; 175 + } 176 + 177 + static struct platform_driver regulator_userspace_consumer_driver = { 178 + .probe = regulator_userspace_consumer_probe, 179 + .remove = regulator_userspace_consumer_remove, 180 + .driver = { 181 + .name = "reg-userspace-consumer", 182 + }, 183 + }; 184 + 185 + 186 + static int __init regulator_userspace_consumer_init(void) 187 + { 188 + return platform_driver_register(&regulator_userspace_consumer_driver); 189 + } 190 + module_init(regulator_userspace_consumer_init); 191 + 192 + static void __exit regulator_userspace_consumer_exit(void) 193 + { 194 + platform_driver_unregister(&regulator_userspace_consumer_driver); 195 + } 196 + module_exit(regulator_userspace_consumer_exit); 197 + 198 + MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); 199 + MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators"); 200 + MODULE_LICENSE("GPL");
+25
include/linux/regulator/userspace-consumer.h
··· 1 + #ifndef __REGULATOR_PLATFORM_CONSUMER_H_ 2 + #define __REGULATOR_PLATFORM_CONSUMER_H_ 3 + 4 + struct regulator_consumer_supply; 5 + 6 + /** 7 + * struct regulator_userspace_consumer_data - line consumer 8 + * initialisation data. 9 + * 10 + * @name: Name for the consumer line 11 + * @num_supplies: Number of supplies feeding the line 12 + * @supplies: Supplies configuration. 13 + * @init_on: Set if the regulators supplying the line should be 14 + * enabled during initialisation 15 + */ 16 + struct regulator_userspace_consumer_data { 17 + const char *name; 18 + 19 + int num_supplies; 20 + struct regulator_bulk_data *supplies; 21 + 22 + bool init_on; 23 + }; 24 + 25 + #endif /* __REGULATOR_PLATFORM_CONSUMER_H_ */