Merge branch 'reg-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Aug 2008 17:56:40 +0000 (10:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Aug 2008 17:56:40 +0000 (10:56 -0700)
* 'reg-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6:
  regulator: TI bq24022 Li-Ion Charger driver
  regulator: maintainers - add maintainers for regulator framework.
  regulator: documentation - ABI
  regulator: documentation - machine
  regulator: documentation - regulator driver
  regulator: documentation - consumer interface
  regulator: documentation - overview
  regulator: core kbuild files
  regulator: regulator test harness
  regulator: add support for fixed regulators.
  regulator: regulator framework core
  regulator: fixed regulator interface
  regulator: machine driver interface
  regulator: regulator driver interface
  regulator: consumer device interface

19 files changed:
Documentation/ABI/testing/sysfs-class-regulator [new file with mode: 0644]
Documentation/power/regulator/consumer.txt [new file with mode: 0644]
Documentation/power/regulator/machine.txt [new file with mode: 0644]
Documentation/power/regulator/overview.txt [new file with mode: 0644]
Documentation/power/regulator/regulator.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/Kconfig
drivers/Makefile
drivers/regulator/Kconfig [new file with mode: 0644]
drivers/regulator/Makefile [new file with mode: 0644]
drivers/regulator/bq24022.c [new file with mode: 0644]
drivers/regulator/core.c [new file with mode: 0644]
drivers/regulator/fixed.c [new file with mode: 0644]
drivers/regulator/virtual.c [new file with mode: 0644]
include/linux/regulator/bq24022.h [new file with mode: 0644]
include/linux/regulator/consumer.h [new file with mode: 0644]
include/linux/regulator/driver.h [new file with mode: 0644]
include/linux/regulator/fixed.h [new file with mode: 0644]
include/linux/regulator/machine.h [new file with mode: 0644]

diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
new file mode 100644 (file)
index 0000000..79a4a75
--- /dev/null
@@ -0,0 +1,315 @@
+What:          /sys/class/regulator/.../state
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               state. This holds the regulator output state.
+
+               This will be one of the following strings:
+
+               'enabled'
+               'disabled'
+               'unknown'
+
+               'enabled' means the regulator output is ON and is supplying
+               power to the system.
+
+               'disabled' means the regulator output is OFF and is not
+               supplying power to the system..
+
+               'unknown' means software cannot determine the state.
+
+               NOTE: this field can be used in conjunction with microvolts
+               and microamps to determine regulator output levels.
+
+
+What:          /sys/class/regulator/.../type
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               type. This holds the regulator type.
+
+               This will be one of the following strings:
+
+               'voltage'
+               'current'
+               'unknown'
+
+               'voltage' means the regulator output voltage can be controlled
+               by software.
+
+               'current' means the regulator output current limit can be
+               controlled by software.
+
+               'unknown' means software cannot control either voltage or
+               current limit.
+
+
+What:          /sys/class/regulator/.../microvolts
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               microvolts. This holds the regulator output voltage setting
+               measured in microvolts (i.e. E-6 Volts).
+
+               NOTE: This value should not be used to determine the regulator
+               output voltage level as this value is the same regardless of
+               whether the regulator is enabled or disabled.
+
+
+What:          /sys/class/regulator/.../microamps
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               microamps. This holds the regulator output current limit
+               setting measured in microamps (i.e. E-6 Amps).
+
+               NOTE: This value should not be used to determine the regulator
+               output current level as this value is the same regardless of
+               whether the regulator is enabled or disabled.
+
+
+What:          /sys/class/regulator/.../opmode
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               opmode. This holds the regulator operating mode setting.
+
+               The opmode value can be one of the following strings:
+
+               'fast'
+               'normal'
+               'idle'
+               'standby'
+               'unknown'
+
+               The modes are described in include/linux/regulator/regulator.h
+
+               NOTE: This value should not be used to determine the regulator
+               output operating mode as this value is the same regardless of
+               whether the regulator is enabled or disabled.
+
+
+What:          /sys/class/regulator/.../min_microvolts
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               min_microvolts. This holds the minimum safe working regulator
+               output voltage setting for this domain measured in microvolts.
+
+               NOTE: this will return the string 'constraint not defined' if
+               the power domain has no min microvolts constraint defined by
+               platform code.
+
+
+What:          /sys/class/regulator/.../max_microvolts
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               max_microvolts. This holds the maximum safe working regulator
+               output voltage setting for this domain measured in microvolts.
+
+               NOTE: this will return the string 'constraint not defined' if
+               the power domain has no max microvolts constraint defined by
+               platform code.
+
+
+What:          /sys/class/regulator/.../min_microamps
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               min_microamps. This holds the minimum safe working regulator
+               output current limit setting for this domain measured in
+               microamps.
+
+               NOTE: this will return the string 'constraint not defined' if
+               the power domain has no min microamps constraint defined by
+               platform code.
+
+
+What:          /sys/class/regulator/.../max_microamps
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               max_microamps. This holds the maximum safe working regulator
+               output current limit setting for this domain measured in
+               microamps.
+
+               NOTE: this will return the string 'constraint not defined' if
+               the power domain has no max microamps constraint defined by
+               platform code.
+
+
+What:          /sys/class/regulator/.../num_users
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               num_users. This holds the number of consumer devices that
+               have called regulator_enable() on this regulator.
+
+
+What:          /sys/class/regulator/.../requested_microamps
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               requested_microamps. This holds the total requested load
+               current in microamps for this regulator from all its consumer
+               devices.
+
+
+What:          /sys/class/regulator/.../parent
+Date:          April 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Some regulator directories will contain a link called parent.
+               This points to the parent or supply regulator if one exists.
+
+What:          /sys/class/regulator/.../suspend_mem_microvolts
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_mem_microvolts. This holds the regulator output
+               voltage setting for this domain measured in microvolts when
+               the system is suspended to memory.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to memory voltage defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_disk_microvolts
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_disk_microvolts. This holds the regulator output
+               voltage setting for this domain measured in microvolts when
+               the system is suspended to disk.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to disk voltage defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_standby_microvolts
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_standby_microvolts. This holds the regulator output
+               voltage setting for this domain measured in microvolts when
+               the system is suspended to standby.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to standby voltage defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_mem_mode
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_mem_mode. This holds the regulator operating mode
+               setting for this domain when the system is suspended to
+               memory.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to memory mode defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_disk_mode
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_disk_mode. This holds the regulator operating mode
+               setting for this domain when the system is suspended to disk.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to disk mode defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_standby_mode
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_standby_mode. This holds the regulator operating mode
+               setting for this domain when the system is suspended to
+               standby.
+
+               NOTE: this will return the string 'not defined' if
+               the power domain has no suspend to standby mode defined by
+               platform code.
+
+What:          /sys/class/regulator/.../suspend_mem_state
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_mem_state. This holds the regulator operating state
+               when suspended to memory.
+
+               This will be one of the following strings:
+
+               'enabled'
+               'disabled'
+               'not defined'
+
+What:          /sys/class/regulator/.../suspend_disk_state
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_disk_state. This holds the regulator operating state
+               when suspended to disk.
+
+               This will be one of the following strings:
+
+               'enabled'
+               'disabled'
+               'not defined'
+
+What:          /sys/class/regulator/.../suspend_standby_state
+Date:          May 2008
+KernelVersion: 2.6.26
+Contact:       Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Description:
+               Each regulator directory will contain a field called
+               suspend_standby_state. This holds the regulator operating
+               state when suspended to standby.
+
+               This will be one of the following strings:
+
+               'enabled'
+               'disabled'
+               'not defined'
diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt
new file mode 100644 (file)
index 0000000..82b7a43
--- /dev/null
@@ -0,0 +1,182 @@
+Regulator Consumer Driver Interface
+===================================
+
+This text describes the regulator interface for consumer device drivers.
+Please see overview.txt for a description of the terms used in this text.
+
+
+1. Consumer Regulator Access (static & dynamic drivers)
+=======================================================
+
+A consumer driver can get access to it's supply regulator by calling :-
+
+regulator = regulator_get(dev, "Vcc");
+
+The consumer passes in it's struct device pointer and power supply ID. The core
+then finds the correct regulator by consulting a machine specific lookup table.
+If the lookup is successful then this call will return a pointer to the struct
+regulator that supplies this consumer.
+
+To release the regulator the consumer driver should call :-
+
+regulator_put(regulator);
+
+Consumers can be supplied by more than one regulator e.g. codec consumer with
+analog and digital supplies :-
+
+digital = regulator_get(dev, "Vcc");  /* digital core */
+analog = regulator_get(dev, "Avdd");  /* analog */
+
+The regulator access functions regulator_get() and regulator_put() will
+usually be called in your device drivers probe() and remove() respectively.
+
+
+2. Regulator Output Enable & Disable (static & dynamic drivers)
+====================================================================
+
+A consumer can enable it's power supply by calling:-
+
+int regulator_enable(regulator);
+
+NOTE: The supply may already be enabled before regulator_enabled() is called.
+This may happen if the consumer shares the regulator or the regulator has been
+previously enabled by bootloader or kernel board initialization code.
+
+A consumer can determine if a regulator is enabled by calling :-
+
+int regulator_is_enabled(regulator);
+
+This will return > zero when the regulator is enabled.
+
+
+A consumer can disable it's supply when no longer needed by calling :-
+
+int regulator_disable(regulator);
+
+NOTE: This may not disable the supply if it's shared with other consumers. The
+regulator will only be disabled when the enabled reference count is zero.
+
+Finally, a regulator can be forcefully disabled in the case of an emergency :-
+
+int regulator_force_disable(regulator);
+
+NOTE: this will immediately and forcefully shutdown the regulator output. All
+consumers will be powered off.
+
+
+3. Regulator Voltage Control & Status (dynamic drivers)
+======================================================
+
+Some consumer drivers need to be able to dynamically change their supply
+voltage to match system operating points. e.g. CPUfreq drivers can scale
+voltage along with frequency to save power, SD drivers may need to select the
+correct card voltage, etc.
+
+Consumers can control their supply voltage by calling :-
+
+int regulator_set_voltage(regulator, min_uV, max_uV);
+
+Where min_uV and max_uV are the minimum and maximum acceptable voltages in
+microvolts.
+
+NOTE: this can be called when the regulator is enabled or disabled. If called
+when enabled, then the voltage changes instantly, otherwise the voltage
+configuration changes and the voltage is physically set when the regulator is
+next enabled.
+
+The regulators configured voltage output can be found by calling :-
+
+int regulator_get_voltage(regulator);
+
+NOTE: get_voltage() will return the configured output voltage whether the
+regulator is enabled or disabled and should NOT be used to determine regulator
+output state. However this can be used in conjunction with is_enabled() to
+determine the regulator physical output voltage.
+
+
+4. Regulator Current Limit Control & Status (dynamic drivers)
+===========================================================
+
+Some consumer drivers need to be able to dynamically change their supply
+current limit to match system operating points. e.g. LCD backlight driver can
+change the current limit to vary the backlight brightness, USB drivers may want
+to set the limit to 500mA when supplying power.
+
+Consumers can control their supply current limit by calling :-
+
+int regulator_set_current_limit(regulator, min_uV, max_uV);
+
+Where min_uA and max_uA are the minimum and maximum acceptable current limit in
+microamps.
+
+NOTE: this can be called when the regulator is enabled or disabled. If called
+when enabled, then the current limit changes instantly, otherwise the current
+limit configuration changes and the current limit is physically set when the
+regulator is next enabled.
+
+A regulators current limit can be found by calling :-
+
+int regulator_get_current_limit(regulator);
+
+NOTE: get_current_limit() will return the current limit whether the regulator
+is enabled or disabled and should not be used to determine regulator current
+load.
+
+
+5. Regulator Operating Mode Control & Status (dynamic drivers)
+=============================================================
+
+Some consumers can further save system power by changing the operating mode of
+their supply regulator to be more efficient when the consumers operating state
+changes. e.g. consumer driver is idle and subsequently draws less current
+
+Regulator operating mode can be changed indirectly or directly.
+
+Indirect operating mode control.
+--------------------------------
+Consumer drivers can request a change in their supply regulator operating mode
+by calling :-
+
+int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
+
+This will cause the core to recalculate the total load on the regulator (based
+on all it's consumers) and change operating mode (if necessary and permitted)
+to best match the current operating load.
+
+The load_uA value can be determined from the consumers datasheet. e.g.most
+datasheets have tables showing the max current consumed in certain situations.
+
+Most consumers will use indirect operating mode control since they have no
+knowledge of the regulator or whether the regulator is shared with other
+consumers.
+
+Direct operating mode control.
+------------------------------
+Bespoke or tightly coupled drivers may want to directly control regulator
+operating mode depending on their operating point. This can be achieved by
+calling :-
+
+int regulator_set_mode(struct regulator *regulator, unsigned int mode);
+unsigned int regulator_get_mode(struct regulator *regulator);
+
+Direct mode will only be used by consumers that *know* about the regulator and
+are not sharing the regulator with other consumers.
+
+
+6. Regulator Events
+===================
+Regulators can notify consumers of external events. Events could be received by
+consumers under regulator stress or failure conditions.
+
+Consumers can register interest in regulator events by calling :-
+
+int regulator_register_notifier(struct regulator *regulator,
+                             struct notifier_block *nb);
+
+Consumers can uregister interest by calling :-
+
+int regulator_unregister_notifier(struct regulator *regulator,
+                               struct notifier_block *nb);
+
+Regulators use the kernel notifier framework to send event to thier interested
+consumers.
diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt
new file mode 100644 (file)
index 0000000..c9a3566
--- /dev/null
@@ -0,0 +1,101 @@
+Regulator Machine Driver Interface
+===================================
+
+The regulator machine driver interface is intended for board/machine specific
+initialisation code to configure the regulator subsystem. Typical things that
+machine drivers would do are :-
+
+ 1. Regulator -> Device mapping.
+ 2. Regulator supply configuration.
+ 3. Power Domain constraint setting.
+
+
+
+1. Regulator -> device mapping
+==============================
+Consider the following machine :-
+
+  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
+               |
+               +-> [Consumer B @ 3.3V]
+
+The drivers for consumers A & B must be mapped to the correct regulator in
+order to control their power supply. This mapping can be achieved in machine
+initialisation code by calling :-
+
+int regulator_set_device_supply(const char *regulator, struct device *dev,
+                               const char *supply);
+
+and is shown with the following code :-
+
+regulator_set_device_supply("Regulator-1", devB, "Vcc");
+regulator_set_device_supply("Regulator-2", devA, "Vcc");
+
+This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
+to the 'Vcc' supply for Consumer A.
+
+
+2. Regulator supply configuration.
+==================================
+Consider the following machine (again) :-
+
+  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
+               |
+               +-> [Consumer B @ 3.3V]
+
+Regulator-1 supplies power to Regulator-2. This relationship must be registered
+with the core so that Regulator-1 is also enabled when Consumer A enables it's
+supply (Regulator-2).
+
+This relationship can be register with the core via :-
+
+int regulator_set_supply(const char *regulator, const char *regulator_supply);
+
+In this example we would use the following code :-
+
+regulator_set_supply("Regulator-2", "Regulator-1");
+
+Relationships can be queried by calling :-
+
+const char *regulator_get_supply(const char *regulator);
+
+
+3. Power Domain constraint setting.
+===================================
+Each power domain within a system has physical constraints on voltage and
+current. This must be defined in software so that the power domain is always
+operated within specifications.
+
+Consider the following machine (again) :-
+
+  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
+               |
+               +-> [Consumer B @ 3.3V]
+
+This gives us two regulators and two power domains:
+
+                   Domain 1: Regulator-2, Consumer B.
+                   Domain 2: Consumer A.
+
+Constraints can be registered by calling :-
+
+int regulator_set_platform_constraints(const char *regulator,
+       struct regulation_constraints *constraints);
+
+The example is defined as follows :-
+
+struct regulation_constraints domain_1 = {
+       .min_uV = 3300000,
+       .max_uV = 3300000,
+       .valid_modes_mask = REGULATOR_MODE_NORMAL,
+};
+
+struct regulation_constraints domain_2 = {
+       .min_uV = 1800000,
+       .max_uV = 2000000,
+       .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+       .valid_modes_mask = REGULATOR_MODE_NORMAL,
+};
+
+regulator_set_platform_constraints("Regulator-1", &domain_1);
+regulator_set_platform_constraints("Regulator-2", &domain_2);
diff --git a/Documentation/power/regulator/overview.txt b/Documentation/power/regulator/overview.txt
new file mode 100644 (file)
index 0000000..bdcb332
--- /dev/null
@@ -0,0 +1,171 @@
+Linux voltage and current regulator framework
+=============================================
+
+About
+=====
+
+This framework is designed to provide a standard kernel interface to control
+voltage and current regulators.
+
+The intention is to allow systems to dynamically control regulator power output
+in order to save power and prolong battery life. This applies to both voltage
+regulators (where voltage output is controllable) and current sinks (where
+current limit is controllable).
+
+(C) 2008  Wolfson Microelectronics PLC.
+Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+
+
+Nomenclature
+============
+
+Some terms used in this document:-
+
+  o Regulator    - Electronic device that supplies power to other devices.
+                   Most regulators can enable and disable their output whilst
+                   some can control their output voltage and or current.
+
+                   Input Voltage -> Regulator -> Output Voltage
+
+
+  o PMIC         - Power Management IC. An IC that contains numerous regulators
+                   and often contains other susbsystems.
+
+
+  o Consumer     - Electronic device that is supplied power by a regulator.
+                   Consumers can be classified into two types:-
+
+                   Static: consumer does not change it's supply voltage or
+                   current limit. It only needs to enable or disable it's
+                   power supply. It's supply voltage is set by the hardware,
+                   bootloader, firmware or kernel board initialisation code.
+
+                   Dynamic: consumer needs to change it's supply voltage or
+                   current limit to meet operation demands.
+
+
+  o Power Domain - Electronic circuit that is supplied it's input power by the
+                   output power of a regulator, switch or by another power
+                   domain.
+
+                   The supply regulator may be behind a switch(s). i.e.
+
+                   Regulator -+-> Switch-1 -+-> Switch-2 --> [Consumer A]
+                              |             |
+                              |             +-> [Consumer B], [Consumer C]
+                              |
+                              +-> [Consumer D], [Consumer E]
+
+                   That is one regulator and three power domains:
+
+                   Domain 1: Switch-1, Consumers D & E.
+                   Domain 2: Switch-2, Consumers B & C.
+                   Domain 3: Consumer A.
+
+                   and this represents a "supplies" relationship:
+
+                   Domain-1 --> Domain-2 --> Domain-3.
+
+                   A power domain may have regulators that are supplied power
+                   by other regulators. i.e.
+
+                   Regulator-1 -+-> Regulator-2 -+-> [Consumer A]
+                                |
+                                +-> [Consumer B]
+
+                   This gives us two regulators and two power domains:
+
+                   Domain 1: Regulator-2, Consumer B.
+                   Domain 2: Consumer A.
+
+                   and a "supplies" relationship:
+
+                   Domain-1 --> Domain-2
+
+
+  o Constraints  - Constraints are used to define power levels for performance
+                   and hardware protection. Constraints exist at three levels:
+
+                   Regulator Level: This is defined by the regulator hardware
+                   operating parameters and is specified in the regulator
+                   datasheet. i.e.
+
+                     - voltage output is in the range 800mV -> 3500mV.
+                     - regulator current output limit is 20mA @ 5V but is
+                       10mA @ 10V.
+
+                   Power Domain Level: This is defined in software by kernel
+                   level board initialisation code. It is used to constrain a
+                   power domain to a particular power range. i.e.
+
+                     - Domain-1 voltage is 3300mV
+                     - Domain-2 voltage is 1400mV -> 1600mV
+                     - Domain-3 current limit is 0mA -> 20mA.
+
+                   Consumer Level: This is defined by consumer drivers
+                   dynamically setting voltage or current limit levels.
+
+                   e.g. a consumer backlight driver asks for a current increase
+                   from 5mA to 10mA to increase LCD illumination. This passes
+                   to through the levels as follows :-
+
+                   Consumer: need to increase LCD brightness. Lookup and
+                   request next current mA value in brightness table (the
+                   consumer driver could be used on several different
+                   personalities based upon the same reference device).
+
+                   Power Domain: is the new current limit within the domain
+                   operating limits for this domain and system state (e.g.
+                   battery power, USB power)
+
+                   Regulator Domains: is the new current limit within the
+                   regulator operating parameters for input/ouput voltage.
+
+                   If the regulator request passes all the constraint tests
+                   then the new regulator value is applied.
+
+
+Design
+======
+
+The framework is designed and targeted at SoC based devices but may also be
+relevant to non SoC devices and is split into the following four interfaces:-
+
+
+   1. Consumer driver interface.
+
+      This uses a similar API to the kernel clock interface in that consumer
+      drivers can get and put a regulator (like they can with clocks atm) and
+      get/set voltage, current limit, mode, enable and disable. This should
+      allow consumers complete control over their supply voltage and current
+      limit. This also compiles out if not in use so drivers can be reused in
+      systems with no regulator based power control.
+
+        See Documentation/power/regulator/consumer.txt
+
+   2. Regulator driver interface.
+
+      This allows regulator drivers to register their regulators and provide
+      operations to the core. It also has a notifier call chain for propagating
+      regulator events to clients.
+
+        See Documentation/power/regulator/regulator.txt
+
+   3. Machine interface.
+
+      This interface is for machine specific code and allows the creation of
+      voltage/current domains (with constraints) for each regulator. It can
+      provide regulator constraints that will prevent device damage through
+      overvoltage or over current caused by buggy client drivers. It also
+      allows the creation of a regulator tree whereby some regulators are
+      supplied by others (similar to a clock tree).
+
+        See Documentation/power/regulator/machine.txt
+
+   4. Userspace ABI.
+
+      The framework also exports a lot of useful voltage/current/opmode data to
+      userspace via sysfs. This could be used to help monitor device power
+      consumption and status.
+
+        See Documentation/ABI/testing/regulator-sysfs.txt
diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt
new file mode 100644 (file)
index 0000000..a690501
--- /dev/null
@@ -0,0 +1,30 @@
+Regulator Driver Interface
+==========================
+
+The regulator driver interface is relatively simple and designed to allow
+regulator drivers to register their services with the core framework.
+
+
+Registration
+============
+
+Drivers can register a regulator by calling :-
+
+struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
+                                         void *reg_data);
+
+This will register the regulators capabilities and operations the regulator
+core. The core does not touch reg_data (private to regulator driver).
+
+Regulators can be unregistered by calling :-
+
+void regulator_unregister(struct regulator_dev *rdev);
+
+
+Regulator Events
+================
+Regulators can send events (e.g. over temp, under voltage, etc) to consumer
+drivers by calling :-
+
+int regulator_notifier_call_chain(struct regulator_dev *rdev,
+                                 unsigned long event, void *data);
index 5f043d1..c65a5b9 100644 (file)
@@ -4504,6 +4504,15 @@ M:       kaber@trash.net
 L:     netdev@vger.kernel.org
 S:     Maintained
 
+VOLTAGE AND CURRENT REGULATOR FRAMEWORK
+P:     Liam Girdwood
+M:     lg@opensource.wolfsonmicro.com
+P:     Mark Brown
+M:     broonie@opensource.wolfsonmicro.com
+W:     http://opensource.wolfsonmicro.com/node/15
+T:     git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
+S:     Supported
+
 VT1211 HARDWARE MONITOR DRIVER
 P:     Juerg Haefliger
 M:     juergh@gmail.com
index 257033c..4b8acd2 100644 (file)
@@ -1225,6 +1225,8 @@ source "drivers/dma/Kconfig"
 
 source "drivers/dca/Kconfig"
 
+source "drivers/regulator/Kconfig"
+
 source "drivers/uio/Kconfig"
 
 endmenu
index 54ec5e7..a280ab3 100644 (file)
@@ -97,3 +97,4 @@ obj-$(CONFIG_PPC_PS3)         += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
 obj-$(CONFIG_VIRTIO)           += virtio/
+obj-$(CONFIG_REGULATOR)                += regulator/
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
new file mode 100644 (file)
index 0000000..a656128
--- /dev/null
@@ -0,0 +1,59 @@
+menu "Voltage and Current regulators"
+
+config REGULATOR
+       bool "Voltage and Current Regulator Support"
+       default n
+       help
+         Generic Voltage and Current Regulator support.
+
+         This framework is designed to provide a generic interface to voltage
+         and current regulators within the Linux kernel. It's intended to
+         provide voltage and current control to client or consumer drivers and
+         also provide status information to user space applications through a
+         sysfs interface.
+
+         The intention is to allow systems to dynamically control regulator
+         output in order to save power and prolong battery life. This applies
+         to both voltage regulators (where voltage output is controllable) and
+         current sinks (where current output is controllable).
+
+         This framework safely compiles out if not selected so that client
+         drivers can still be used in systems with no software controllable
+         regulators.
+
+         If unsure, say no.
+
+config REGULATOR_DEBUG
+       bool "Regulator debug support"
+       depends on REGULATOR
+       help
+         Say yes here to enable debugging support.
+
+config REGULATOR_FIXED_VOLTAGE
+       tristate
+       default n
+       select REGULATOR
+
+config REGULATOR_VIRTUAL_CONSUMER
+       tristate "Virtual regulator consumer support"
+       default n
+       select REGULATOR
+       help
+         This driver provides a virtual consumer for the voltage and
+          current regulator API which provides sysfs controls for
+          configuring the supplies requested.  This is mainly useful
+          for test purposes.
+
+          If unsure, say no.
+
+config REGULATOR_BQ24022
+       tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
+       default n
+       select REGULATOR
+       help
+         This driver controls a TI bq24022 Charger attached via
+         GPIOs. The provided current regulator can enable/disable
+         charging select between 100 mA and 500 mA charging current
+         limit.
+
+endmenu
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
new file mode 100644 (file)
index 0000000..ac2c64e
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for regulator drivers.
+#
+
+
+obj-$(CONFIG_REGULATOR) += core.o
+obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
+obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
+
+obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+
+ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
new file mode 100644 (file)
index 0000000..263699d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
+ * 1-Cell Li-Ion Charger connected via GPIOs.
+ *
+ * Copyright (c) 2008 Philipp Zabel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/regulator/bq24022.h>
+#include <linux/regulator/driver.h>
+
+static int bq24022_set_current_limit(struct regulator_dev *rdev,
+                                       int min_uA, int max_uA)
+{
+       struct platform_device *pdev = rdev_get_drvdata(rdev);
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+
+       dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
+               max_uA >= 500000 ? "500" : "100");
+
+       /* REVISIT: maybe return error if min_uA != 0 ? */
+       gpio_set_value(pdata->gpio_iset2, max_uA >= 500000);
+       return 0;
+}
+
+static int bq24022_get_current_limit(struct regulator_dev *rdev)
+{
+       struct platform_device *pdev = rdev_get_drvdata(rdev);
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+
+       return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
+}
+
+static int bq24022_enable(struct regulator_dev *rdev)
+{
+       struct platform_device *pdev = rdev_get_drvdata(rdev);
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+
+       dev_dbg(&pdev->dev, "enabling charger\n");
+
+       gpio_set_value(pdata->gpio_nce, 0);
+       return 0;
+}
+
+static int bq24022_disable(struct regulator_dev *rdev)
+{
+       struct platform_device *pdev = rdev_get_drvdata(rdev);
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+
+       dev_dbg(&pdev->dev, "disabling charger\n");
+
+       gpio_set_value(pdata->gpio_nce, 1);
+       return 0;
+}
+
+static int bq24022_is_enabled(struct regulator_dev *rdev)
+{
+       struct platform_device *pdev = rdev_get_drvdata(rdev);
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+
+       return !gpio_get_value(pdata->gpio_nce);
+}
+
+static struct regulator_ops bq24022_ops = {
+       .set_current_limit = bq24022_set_current_limit,
+       .get_current_limit = bq24022_get_current_limit,
+       .enable            = bq24022_enable,
+       .disable           = bq24022_disable,
+       .is_enabled        = bq24022_is_enabled,
+};
+
+static struct regulator_desc bq24022_desc = {
+       .name  = "bq24022",
+       .ops   = &bq24022_ops,
+       .type  = REGULATOR_CURRENT,
+};
+
+static int __init bq24022_probe(struct platform_device *pdev)
+{
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct regulator_dev *bq24022;
+       int ret;
+
+       if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2)
+               return -EINVAL;
+
+       ret = gpio_request(pdata->gpio_nce, "ncharge_en");
+       if (ret) {
+               dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n",
+                       pdata->gpio_nce);
+               goto err_ce;
+       }
+       ret = gpio_request(pdata->gpio_iset2, "charge_mode");
+       if (ret) {
+               dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n",
+                       pdata->gpio_iset2);
+               goto err_iset2;
+       }
+       ret = gpio_direction_output(pdata->gpio_iset2, 0);
+       ret = gpio_direction_output(pdata->gpio_nce, 1);
+
+       bq24022 = regulator_register(&bq24022_desc, pdev);
+       if (IS_ERR(bq24022)) {
+               dev_dbg(&pdev->dev, "couldn't register regulator\n");
+               ret = PTR_ERR(bq24022);
+               goto err_reg;
+       }
+       platform_set_drvdata(pdev, bq24022);
+       dev_dbg(&pdev->dev, "registered regulator\n");
+
+       return 0;
+err_reg:
+       gpio_free(pdata->gpio_iset2);
+err_iset2:
+       gpio_free(pdata->gpio_nce);
+err_ce:
+       return ret;
+}
+
+static int __devexit bq24022_remove(struct platform_device *pdev)
+{
+       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+       struct regulator_dev *bq24022 = platform_get_drvdata(pdev);
+
+       regulator_unregister(bq24022);
+       gpio_free(pdata->gpio_iset2);
+       gpio_free(pdata->gpio_nce);
+
+       return 0;
+}
+
+static struct platform_driver bq24022_driver = {
+       .driver = {
+               .name = "bq24022",
+       },
+       .remove = __devexit_p(bq24022_remove),
+};
+
+static int __init bq24022_init(void)
+{
+       return platform_driver_probe(&bq24022_driver, bq24022_probe);
+}
+
+static void __exit bq24022_exit(void)
+{
+       platform_driver_unregister(&bq24022_driver);
+}
+
+/*
+ * make sure this is probed before gpio_vbus and pda_power,
+ * but after asic3 or other GPIO expander drivers.
+ */
+subsys_initcall(bq24022_init);
+module_exit(bq24022_exit);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
new file mode 100644 (file)
index 0000000..9c79862
--- /dev/null
@@ -0,0 +1,1903 @@
+/*
+ * core.c  --  Voltage/Current Regulator framework.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define REGULATOR_VERSION "0.5"
+
+static DEFINE_MUTEX(regulator_list_mutex);
+static LIST_HEAD(regulator_list);
+static LIST_HEAD(regulator_map_list);
+
+/**
+ * struct regulator_dev
+ *
+ * Voltage / Current regulator class device. One for each regulator.
+ */
+struct regulator_dev {
+       struct regulator_desc *desc;
+       int use_count;
+
+       /* lists we belong to */
+       struct list_head list; /* list of all regulators */
+       struct list_head slist; /* list of supplied regulators */
+
+       /* lists we own */
+       struct list_head consumer_list; /* consumers we supply */
+       struct list_head supply_list; /* regulators we supply */
+
+       struct blocking_notifier_head notifier;
+       struct mutex mutex; /* consumer lock */
+       struct module *owner;
+       struct device dev;
+       struct regulation_constraints *constraints;
+       struct regulator_dev *supply;   /* for tree */
+
+       void *reg_data;         /* regulator_dev data */
+};
+
+/**
+ * struct regulator_map
+ *
+ * Used to provide symbolic supply names to devices.
+ */
+struct regulator_map {
+       struct list_head list;
+       struct device *dev;
+       const char *supply;
+       const char *regulator;
+};
+
+static inline struct regulator_dev *to_rdev(struct device *d)
+{
+       return container_of(d, struct regulator_dev, dev);
+}
+
+/*
+ * struct regulator
+ *
+ * One for each consumer device.
+ */
+struct regulator {
+       struct device *dev;
+       struct list_head list;
+       int uA_load;
+       int min_uV;
+       int max_uV;
+       int enabled; /* client has called enabled */
+       char *supply_name;
+       struct device_attribute dev_attr;
+       struct regulator_dev *rdev;
+};
+
+static int _regulator_is_enabled(struct regulator_dev *rdev);
+static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_get_voltage(struct regulator_dev *rdev);
+static int _regulator_get_current_limit(struct regulator_dev *rdev);
+static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
+static void _notifier_call_chain(struct regulator_dev *rdev,
+                                 unsigned long event, void *data);
+
+/* gets the regulator for a given consumer device */
+static struct regulator *get_device_regulator(struct device *dev)
+{
+       struct regulator *regulator = NULL;
+       struct regulator_dev *rdev;
+
+       mutex_lock(&regulator_list_mutex);
+       list_for_each_entry(rdev, &regulator_list, list) {
+               mutex_lock(&rdev->mutex);
+               list_for_each_entry(regulator, &rdev->consumer_list, list) {
+                       if (regulator->dev == dev) {
+                               mutex_unlock(&rdev->mutex);
+                               mutex_unlock(&regulator_list_mutex);
+                               return regulator;
+                       }
+               }
+               mutex_unlock(&rdev->mutex);
+       }
+       mutex_unlock(&regulator_list_mutex);
+       return NULL;
+}
+
+/* Platform voltage constraint check */
+static int regulator_check_voltage(struct regulator_dev *rdev,
+                                  int *min_uV, int *max_uV)
+{
+       BUG_ON(*min_uV > *max_uV);
+
+       if (!rdev->constraints) {
+               printk(KERN_ERR "%s: no constraints for %s\n", __func__,
+                      rdev->desc->name);
+               return -ENODEV;
+       }
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+               printk(KERN_ERR "%s: operation not allowed for %s\n",
+                      __func__, rdev->desc->name);
+               return -EPERM;
+       }
+
+       if (*max_uV > rdev->constraints->max_uV)
+               *max_uV = rdev->constraints->max_uV;
+       if (*min_uV < rdev->constraints->min_uV)
+               *min_uV = rdev->constraints->min_uV;
+
+       if (*min_uV > *max_uV)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* current constraint check */
+static int regulator_check_current_limit(struct regulator_dev *rdev,
+                                       int *min_uA, int *max_uA)
+{
+       BUG_ON(*min_uA > *max_uA);
+
+       if (!rdev->constraints) {
+               printk(KERN_ERR "%s: no constraints for %s\n", __func__,
+                      rdev->desc->name);
+               return -ENODEV;
+       }
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
+               printk(KERN_ERR "%s: operation not allowed for %s\n",
+                      __func__, rdev->desc->name);
+               return -EPERM;
+       }
+
+       if (*max_uA > rdev->constraints->max_uA)
+               *max_uA = rdev->constraints->max_uA;
+       if (*min_uA < rdev->constraints->min_uA)
+               *min_uA = rdev->constraints->min_uA;
+
+       if (*min_uA > *max_uA)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* operating mode constraint check */
+static int regulator_check_mode(struct regulator_dev *rdev, int mode)
+{
+       if (!rdev->constraints) {
+               printk(KERN_ERR "%s: no constraints for %s\n", __func__,
+                      rdev->desc->name);
+               return -ENODEV;
+       }
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
+               printk(KERN_ERR "%s: operation not allowed for %s\n",
+                      __func__, rdev->desc->name);
+               return -EPERM;
+       }
+       if (!(rdev->constraints->valid_modes_mask & mode)) {
+               printk(KERN_ERR "%s: invalid mode %x for %s\n",
+                      __func__, mode, rdev->desc->name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* dynamic regulator mode switching constraint check */
+static int regulator_check_drms(struct regulator_dev *rdev)
+{
+       if (!rdev->constraints) {
+               printk(KERN_ERR "%s: no constraints for %s\n", __func__,
+                      rdev->desc->name);
+               return -ENODEV;
+       }
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
+               printk(KERN_ERR "%s: operation not allowed for %s\n",
+                      __func__, rdev->desc->name);
+               return -EPERM;
+       }
+       return 0;
+}
+
+static ssize_t device_requested_uA_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct regulator *regulator;
+
+       regulator = get_device_regulator(dev);
+       if (regulator == NULL)
+               return 0;
+
+       return sprintf(buf, "%d\n", regulator->uA_load);
+}
+
+static ssize_t regulator_uV_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       ssize_t ret;
+
+       mutex_lock(&rdev->mutex);
+       ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
+       mutex_unlock(&rdev->mutex);
+
+       return ret;
+}
+
+static ssize_t regulator_uA_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
+}
+
+static ssize_t regulator_opmode_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       int mode = _regulator_get_mode(rdev);
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               return sprintf(buf, "fast\n");
+       case REGULATOR_MODE_NORMAL:
+               return sprintf(buf, "normal\n");
+       case REGULATOR_MODE_IDLE:
+               return sprintf(buf, "idle\n");
+       case REGULATOR_MODE_STANDBY:
+               return sprintf(buf, "standby\n");
+       }
+       return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       int state = _regulator_is_enabled(rdev);
+
+       if (state > 0)
+               return sprintf(buf, "enabled\n");
+       else if (state == 0)
+               return sprintf(buf, "disabled\n");
+       else
+               return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_min_uA_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "constraint not defined\n");
+
+       return sprintf(buf, "%d\n", rdev->constraints->min_uA);
+}
+
+static ssize_t regulator_max_uA_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "constraint not defined\n");
+
+       return sprintf(buf, "%d\n", rdev->constraints->max_uA);
+}
+
+static ssize_t regulator_min_uV_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "constraint not defined\n");
+
+       return sprintf(buf, "%d\n", rdev->constraints->min_uV);
+}
+
+static ssize_t regulator_max_uV_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "constraint not defined\n");
+
+       return sprintf(buf, "%d\n", rdev->constraints->max_uV);
+}
+
+static ssize_t regulator_total_uA_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       struct regulator *regulator;
+       int uA = 0;
+
+       mutex_lock(&rdev->mutex);
+       list_for_each_entry(regulator, &rdev->consumer_list, list)
+           uA += regulator->uA_load;
+       mutex_unlock(&rdev->mutex);
+       return sprintf(buf, "%d\n", uA);
+}
+
+static ssize_t regulator_num_users_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       return sprintf(buf, "%d\n", rdev->use_count);
+}
+
+static ssize_t regulator_type_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       switch (rdev->desc->type) {
+       case REGULATOR_VOLTAGE:
+               return sprintf(buf, "voltage\n");
+       case REGULATOR_CURRENT:
+               return sprintf(buf, "current\n");
+       }
+       return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV);
+}
+
+static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV);
+}
+
+static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV);
+}
+
+static ssize_t suspend_opmode_show(struct regulator_dev *rdev,
+       unsigned int mode, char *buf)
+{
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               return sprintf(buf, "fast\n");
+       case REGULATOR_MODE_NORMAL:
+               return sprintf(buf, "normal\n");
+       case REGULATOR_MODE_IDLE:
+               return sprintf(buf, "idle\n");
+       case REGULATOR_MODE_STANDBY:
+               return sprintf(buf, "standby\n");
+       }
+       return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return suspend_opmode_show(rdev,
+               rdev->constraints->state_mem.mode, buf);
+}
+
+static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return suspend_opmode_show(rdev,
+               rdev->constraints->state_disk.mode, buf);
+}
+
+static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+       return suspend_opmode_show(rdev,
+               rdev->constraints->state_standby.mode, buf);
+}
+
+static ssize_t regulator_suspend_mem_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+
+       if (rdev->constraints->state_mem.enabled)
+               return sprintf(buf, "enabled\n");
+       else
+               return sprintf(buf, "disabled\n");
+}
+
+static ssize_t regulator_suspend_disk_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+
+       if (rdev->constraints->state_disk.enabled)
+               return sprintf(buf, "enabled\n");
+       else
+               return sprintf(buf, "disabled\n");
+}
+
+static ssize_t regulator_suspend_standby_state_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+
+       if (!rdev->constraints)
+               return sprintf(buf, "not defined\n");
+
+       if (rdev->constraints->state_standby.enabled)
+               return sprintf(buf, "enabled\n");
+       else
+               return sprintf(buf, "disabled\n");
+}
+static struct device_attribute regulator_dev_attrs[] = {
+       __ATTR(microvolts, 0444, regulator_uV_show, NULL),
+       __ATTR(microamps, 0444, regulator_uA_show, NULL),
+       __ATTR(opmode, 0444, regulator_opmode_show, NULL),
+       __ATTR(state, 0444, regulator_state_show, NULL),
+       __ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL),
+       __ATTR(min_microamps, 0444, regulator_min_uA_show, NULL),
+       __ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL),
+       __ATTR(max_microamps, 0444, regulator_max_uA_show, NULL),
+       __ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL),
+       __ATTR(num_users, 0444, regulator_num_users_show, NULL),
+       __ATTR(type, 0444, regulator_type_show, NULL),
+       __ATTR(suspend_mem_microvolts, 0444,
+               regulator_suspend_mem_uV_show, NULL),
+       __ATTR(suspend_disk_microvolts, 0444,
+               regulator_suspend_disk_uV_show, NULL),
+       __ATTR(suspend_standby_microvolts, 0444,
+               regulator_suspend_standby_uV_show, NULL),
+       __ATTR(suspend_mem_mode, 0444,
+               regulator_suspend_mem_mode_show, NULL),
+       __ATTR(suspend_disk_mode, 0444,
+               regulator_suspend_disk_mode_show, NULL),
+       __ATTR(suspend_standby_mode, 0444,
+               regulator_suspend_standby_mode_show, NULL),
+       __ATTR(suspend_mem_state, 0444,
+               regulator_suspend_mem_state_show, NULL),
+       __ATTR(suspend_disk_state, 0444,
+               regulator_suspend_disk_state_show, NULL),
+       __ATTR(suspend_standby_state, 0444,
+               regulator_suspend_standby_state_show, NULL),
+       __ATTR_NULL,
+};
+
+static void regulator_dev_release(struct device *dev)
+{
+       struct regulator_dev *rdev = to_rdev(dev);
+       kfree(rdev);
+}
+
+static struct class regulator_class = {
+       .name = "regulator",
+       .dev_release = regulator_dev_release,
+       .dev_attrs = regulator_dev_attrs,
+};
+
+/* Calculate the new optimum regulator operating mode based on the new total
+ * consumer load. All locks held by caller */
+static void drms_uA_update(struct regulator_dev *rdev)
+{
+       struct regulator *sibling;
+       int current_uA = 0, output_uV, input_uV, err;
+       unsigned int mode;
+
+       err = regulator_check_drms(rdev);
+       if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
+           !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode);
+       return;
+
+       /* get output voltage */
+       output_uV = rdev->desc->ops->get_voltage(rdev);
+       if (output_uV <= 0)
+               return;
+
+       /* get input voltage */
+       if (rdev->supply && rdev->supply->desc->ops->get_voltage)
+               input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply);
+       else
+               input_uV = rdev->constraints->input_uV;
+       if (input_uV <= 0)
+               return;
+
+       /* calc total requested load */
+       list_for_each_entry(sibling, &rdev->consumer_list, list)
+           current_uA += sibling->uA_load;
+
+       /* now get the optimum mode for our new total regulator load */
+       mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
+                                                 output_uV, current_uA);
+
+       /* check the new mode is allowed */
+       err = regulator_check_mode(rdev, mode);
+       if (err == 0)
+               rdev->desc->ops->set_mode(rdev, mode);
+}
+
+static int suspend_set_state(struct regulator_dev *rdev,
+       struct regulator_state *rstate)
+{
+       int ret = 0;
+
+       /* enable & disable are mandatory for suspend control */
+       if (!rdev->desc->ops->set_suspend_enable ||
+               !rdev->desc->ops->set_suspend_disable)
+               return -EINVAL;
+
+       if (rstate->enabled)
+               ret = rdev->desc->ops->set_suspend_enable(rdev);
+       else
+               ret = rdev->desc->ops->set_suspend_disable(rdev);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: failed to enabled/disable\n", __func__);
+               return ret;
+       }
+
+       if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) {
+               ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to set voltage\n",
+                               __func__);
+                       return ret;
+               }
+       }
+
+       if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) {
+               ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to set mode\n", __func__);
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+/* locks held by caller */
+static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
+{
+       if (!rdev->constraints)
+               return -EINVAL;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+               return suspend_set_state(rdev,
+                       &rdev->constraints->state_standby);
+       case PM_SUSPEND_MEM:
+               return suspend_set_state(rdev,
+                       &rdev->constraints->state_mem);
+       case PM_SUSPEND_MAX:
+               return suspend_set_state(rdev,
+                       &rdev->constraints->state_disk);
+       default:
+               return -EINVAL;
+       }
+}
+
+static void print_constraints(struct regulator_dev *rdev)
+{
+       struct regulation_constraints *constraints = rdev->constraints;
+       char buf[80];
+       int count;
+
+       if (rdev->desc->type == REGULATOR_VOLTAGE) {
+               if (constraints->min_uV == constraints->max_uV)
+                       count = sprintf(buf, "%d mV ",
+                                       constraints->min_uV / 1000);
+               else
+                       count = sprintf(buf, "%d <--> %d mV ",
+                                       constraints->min_uV / 1000,
+                                       constraints->max_uV / 1000);
+       } else {
+               if (constraints->min_uA == constraints->max_uA)
+                       count = sprintf(buf, "%d mA ",
+                                       constraints->min_uA / 1000);
+               else
+                       count = sprintf(buf, "%d <--> %d mA ",
+                                       constraints->min_uA / 1000,
+                                       constraints->max_uA / 1000);
+       }
+       if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
+               count += sprintf(buf + count, "fast ");
+       if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
+               count += sprintf(buf + count, "normal ");
+       if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE)
+               count += sprintf(buf + count, "idle ");
+       if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
+               count += sprintf(buf + count, "standby");
+
+       printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
+}
+
+#define REG_STR_SIZE   32
+
+static struct regulator *create_regulator(struct regulator_dev *rdev,
+                                         struct device *dev,
+                                         const char *supply_name)
+{
+       struct regulator *regulator;
+       char buf[REG_STR_SIZE];
+       int err, size;
+
+       regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
+       if (regulator == NULL)
+               return NULL;
+
+       mutex_lock(&rdev->mutex);
+       regulator->rdev = rdev;
+       list_add(&regulator->list, &rdev->consumer_list);
+
+       if (dev) {
+               /* create a 'requested_microamps_name' sysfs entry */
+               size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s",
+                       supply_name);
+               if (size >= REG_STR_SIZE)
+                       goto overflow_err;
+
+               regulator->dev = dev;
+               regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
+               if (regulator->dev_attr.attr.name == NULL)
+                       goto attr_name_err;
+
+               regulator->dev_attr.attr.owner = THIS_MODULE;
+               regulator->dev_attr.attr.mode = 0444;
+               regulator->dev_attr.show = device_requested_uA_show;
+               err = device_create_file(dev, &regulator->dev_attr);
+               if (err < 0) {
+                       printk(KERN_WARNING "%s: could not add regulator_dev"
+                               " load sysfs\n", __func__);
+                       goto attr_name_err;
+               }
+
+               /* also add a link to the device sysfs entry */
+               size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
+                                dev->kobj.name, supply_name);
+               if (size >= REG_STR_SIZE)
+                       goto attr_err;
+
+               regulator->supply_name = kstrdup(buf, GFP_KERNEL);
+               if (regulator->supply_name == NULL)
+                       goto attr_err;
+
+               err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
+                                       buf);
+               if (err) {
+                       printk(KERN_WARNING
+                              "%s: could not add device link %s err %d\n",
+                              __func__, dev->kobj.name, err);
+                       device_remove_file(dev, &regulator->dev_attr);
+                       goto link_name_err;
+               }
+       }
+       mutex_unlock(&rdev->mutex);
+       return regulator;
+link_name_err:
+       kfree(regulator->supply_name);
+attr_err:
+       device_remove_file(regulator->dev, &regulator->dev_attr);
+attr_name_err:
+       kfree(regulator->dev_attr.attr.name);
+overflow_err:
+       list_del(&regulator->list);
+       kfree(regulator);
+       mutex_unlock(&rdev->mutex);
+       return NULL;
+}
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.  Use of supply names
+ * configured via regulator_set_device_supply() is strongly
+ * encouraged.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+       struct regulator_dev *rdev;
+       struct regulator_map *map;
+       struct regulator *regulator = ERR_PTR(-ENODEV);
+       const char *supply = id;
+
+       if (id == NULL) {
+               printk(KERN_ERR "regulator: get() with no identifier\n");
+               return regulator;
+       }
+
+       mutex_lock(&regulator_list_mutex);
+
+       list_for_each_entry(map, &regulator_map_list, list) {
+               if (dev == map->dev &&
+                   strcmp(map->supply, id) == 0) {
+                       supply = map->regulator;
+                       break;
+               }
+       }
+
+       list_for_each_entry(rdev, &regulator_list, list) {
+               if (strcmp(supply, rdev->desc->name) == 0 &&
+                   try_module_get(rdev->owner))
+                       goto found;
+       }
+       printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
+              id);
+       mutex_unlock(&regulator_list_mutex);
+       return regulator;
+
+found:
+       regulator = create_regulator(rdev, dev, id);
+       if (regulator == NULL) {
+               regulator = ERR_PTR(-ENOMEM);
+               module_put(rdev->owner);
+       }
+
+       mutex_unlock(&regulator_list_mutex);
+       return regulator;
+}
+EXPORT_SYMBOL_GPL(regulator_get);
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+       struct regulator_dev *rdev;
+
+       if (regulator == NULL || IS_ERR(regulator))
+               return;
+
+       if (regulator->enabled) {
+               printk(KERN_WARNING "Releasing supply %s while enabled\n",
+                      regulator->supply_name);
+               WARN_ON(regulator->enabled);
+               regulator_disable(regulator);
+       }
+
+       mutex_lock(&regulator_list_mutex);
+       rdev = regulator->rdev;
+
+       /* remove any sysfs entries */
+       if (regulator->dev) {
+               sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
+               kfree(regulator->supply_name);
+               device_remove_file(regulator->dev, &regulator->dev_attr);
+               kfree(regulator->dev_attr.attr.name);
+       }
+       list_del(&regulator->list);
+       kfree(regulator);
+
+       module_put(rdev->owner);
+       mutex_unlock(&regulator_list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_put);
+
+/* locks held by regulator_enable() */
+static int _regulator_enable(struct regulator_dev *rdev)
+{
+       int ret = -EINVAL;
+
+       if (!rdev->constraints) {
+               printk(KERN_ERR "%s: %s has no constraints\n",
+                      __func__, rdev->desc->name);
+               return ret;
+       }
+
+       /* do we need to enable the supply regulator first */
+       if (rdev->supply) {
+               ret = _regulator_enable(rdev->supply);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to enable %s: %d\n",
+                              __func__, rdev->desc->name, ret);
+                       return ret;
+               }
+       }
+
+       /* check voltage and requested load before enabling */
+       if (rdev->desc->ops->enable) {
+
+               if (rdev->constraints &&
+                       (rdev->constraints->valid_ops_mask &
+                       REGULATOR_CHANGE_DRMS))
+                       drms_uA_update(rdev);
+
+               ret = rdev->desc->ops->enable(rdev);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to enable %s: %d\n",
+                              __func__, rdev->desc->name, ret);
+                       return ret;
+               }
+               rdev->use_count++;
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * regulator_enable - enable regulator output
+ * @regulator: regulator source
+ *
+ * Enable the regulator output at the predefined voltage or current value.
+ * NOTE: the output value can be set by other drivers, boot loader or may be
+ * hardwired in the regulator.
+ * NOTE: calls to regulator_enable() must be balanced with calls to
+ * regulator_disable().
+ */
+int regulator_enable(struct regulator *regulator)
+{
+       int ret;
+
+       if (regulator->enabled) {
+               printk(KERN_CRIT "Regulator %s already enabled\n",
+                      regulator->supply_name);
+               WARN_ON(regulator->enabled);
+               return 0;
+       }
+
+       mutex_lock(&regulator->rdev->mutex);
+       regulator->enabled = 1;
+       ret = _regulator_enable(regulator->rdev);
+       if (ret != 0)
+               regulator->enabled = 0;
+       mutex_unlock(&regulator->rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_enable);
+
+/* locks held by regulator_disable() */
+static int _regulator_disable(struct regulator_dev *rdev)
+{
+       int ret = 0;
+
+       /* are we the last user and permitted to disable ? */
+       if (rdev->use_count == 1 && !rdev->constraints->always_on) {
+
+               /* we are last user */
+               if (rdev->desc->ops->disable) {
+                       ret = rdev->desc->ops->disable(rdev);
+                       if (ret < 0) {
+                               printk(KERN_ERR "%s: failed to disable %s\n",
+                                      __func__, rdev->desc->name);
+                               return ret;
+                       }
+               }
+
+               /* decrease our supplies ref count and disable if required */
+               if (rdev->supply)
+                       _regulator_disable(rdev->supply);
+
+               rdev->use_count = 0;
+       } else if (rdev->use_count > 1) {
+
+               if (rdev->constraints &&
+                       (rdev->constraints->valid_ops_mask &
+                       REGULATOR_CHANGE_DRMS))
+                       drms_uA_update(rdev);
+
+               rdev->use_count--;
+       }
+       return ret;
+}
+
+/**
+ * regulator_disable - disable regulator output
+ * @regulator: regulator source
+ *
+ * Disable the regulator output voltage or current.
+ * NOTE: this will only disable the regulator output if no other consumer
+ * devices have it enabled.
+ * NOTE: calls to regulator_enable() must be balanced with calls to
+ * regulator_disable().
+ */
+int regulator_disable(struct regulator *regulator)
+{
+       int ret;
+
+       if (!regulator->enabled) {
+               printk(KERN_ERR "%s: not in use by this consumer\n",
+                       __func__);
+               return 0;
+       }
+
+       mutex_lock(&regulator->rdev->mutex);
+       regulator->enabled = 0;
+       regulator->uA_load = 0;
+       ret = _regulator_disable(regulator->rdev);
+       mutex_unlock(&regulator->rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_disable);
+
+/* locks held by regulator_force_disable() */
+static int _regulator_force_disable(struct regulator_dev *rdev)
+{
+       int ret = 0;
+
+       /* force disable */
+       if (rdev->desc->ops->disable) {
+               /* ah well, who wants to live forever... */
+               ret = rdev->desc->ops->disable(rdev);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to force disable %s\n",
+                              __func__, rdev->desc->name);
+                       return ret;
+               }
+               /* notify other consumers that power has been forced off */
+               _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE,
+                       NULL);
+       }
+
+       /* decrease our supplies ref count and disable if required */
+       if (rdev->supply)
+               _regulator_disable(rdev->supply);
+
+       rdev->use_count = 0;
+       return ret;
+}
+
+/**
+ * regulator_force_disable - force disable regulator output
+ * @regulator: regulator source
+ *
+ * Forcibly disable the regulator output voltage or current.
+ * NOTE: this *will* disable the regulator output even if other consumer
+ * devices have it enabled. This should be used for situations when device
+ * damage will likely occur if the regulator is not disabled (e.g. over temp).
+ */
+int regulator_force_disable(struct regulator *regulator)
+{
+       int ret;
+
+       mutex_lock(&regulator->rdev->mutex);
+       regulator->enabled = 0;
+       regulator->uA_load = 0;
+       ret = _regulator_force_disable(regulator->rdev);
+       mutex_unlock(&regulator->rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_force_disable);
+
+static int _regulator_is_enabled(struct regulator_dev *rdev)
+{
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->is_enabled) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = rdev->desc->ops->is_enabled(rdev);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+
+/**
+ * regulator_is_enabled - is the regulator output enabled
+ * @regulator: regulator source
+ *
+ * Returns zero for disabled otherwise return number of enable requests.
+ */
+int regulator_is_enabled(struct regulator *regulator)
+{
+       return _regulator_is_enabled(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled);
+
+/**
+ * regulator_set_voltage - set regulator output voltage
+ * @regulator: regulator source
+ * @min_uV: Minimum required voltage in uV
+ * @max_uV: Maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * during any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the voltage will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new voltage when enabled.
+ *
+ * NOTE: If the regulator is shared between several devices then the lowest
+ * request voltage that meets the system constraints will be used.
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->set_voltage) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* constraints check */
+       ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+       if (ret < 0)
+               goto out;
+       regulator->min_uV = min_uV;
+       regulator->max_uV = max_uV;
+       ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV);
+
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage);
+
+static int _regulator_get_voltage(struct regulator_dev *rdev)
+{
+       /* sanity check */
+       if (rdev->desc->ops->get_voltage)
+               return rdev->desc->ops->get_voltage(rdev);
+       else
+               return -EINVAL;
+}
+
+/**
+ * regulator_get_voltage - get regulator output voltage
+ * @regulator: regulator source
+ *
+ * This returns the current regulator voltage in uV.
+ *
+ * NOTE: If the regulator is disabled it will return the voltage value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_voltage(struct regulator *regulator)
+{
+       int ret;
+
+       mutex_lock(&regulator->rdev->mutex);
+
+       ret = _regulator_get_voltage(regulator->rdev);
+
+       mutex_unlock(&regulator->rdev->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage);
+
+/**
+ * regulator_set_current_limit - set regulator output current limit
+ * @regulator: regulator source
+ * @min_uA: Minimuum supported current in uA
+ * @max_uA: Maximum supported current in uA
+ *
+ * Sets current sink to the desired output current. This can be set during
+ * any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the current will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new current when enabled.
+ *
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_current_limit(struct regulator *regulator,
+                              int min_uA, int max_uA)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->set_current_limit) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* constraints check */
+       ret = regulator_check_current_limit(rdev, &min_uA, &max_uA);
+       if (ret < 0)
+               goto out;
+
+       ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_current_limit);
+
+static int _regulator_get_current_limit(struct regulator_dev *rdev)
+{
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->get_current_limit) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = rdev->desc->ops->get_current_limit(rdev);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+
+/**
+ * regulator_get_current_limit - get regulator output current
+ * @regulator: regulator source
+ *
+ * This returns the current supplied by the specified current sink in uA.
+ *
+ * NOTE: If the regulator is disabled it will return the current value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_current_limit(struct regulator *regulator)
+{
+       return _regulator_get_current_limit(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_get_current_limit);
+
+/**
+ * regulator_set_mode - set regulator operating mode
+ * @regulator: regulator source
+ * @mode: operating mode - one of the REGULATOR_MODE constants
+ *
+ * Set regulator operating mode to increase regulator efficiency or improve
+ * regulation performance.
+ *
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_mode(struct regulator *regulator, unsigned int mode)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->set_mode) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* constraints check */
+       ret = regulator_check_mode(rdev, mode);
+       if (ret < 0)
+               goto out;
+
+       ret = rdev->desc->ops->set_mode(rdev, mode);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_mode);
+
+static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
+{
+       int ret;
+
+       mutex_lock(&rdev->mutex);
+
+       /* sanity check */
+       if (!rdev->desc->ops->get_mode) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = rdev->desc->ops->get_mode(rdev);
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+
+/**
+ * regulator_get_mode - get regulator operating mode
+ * @regulator: regulator source
+ *
+ * Get the current regulator operating mode.
+ */
+unsigned int regulator_get_mode(struct regulator *regulator)
+{
+       return _regulator_get_mode(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_get_mode);
+
+/**
+ * regulator_set_optimum_mode - set regulator optimum operating mode
+ * @regulator: regulator source
+ * @uA_load: load current
+ *
+ * Notifies the regulator core of a new device load. This is then used by
+ * DRMS (if enabled by constraints) to set the most efficient regulator
+ * operating mode for the new regulator loading.
+ *
+ * Consumer devices notify their supply regulator of the maximum power
+ * they will require (can be taken from device datasheet in the power
+ * consumption tables) when they change operational status and hence power
+ * state. Examples of operational state changes that can affect power
+ * consumption are :-
+ *
+ *    o Device is opened / closed.
+ *    o Device I/O is about to begin or has just finished.
+ *    o Device is idling in between work.
+ *
+ * This information is also exported via sysfs to userspace.
+ *
+ * DRMS will sum the total requested load on the regulator and change
+ * to the most efficient operating mode if platform constraints allow.
+ *
+ * Returns the new regulator mode or error.
+ */
+int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+       struct regulator *consumer;
+       int ret, output_uV, input_uV, total_uA_load = 0;
+       unsigned int mode;
+
+       mutex_lock(&rdev->mutex);
+
+       regulator->uA_load = uA_load;
+       ret = regulator_check_drms(rdev);
+       if (ret < 0)
+               goto out;
+       ret = -EINVAL;
+
+       /* sanity check */
+       if (!rdev->desc->ops->get_optimum_mode)
+               goto out;
+
+       /* get output voltage */
+       output_uV = rdev->desc->ops->get_voltage(rdev);
+       if (output_uV <= 0) {
+               printk(KERN_ERR "%s: invalid output voltage found for %s\n",
+                       __func__, rdev->desc->name);
+               goto out;
+       }
+
+       /* get input voltage */
+       if (rdev->supply && rdev->supply->desc->ops->get_voltage)
+               input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply);
+       else
+               input_uV = rdev->constraints->input_uV;
+       if (input_uV <= 0) {
+               printk(KERN_ERR "%s: invalid input voltage found for %s\n",
+                       __func__, rdev->desc->name);
+               goto out;
+       }
+
+       /* calc total requested load for this regulator */
+       list_for_each_entry(consumer, &rdev->consumer_list, list)
+           total_uA_load += consumer->uA_load;
+
+       mode = rdev->desc->ops->get_optimum_mode(rdev,
+                                                input_uV, output_uV,
+                                                total_uA_load);
+       if (ret <= 0) {
+               printk(KERN_ERR "%s: failed to get optimum mode for %s @"
+                       " %d uA %d -> %d uV\n", __func__, rdev->desc->name,
+                       total_uA_load, input_uV, output_uV);
+               goto out;
+       }
+
+       ret = rdev->desc->ops->set_mode(rdev, mode);
+       if (ret <= 0) {
+               printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
+                       __func__, mode, rdev->desc->name);
+               goto out;
+       }
+       ret = mode;
+out:
+       mutex_unlock(&rdev->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
+
+/**
+ * regulator_register_notifier - register regulator event notifier
+ * @regulator: regulator source
+ * @notifier_block: notifier block
+ *
+ * Register notifier block to receive regulator events.
+ */
+int regulator_register_notifier(struct regulator *regulator,
+                             struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&regulator->rdev->notifier,
+                                               nb);
+}
+EXPORT_SYMBOL_GPL(regulator_register_notifier);
+
+/**
+ * regulator_unregister_notifier - unregister regulator event notifier
+ * @regulator: regulator source
+ * @notifier_block: notifier block
+ *
+ * Unregister regulator event notifier block.
+ */
+int regulator_unregister_notifier(struct regulator *regulator,
+                               struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&regulator->rdev->notifier,
+                                                 nb);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
+
+/* notify regulator consumers and downstream regulator consumers */
+static void _notifier_call_chain(struct regulator_dev *rdev,
+                                 unsigned long event, void *data)
+{
+       struct regulator_dev *_rdev;
+
+       /* call rdev chain first */
+       mutex_lock(&rdev->mutex);
+       blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+       mutex_unlock(&rdev->mutex);
+
+       /* now notify regulator we supply */
+       list_for_each_entry(_rdev, &rdev->supply_list, slist)
+               _notifier_call_chain(_rdev, event, data);
+}
+
+/**
+ * regulator_bulk_get - get multiple regulator consumers
+ *
+ * @dev:           Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers:     Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation.  If any of the regulators cannot be
+ * acquired then any regulators that were allocated will be freed
+ * before returning to the caller.
+ */
+int regulator_bulk_get(struct device *dev, int num_consumers,
+                      struct regulator_bulk_data *consumers)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < num_consumers; i++)
+               consumers[i].consumer = NULL;
+
+       for (i = 0; i < num_consumers; i++) {
+               consumers[i].consumer = regulator_get(dev,
+                                                     consumers[i].supply);
+               if (IS_ERR(consumers[i].consumer)) {
+                       dev_err(dev, "Failed to get supply '%s'\n",
+                               consumers[i].supply);
+                       ret = PTR_ERR(consumers[i].consumer);
+                       consumers[i].consumer = NULL;
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < num_consumers && consumers[i].consumer; i++)
+               regulator_put(consumers[i].consumer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_get);
+
+/**
+ * regulator_bulk_enable - enable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to enable multiple regulator
+ * clients in a single API call.  If any consumers cannot be enabled
+ * then any others that were enabled will be disabled again prior to
+ * return.
+ */
+int regulator_bulk_enable(int num_consumers,
+                         struct regulator_bulk_data *consumers)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < num_consumers; i++) {
+               ret = regulator_enable(consumers[i].consumer);
+               if (ret != 0)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       printk(KERN_ERR "Failed to enable %s\n", consumers[i].supply);
+       for (i = 0; i < num_consumers; i++)
+               regulator_disable(consumers[i].consumer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_enable);
+
+/**
+ * regulator_bulk_disable - disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to disable multiple regulator
+ * clients in a single API call.  If any consumers cannot be enabled
+ * then any others that were disabled will be disabled again prior to
+ * return.
+ */
+int regulator_bulk_disable(int num_consumers,
+                          struct regulator_bulk_data *consumers)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < num_consumers; i++) {
+               ret = regulator_disable(consumers[i].consumer);
+               if (ret != 0)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       printk(KERN_ERR "Failed to disable %s\n", consumers[i].supply);
+       for (i = 0; i < num_consumers; i++)
+               regulator_enable(consumers[i].consumer);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_disable);
+
+/**
+ * regulator_bulk_free - free multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ *
+ * This convenience API allows consumers to free multiple regulator
+ * clients in a single API call.
+ */
+void regulator_bulk_free(int num_consumers,
+                        struct regulator_bulk_data *consumers)
+{
+       int i;
+
+       for (i = 0; i < num_consumers; i++) {
+               regulator_put(consumers[i].consumer);
+               consumers[i].consumer = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_free);
+
+/**
+ * regulator_notifier_call_chain - call regulator event notifier
+ * @regulator: regulator source
+ * @event: notifier block
+ * @data:
+ *
+ * Called by regulator drivers to notify clients a regulator event has
+ * occurred. We also notify regulator clients downstream.
+ */
+int regulator_notifier_call_chain(struct regulator_dev *rdev,
+                                 unsigned long event, void *data)
+{
+       _notifier_call_chain(rdev, event, data);
+       return NOTIFY_DONE;
+
+}
+EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
+
+/**
+ * regulator_register - register regulator
+ * @regulator: regulator source
+ * @reg_data: private regulator data
+ *
+ * Called by regulator drivers to register a regulator.
+ * Returns 0 on success.
+ */
+struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
+                                         void *reg_data)
+{
+       static atomic_t regulator_no = ATOMIC_INIT(0);
+       struct regulator_dev *rdev;
+       int ret;
+
+       if (regulator_desc == NULL)
+               return ERR_PTR(-EINVAL);
+
+       if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
+               return ERR_PTR(-EINVAL);
+
+       if (!regulator_desc->type == REGULATOR_VOLTAGE &&
+           !regulator_desc->type == REGULATOR_CURRENT)
+               return ERR_PTR(-EINVAL);
+
+       rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+       if (rdev == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_lock(&regulator_list_mutex);
+
+       mutex_init(&rdev->mutex);
+       rdev->reg_data = reg_data;
+       rdev->owner = regulator_desc->owner;
+       rdev->desc = regulator_desc;
+       INIT_LIST_HEAD(&rdev->consumer_list);
+       INIT_LIST_HEAD(&rdev->supply_list);
+       INIT_LIST_HEAD(&rdev->list);
+       INIT_LIST_HEAD(&rdev->slist);
+       BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+
+       rdev->dev.class = &regulator_class;
+       device_initialize(&rdev->dev);
+       snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
+                "regulator_%ld_%s",
+                (unsigned long)atomic_inc_return(&regulator_no) - 1,
+                regulator_desc->name);
+
+       ret = device_add(&rdev->dev);
+       if (ret == 0)
+               list_add(&rdev->list, &regulator_list);
+       else {
+               kfree(rdev);
+               rdev = ERR_PTR(ret);
+       }
+       mutex_unlock(&regulator_list_mutex);
+       return rdev;
+}
+EXPORT_SYMBOL_GPL(regulator_register);
+
+/**
+ * regulator_unregister - unregister regulator
+ * @regulator: regulator source
+ *
+ * Called by regulator drivers to unregister a regulator.
+ */
+void regulator_unregister(struct regulator_dev *rdev)
+{
+       if (rdev == NULL)
+               return;
+
+       mutex_lock(&regulator_list_mutex);
+       list_del(&rdev->list);
+       if (rdev->supply)
+               sysfs_remove_link(&rdev->dev.kobj, "supply");
+       device_unregister(&rdev->dev);
+       mutex_unlock(&regulator_list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister);
+
+/**
+ * regulator_set_supply - set regulator supply regulator
+ * @regulator: regulator name
+ * @supply: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+int regulator_set_supply(const char *regulator, const char *supply)
+{
+       struct regulator_dev *rdev, *supply_rdev;
+       int err;
+
+       if (regulator == NULL || supply == NULL)
+               return -EINVAL;
+
+       mutex_lock(&regulator_list_mutex);
+
+       list_for_each_entry(rdev, &regulator_list, list) {
+               if (!strcmp(rdev->desc->name, regulator))
+                       goto found_regulator;
+       }
+       mutex_unlock(&regulator_list_mutex);
+       return -ENODEV;
+
+found_regulator:
+       list_for_each_entry(supply_rdev, &regulator_list, list) {
+               if (!strcmp(supply_rdev->desc->name, supply))
+                       goto found_supply;
+       }
+       mutex_unlock(&regulator_list_mutex);
+       return -ENODEV;
+
+found_supply:
+       err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
+                               "supply");
+       if (err) {
+               printk(KERN_ERR
+                      "%s: could not add device link %s err %d\n",
+                      __func__, supply_rdev->dev.kobj.name, err);
+                      goto out;
+       }
+       rdev->supply = supply_rdev;
+       list_add(&rdev->slist, &supply_rdev->supply_list);
+out:
+       mutex_unlock(&regulator_list_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(regulator_set_supply);
+
+/**
+ * regulator_get_supply - get regulator supply regulator
+ * @regulator: regulator name
+ *
+ * Returns the supply supply regulator name or NULL if no supply regulator
+ * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
+ */
+const char *regulator_get_supply(const char *regulator)
+{
+       struct regulator_dev *rdev;
+
+       if (regulator == NULL)
+               return NULL;
+
+       mutex_lock(&regulator_list_mutex);
+       list_for_each_entry(rdev, &regulator_list, list) {
+               if (!strcmp(rdev->desc->name, regulator))
+                       goto found;
+       }
+       mutex_unlock(&regulator_list_mutex);
+       return NULL;
+
+found:
+       mutex_unlock(&regulator_list_mutex);
+       if (rdev->supply)
+               return rdev->supply->desc->name;
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(regulator_get_supply);
+
+/**
+ * regulator_set_machine_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+int regulator_set_machine_constraints(const char *regulator_name,
+       struct regulation_constraints *constraints)
+{
+       struct regulator_dev *rdev;
+       int ret = 0;
+
+       if (regulator_name == NULL)
+               return -EINVAL;
+
+       mutex_lock(&regulator_list_mutex);
+
+       list_for_each_entry(rdev, &regulator_list, list) {
+               if (!strcmp(regulator_name, rdev->desc->name))
+                       goto found;
+       }
+       ret = -ENODEV;
+       goto out;
+
+found:
+       mutex_lock(&rdev->mutex);
+       rdev->constraints = constraints;
+
+       /* do we need to apply the constraint voltage */
+       if (rdev->constraints->apply_uV &&
+               rdev->constraints->min_uV == rdev->constraints->max_uV &&
+               rdev->desc->ops->set_voltage) {
+               ret = rdev->desc->ops->set_voltage(rdev,
+                       rdev->constraints->min_uV, rdev->constraints->max_uV);
+                       if (ret < 0) {
+                               printk(KERN_ERR "%s: failed to apply %duV"
+                                       " constraint\n", __func__,
+                                       rdev->constraints->min_uV);
+                               rdev->constraints = NULL;
+                               goto out;
+                       }
+       }
+
+       /* are we enabled at boot time by firmware / bootloader */
+       if (rdev->constraints->boot_on)
+               rdev->use_count = 1;
+
+       /* do we need to setup our suspend state */
+       if (constraints->initial_state)
+               ret = suspend_prepare(rdev, constraints->initial_state);
+
+       print_constraints(rdev);
+       mutex_unlock(&rdev->mutex);
+
+out:
+       mutex_unlock(&regulator_list_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_machine_constraints);
+
+
+/**
+ * regulator_set_device_supply: Bind a regulator to a symbolic supply
+ * @regulator: regulator source
+ * @dev:       device the supply applies to
+ * @supply:    symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices.  Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+int regulator_set_device_supply(const char *regulator, struct device *dev,
+                               const char *supply)
+{
+       struct regulator_map *node;
+
+       if (regulator == NULL || supply == NULL)
+               return -EINVAL;
+
+       node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (node == NULL)
+               return -ENOMEM;
+
+       node->regulator = regulator;
+       node->dev = dev;
+       node->supply = supply;
+
+       mutex_lock(&regulator_list_mutex);
+       list_add(&node->list, &regulator_map_list);
+       mutex_unlock(&regulator_list_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_set_device_supply);
+
+/**
+ * regulator_suspend_prepare: prepare regulators for system wide suspend
+ * @state: system suspend state
+ *
+ * Configure each regulator with it's suspend operating parameters for state.
+ * This will usually be called by machine suspend code prior to supending.
+ */
+int regulator_suspend_prepare(suspend_state_t state)
+{
+       struct regulator_dev *rdev;
+       int ret = 0;
+
+       /* ON is handled by regulator active state */
+       if (state == PM_SUSPEND_ON)
+               return -EINVAL;
+
+       mutex_lock(&regulator_list_mutex);
+       list_for_each_entry(rdev, &regulator_list, list) {
+
+               mutex_lock(&rdev->mutex);
+               ret = suspend_prepare(rdev, state);
+               mutex_unlock(&rdev->mutex);
+
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: failed to prepare %s\n",
+                               __func__, rdev->desc->name);
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&regulator_list_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
+
+/**
+ * rdev_get_drvdata - get rdev regulator driver data
+ * @regulator: regulator
+ *
+ * Get rdev regulator driver private data. This call can be used in the
+ * regulator driver context.
+ */
+void *rdev_get_drvdata(struct regulator_dev *rdev)
+{
+       return rdev->reg_data;
+}
+EXPORT_SYMBOL_GPL(rdev_get_drvdata);
+
+/**
+ * regulator_get_drvdata - get regulator driver data
+ * @regulator: regulator
+ *
+ * Get regulator driver private data. This call can be used in the consumer
+ * driver context when non API regulator specific functions need to be called.
+ */
+void *regulator_get_drvdata(struct regulator *regulator)
+{
+       return regulator->rdev->reg_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_drvdata);
+
+/**
+ * regulator_set_drvdata - set regulator driver data
+ * @regulator: regulator
+ * @data: data
+ */
+void regulator_set_drvdata(struct regulator *regulator, void *data)
+{
+       regulator->rdev->reg_data = data;
+}
+EXPORT_SYMBOL_GPL(regulator_set_drvdata);
+
+/**
+ * regulator_get_id - get regulator ID
+ * @regulator: regulator
+ */
+int rdev_get_id(struct regulator_dev *rdev)
+{
+       return rdev->desc->id;
+}
+EXPORT_SYMBOL_GPL(rdev_get_id);
+
+static int __init regulator_init(void)
+{
+       printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
+       return class_register(&regulator_class);
+}
+
+/* init early to allow our consumers to complete system booting */
+core_initcall(regulator_init);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
new file mode 100644 (file)
index 0000000..d31db3e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * fixed.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/fixed.h>
+
+struct fixed_voltage_data {
+       struct regulator_desc desc;
+       struct regulator_dev *dev;
+       int microvolts;
+};
+
+static int fixed_voltage_is_enabled(struct regulator_dev *dev)
+{
+       return 1;
+}
+
+static int fixed_voltage_enable(struct regulator_dev *dev)
+{
+       return 0;
+}
+
+static int fixed_voltage_get_voltage(struct regulator_dev *dev)
+{
+       struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+       return data->microvolts;
+}
+
+static struct regulator_ops fixed_voltage_ops = {
+       .is_enabled = fixed_voltage_is_enabled,
+       .enable = fixed_voltage_enable,
+       .get_voltage = fixed_voltage_get_voltage,
+};
+
+static int regulator_fixed_voltage_probe(struct platform_device *pdev)
+{
+       struct fixed_voltage_config *config = pdev->dev.platform_data;
+       struct fixed_voltage_data *drvdata;
+       int ret;
+
+       drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
+       if (drvdata == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+       if (drvdata->desc.name == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       drvdata->desc.type = REGULATOR_VOLTAGE;
+       drvdata->desc.owner = THIS_MODULE;
+       drvdata->desc.ops = &fixed_voltage_ops,
+
+       drvdata->microvolts = config->microvolts;
+
+       drvdata->dev = regulator_register(&drvdata->desc, drvdata);
+       if (IS_ERR(drvdata->dev)) {
+               ret = PTR_ERR(drvdata->dev);
+               goto err_name;
+       }
+
+       platform_set_drvdata(pdev, drvdata);
+
+       dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name,
+               drvdata->microvolts);
+
+       return 0;
+
+err_name:
+       kfree(drvdata->desc.name);
+err:
+       kfree(drvdata);
+       return ret;
+}
+
+static int regulator_fixed_voltage_remove(struct platform_device *pdev)
+{
+       struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
+
+       regulator_unregister(drvdata->dev);
+       kfree(drvdata->desc.name);
+       kfree(drvdata);
+
+       return 0;
+}
+
+static struct platform_driver regulator_fixed_voltage_driver = {
+       .probe          = regulator_fixed_voltage_probe,
+       .remove         = regulator_fixed_voltage_remove,
+       .driver         = {
+               .name           = "reg-fixed-voltage",
+       },
+};
+
+static int __init regulator_fixed_voltage_init(void)
+{
+       return platform_driver_register(&regulator_fixed_voltage_driver);
+}
+module_init(regulator_fixed_voltage_init);
+
+static void __exit regulator_fixed_voltage_exit(void)
+{
+       platform_driver_unregister(&regulator_fixed_voltage_driver);
+}
+module_exit(regulator_fixed_voltage_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Fixed voltage regulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
new file mode 100644 (file)
index 0000000..5ddb464
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * reg-virtual-consumer.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+struct virtual_consumer_data {
+       struct mutex lock;
+       struct regulator *regulator;
+       int enabled;
+       int min_uV;
+       int max_uV;
+       int min_uA;
+       int max_uA;
+       unsigned int mode;
+};
+
+static void update_voltage_constraints(struct virtual_consumer_data *data)
+{
+       int ret;
+
+       if (data->min_uV && data->max_uV
+           && data->min_uV <= data->max_uV) {
+               ret = regulator_set_voltage(data->regulator,
+                                           data->min_uV, data->max_uV);
+               if (ret != 0) {
+                       printk(KERN_ERR "regulator_set_voltage() failed: %d\n",
+                              ret);
+                       return;
+               }
+       }
+
+       if (data->min_uV && data->max_uV && !data->enabled) {
+               ret = regulator_enable(data->regulator);
+               if (ret == 0)
+                       data->enabled = 1;
+               else
+                       printk(KERN_ERR "regulator_enable() failed: %d\n",
+                               ret);
+       }
+
+       if (!(data->min_uV && data->max_uV) && data->enabled) {
+               ret = regulator_disable(data->regulator);
+               if (ret == 0)
+                       data->enabled = 0;
+               else
+                       printk(KERN_ERR "regulator_disable() failed: %d\n",
+                               ret);
+       }
+}
+
+static void update_current_limit_constraints(struct virtual_consumer_data
+                                               *data)
+{
+       int ret;
+
+       if (data->max_uA
+           && data->min_uA <= data->max_uA) {
+               ret = regulator_set_current_limit(data->regulator,
+                                       data->min_uA, data->max_uA);
+               if (ret != 0) {
+                       pr_err("regulator_set_current_limit() failed: %d\n",
+                              ret);
+                       return;
+               }
+       }
+
+       if (data->max_uA && !data->enabled) {
+               ret = regulator_enable(data->regulator);
+               if (ret == 0)
+                       data->enabled = 1;
+               else
+                       printk(KERN_ERR "regulator_enable() failed: %d\n",
+                               ret);
+       }
+
+       if (!(data->min_uA && data->max_uA) && data->enabled) {
+               ret = regulator_disable(data->regulator);
+               if (ret == 0)
+                       data->enabled = 0;
+               else
+                       printk(KERN_ERR "regulator_disable() failed: %d\n",
+                               ret);
+       }
+}
+
+static ssize_t show_min_uV(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->min_uV);
+}
+
+static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) != 0)
+               return count;
+
+       mutex_lock(&data->lock);
+
+       data->min_uV = val;
+       update_voltage_constraints(data);
+
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_max_uV(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->max_uV);
+}
+
+static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) != 0)
+               return count;
+
+       mutex_lock(&data->lock);
+
+       data->max_uV = val;
+       update_voltage_constraints(data);
+
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_min_uA(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->min_uA);
+}
+
+static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) != 0)
+               return count;
+
+       mutex_lock(&data->lock);
+
+       data->min_uA = val;
+       update_current_limit_constraints(data);
+
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_max_uA(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->max_uA);
+}
+
+static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       long val;
+
+       if (strict_strtol(buf, 10, &val) != 0)
+               return count;
+
+       mutex_lock(&data->lock);
+
+       data->max_uA = val;
+       update_current_limit_constraints(data);
+
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t show_mode(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+
+       switch (data->mode) {
+       case REGULATOR_MODE_FAST:
+               return sprintf(buf, "fast\n");
+       case REGULATOR_MODE_NORMAL:
+               return sprintf(buf, "normal\n");
+       case REGULATOR_MODE_IDLE:
+               return sprintf(buf, "idle\n");
+       case REGULATOR_MODE_STANDBY:
+               return sprintf(buf, "standby\n");
+       default:
+               return sprintf(buf, "unknown\n");
+       }
+}
+
+static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct virtual_consumer_data *data = dev_get_drvdata(dev);
+       unsigned int mode;
+       int ret;
+
+       if (strncmp(buf, "fast", strlen("fast")) == 0)
+               mode = REGULATOR_MODE_FAST;
+       else if (strncmp(buf, "normal", strlen("normal")) == 0)
+               mode = REGULATOR_MODE_NORMAL;
+       else if (strncmp(buf, "idle", strlen("idle")) == 0)
+               mode = REGULATOR_MODE_IDLE;
+       else if (strncmp(buf, "standby", strlen("standby")) == 0)
+               mode = REGULATOR_MODE_STANDBY;
+       else {
+               dev_err(dev, "Configuring invalid mode\n");
+               return count;
+       }
+
+       mutex_lock(&data->lock);
+       ret = regulator_set_mode(data->regulator, mode);
+       if (ret == 0)
+               data->mode = mode;
+       else
+               dev_err(dev, "Failed to configure mode: %d\n", ret);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV);
+static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV);
+static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
+static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
+static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
+
+struct device_attribute *attributes[] = {
+       &dev_attr_min_microvolts,
+       &dev_attr_max_microvolts,
+       &dev_attr_min_microamps,
+       &dev_attr_max_microamps,
+       &dev_attr_mode,
+};
+
+static int regulator_virtual_consumer_probe(struct platform_device *pdev)
+{
+       char *reg_id = pdev->dev.platform_data;
+       struct virtual_consumer_data *drvdata;
+       int ret, i;
+
+       drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
+       if (drvdata == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       mutex_init(&drvdata->lock);
+
+       drvdata->regulator = regulator_get(&pdev->dev, reg_id);
+       if (IS_ERR(drvdata->regulator)) {
+               ret = PTR_ERR(drvdata->regulator);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(attributes); i++) {
+               ret = device_create_file(&pdev->dev, attributes[i]);
+               if (ret != 0)
+                       goto err;
+       }
+
+       drvdata->mode = regulator_get_mode(drvdata->regulator);
+
+       platform_set_drvdata(pdev, drvdata);
+
+       return 0;
+
+err:
+       for (i = 0; i < ARRAY_SIZE(attributes); i++)
+               device_remove_file(&pdev->dev, attributes[i]);
+       kfree(drvdata);
+       return ret;
+}
+
+static int regulator_virtual_consumer_remove(struct platform_device *pdev)
+{
+       struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(attributes); i++)
+               device_remove_file(&pdev->dev, attributes[i]);
+       if (drvdata->enabled)
+               regulator_disable(drvdata->regulator);
+       regulator_put(drvdata->regulator);
+
+       kfree(drvdata);
+
+       return 0;
+}
+
+static struct platform_driver regulator_virtual_consumer_driver = {
+       .probe          = regulator_virtual_consumer_probe,
+       .remove         = regulator_virtual_consumer_remove,
+       .driver         = {
+               .name           = "reg-virt-consumer",
+       },
+};
+
+
+static int __init regulator_virtual_consumer_init(void)
+{
+       return platform_driver_register(&regulator_virtual_consumer_driver);
+}
+module_init(regulator_virtual_consumer_init);
+
+static void __exit regulator_virtual_consumer_exit(void)
+{
+       platform_driver_unregister(&regulator_virtual_consumer_driver);
+}
+module_exit(regulator_virtual_consumer_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Virtual regulator consumer");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/bq24022.h b/include/linux/regulator/bq24022.h
new file mode 100644 (file)
index 0000000..e84b0a9
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
+ * 1-Cell Li-Ion Charger connected via GPIOs.
+ *
+ * Copyright (c) 2008 Philipp Zabel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/**
+ * bq24022_mach_info - platform data for bq24022
+ * @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging
+ * @gpio_iset2: GPIO line connected to the ISET2 pin, used to limit charging current to 100 mA / 500 mA
+ */
+struct bq24022_mach_info {
+       int gpio_nce;
+       int gpio_iset2;
+};
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
new file mode 100644 (file)
index 0000000..afdc455
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * consumer.h -- SoC Regulator consumer support.
+ *
+ * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Consumer Interface.
+ *
+ * A Power Management Regulator framework for SoC based devices.
+ * Features:-
+ *   o Voltage and current level control.
+ *   o Operating mode control.
+ *   o Regulator status.
+ *   o sysfs entries for showing client devices and status
+ *
+ * EXPERIMENTAL FEATURES:
+ *   Dynamic Regulator operating Mode Switching (DRMS) - allows regulators
+ *   to use most efficient operating mode depending upon voltage and load and
+ *   is transparent to client drivers.
+ *
+ *   e.g. Devices x,y,z share regulator r. Device x and y draw 20mA each during
+ *   IO and 1mA at idle. Device z draws 100mA when under load and 5mA when
+ *   idling. Regulator r has > 90% efficiency in NORMAL mode at loads > 100mA
+ *   but this drops rapidly to 60% when below 100mA. Regulator r has > 90%
+ *   efficiency in IDLE mode at loads < 10mA. Thus regulator r will operate
+ *   in normal mode for loads > 10mA and in IDLE mode for load <= 10mA.
+ *
+ */
+
+#ifndef __LINUX_REGULATOR_CONSUMER_H_
+#define __LINUX_REGULATOR_CONSUMER_H_
+
+/*
+ * Regulator operating modes.
+ *
+ * Regulators can run in a variety of different operating modes depending on
+ * output load. This allows further system power savings by selecting the
+ * best (and most efficient) regulator mode for a desired load.
+ *
+ * Most drivers will only care about NORMAL. The modes below are generic and
+ * will probably not match the naming convention of your regulator data sheet
+ * but should match the use cases in the datasheet.
+ *
+ * In order of power efficiency (least efficient at top).
+ *
+ *  Mode       Description
+ *  FAST       Regulator can handle fast changes in it's load.
+ *             e.g. useful in CPU voltage & frequency scaling where
+ *             load can quickly increase with CPU frequency increases.
+ *
+ *  NORMAL     Normal regulator power supply mode. Most drivers will
+ *             use this mode.
+ *
+ *  IDLE       Regulator runs in a more efficient mode for light
+ *             loads. Can be used for devices that have a low power
+ *             requirement during periods of inactivity. This mode
+ *             may be more noisy than NORMAL and may not be able
+ *             to handle fast load switching.
+ *
+ *  STANDBY    Regulator runs in the most efficient mode for very
+ *             light loads. Can be used by devices when they are
+ *             in a sleep/standby state. This mode is likely to be
+ *             the most noisy and may not be able to handle fast load
+ *             switching.
+ *
+ * NOTE: Most regulators will only support a subset of these modes. Some
+ * will only just support NORMAL.
+ *
+ * These modes can be OR'ed together to make up a mask of valid register modes.
+ */
+
+#define REGULATOR_MODE_FAST                    0x1
+#define REGULATOR_MODE_NORMAL                  0x2
+#define REGULATOR_MODE_IDLE                    0x4
+#define REGULATOR_MODE_STANDBY                 0x8
+
+/*
+ * Regulator notifier events.
+ *
+ * UNDER_VOLTAGE  Regulator output is under voltage.
+ * OVER_CURRENT   Regulator output current is too high.
+ * REGULATION_OUT Regulator output is out of regulation.
+ * FAIL           Regulator output has failed.
+ * OVER_TEMP      Regulator over temp.
+ * FORCE_DISABLE  Regulator shut down by software.
+ *
+ * NOTE: These events can be OR'ed together when passed into handler.
+ */
+
+#define REGULATOR_EVENT_UNDER_VOLTAGE          0x01
+#define REGULATOR_EVENT_OVER_CURRENT           0x02
+#define REGULATOR_EVENT_REGULATION_OUT         0x04
+#define REGULATOR_EVENT_FAIL                   0x08
+#define REGULATOR_EVENT_OVER_TEMP              0x10
+#define REGULATOR_EVENT_FORCE_DISABLE          0x20
+
+struct regulator;
+
+/**
+ * struct regulator_bulk_data - Data used for bulk regulator operations.
+ *
+ * @supply   The name of the supply.  Initialised by the user before
+ *           using the bulk regulator APIs.
+ * @consumer The regulator consumer for the supply.  This will be managed
+ *           by the bulk API.
+ *
+ * The regulator APIs provide a series of regulator_bulk_() API calls as
+ * a convenience to consumers which require multiple supplies.  This
+ * structure is used to manage data for these calls.
+ */
+struct regulator_bulk_data {
+       const char *supply;
+       struct regulator *consumer;
+};
+
+#if defined(CONFIG_REGULATOR)
+
+/* regulator get and put */
+struct regulator *__must_check regulator_get(struct device *dev,
+                                            const char *id);
+void regulator_put(struct regulator *regulator);
+
+/* regulator output control and status */
+int regulator_enable(struct regulator *regulator);
+int regulator_disable(struct regulator *regulator);
+int regulator_force_disable(struct regulator *regulator);
+int regulator_is_enabled(struct regulator *regulator);
+
+int regulator_bulk_get(struct device *dev, int num_consumers,
+                      struct regulator_bulk_data *consumers);
+int regulator_bulk_enable(int num_consumers,
+                         struct regulator_bulk_data *consumers);
+int regulator_bulk_disable(int num_consumers,
+                          struct regulator_bulk_data *consumers);
+void regulator_bulk_free(int num_consumers,
+                        struct regulator_bulk_data *consumers);
+
+int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
+int regulator_get_voltage(struct regulator *regulator);
+int regulator_set_current_limit(struct regulator *regulator,
+                              int min_uA, int max_uA);
+int regulator_get_current_limit(struct regulator *regulator);
+
+int regulator_set_mode(struct regulator *regulator, unsigned int mode);
+unsigned int regulator_get_mode(struct regulator *regulator);
+int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
+
+/* regulator notifier block */
+int regulator_register_notifier(struct regulator *regulator,
+                             struct notifier_block *nb);
+int regulator_unregister_notifier(struct regulator *regulator,
+                               struct notifier_block *nb);
+
+/* driver data - core doesn't touch */
+void *regulator_get_drvdata(struct regulator *regulator);
+void regulator_set_drvdata(struct regulator *regulator, void *data);
+
+#else
+
+/*
+ * Make sure client drivers will still build on systems with no software
+ * controllable voltage or current regulators.
+ */
+static inline struct regulator *__must_check regulator_get(struct device *dev,
+       const char *id)
+{
+       /* Nothing except the stubbed out regulator API should be
+        * looking at the value except to check if it is an error
+        * value so the actual return value doesn't matter.
+        */
+       return (struct regulator *)id;
+}
+static inline void regulator_put(struct regulator *regulator)
+{
+}
+
+static inline int regulator_enable(struct regulator *regulator)
+{
+       return 0;
+}
+
+static inline int regulator_disable(struct regulator *regulator)
+{
+       return 0;
+}
+
+static inline int regulator_is_enabled(struct regulator *regulator)
+{
+       return 1;
+}
+
+static inline int regulator_bulk_get(struct device *dev,
+                                    int num_consumers,
+                                    struct regulator_bulk_data *consumers)
+{
+       return 0;
+}
+
+static inline int regulator_bulk_enable(int num_consumers,
+                                       struct regulator_bulk_data *consumers)
+{
+       return 0;
+}
+
+static inline int regulator_bulk_disable(int num_consumers,
+                                        struct regulator_bulk_data *consumers)
+{
+       return 0;
+}
+
+static inline void regulator_bulk_free(int num_consumers,
+                                      struct regulator_bulk_data *consumers)
+{
+}
+
+static inline int regulator_set_voltage(struct regulator *regulator,
+                                       int min_uV, int max_uV)
+{
+       return 0;
+}
+
+static inline int regulator_get_voltage(struct regulator *regulator)
+{
+       return 0;
+}
+
+static inline int regulator_set_current_limit(struct regulator *regulator,
+                                            int min_uA, int max_uA)
+{
+       return 0;
+}
+
+static inline int regulator_get_current_limit(struct regulator *regulator)
+{
+       return 0;
+}
+
+static inline int regulator_set_mode(struct regulator *regulator,
+       unsigned int mode)
+{
+       return 0;
+}
+
+static inline unsigned int regulator_get_mode(struct regulator *regulator)
+{
+       return REGULATOR_MODE_NORMAL;
+}
+
+static inline int regulator_set_optimum_mode(struct regulator *regulator,
+                                       int load_uA)
+{
+       return REGULATOR_MODE_NORMAL;
+}
+
+static inline int regulator_register_notifier(struct regulator *regulator,
+                             struct notifier_block *nb)
+{
+       return 0;
+}
+
+static inline int regulator_unregister_notifier(struct regulator *regulator,
+                               struct notifier_block *nb)
+{
+       return 0;
+}
+
+static inline void *regulator_get_drvdata(struct regulator *regulator)
+{
+       return NULL;
+}
+
+static inline void regulator_set_drvdata(struct regulator *regulator,
+       void *data)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
new file mode 100644 (file)
index 0000000..1d712c7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * driver.h -- SoC Regulator driver support.
+ *
+ * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Driver Interface.
+ */
+
+#ifndef __LINUX_REGULATOR_DRIVER_H_
+#define __LINUX_REGULATOR_DRIVER_H_
+
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+
+struct regulator_constraints;
+struct regulator_dev;
+
+/**
+ * struct regulator_ops - regulator operations.
+ *
+ * This struct describes regulator operations.
+ */
+struct regulator_ops {
+
+       /* get/set regulator voltage */
+       int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV);
+       int (*get_voltage) (struct regulator_dev *);
+
+       /* get/set regulator current  */
+       int (*set_current_limit) (struct regulator_dev *,
+                                int min_uA, int max_uA);
+       int (*get_current_limit) (struct regulator_dev *);
+
+       /* enable/disable regulator */
+       int (*enable) (struct regulator_dev *);
+       int (*disable) (struct regulator_dev *);
+       int (*is_enabled) (struct regulator_dev *);
+
+       /* get/set regulator operating mode (defined in regulator.h) */
+       int (*set_mode) (struct regulator_dev *, unsigned int mode);
+       unsigned int (*get_mode) (struct regulator_dev *);
+
+       /* get most efficient regulator operating mode for load */
+       unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
+                                         int output_uV, int load_uA);
+
+       /* the operations below are for configuration of regulator state when
+        * it's parent PMIC enters a global STANBY/HIBERNATE state */
+
+       /* set regulator suspend voltage */
+       int (*set_suspend_voltage) (struct regulator_dev *, int uV);
+
+       /* enable/disable regulator in suspend state */
+       int (*set_suspend_enable) (struct regulator_dev *);
+       int (*set_suspend_disable) (struct regulator_dev *);
+
+       /* set regulator suspend operating mode (defined in regulator.h) */
+       int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
+};
+
+/*
+ * Regulators can either control voltage or current.
+ */
+enum regulator_type {
+       REGULATOR_VOLTAGE,
+       REGULATOR_CURRENT,
+};
+
+/**
+ * struct regulator_desc - Regulator descriptor
+ *
+ */
+struct regulator_desc {
+       const char *name;
+       int id;
+       struct regulator_ops *ops;
+       int irq;
+       enum regulator_type type;
+       struct module *owner;
+};
+
+
+struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
+                                         void *reg_data);
+void regulator_unregister(struct regulator_dev *rdev);
+
+int regulator_notifier_call_chain(struct regulator_dev *rdev,
+                                 unsigned long event, void *data);
+
+void *rdev_get_drvdata(struct regulator_dev *rdev);
+int rdev_get_id(struct regulator_dev *rdev);
+
+#endif
diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h
new file mode 100644 (file)
index 0000000..1387a5d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * fixed.h
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#ifndef __REGULATOR_FIXED_H
+#define __REGULATOR_FIXED_H
+
+struct fixed_voltage_config {
+       const char *supply_name;
+       int microvolts;
+};
+
+#endif
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
new file mode 100644 (file)
index 0000000..11e737d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * machine.h -- SoC Regulator support, machine/board driver API.
+ *
+ * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regulator Machine/Board Interface.
+ */
+
+#ifndef __LINUX_REGULATOR_MACHINE_H_
+#define __LINUX_REGULATOR_MACHINE_H_
+
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+
+struct regulator;
+
+/*
+ * Regulator operation constraint flags. These flags are used to enable
+ * certain regulator operations and can be OR'ed together.
+ *
+ * VOLTAGE:  Regulator output voltage can be changed by software on this
+ *           board/machine.
+ * CURRENT:  Regulator output current can be changed by software on this
+ *           board/machine.
+ * MODE:     Regulator operating mode can be changed by software on this
+ *           board/machine.
+ * STATUS:   Regulator can be enabled and disabled.
+ * DRMS:     Dynamic Regulator Mode Switching is enabled for this regulator.
+ */
+
+#define REGULATOR_CHANGE_VOLTAGE       0x1
+#define REGULATOR_CHANGE_CURRENT       0x2
+#define REGULATOR_CHANGE_MODE          0x4
+#define REGULATOR_CHANGE_STATUS                0x8
+#define REGULATOR_CHANGE_DRMS          0x10
+
+/**
+ * struct regulator_state - regulator state during low power syatem states
+ *
+ * This describes a regulators state during a system wide low power state.
+ */
+struct regulator_state {
+       int uV; /* suspend voltage */
+       unsigned int mode; /* suspend regulator operating mode */
+       int enabled; /* is regulator enabled in this suspend state */
+};
+
+/**
+ * struct regulation_constraints - regulator operating constraints.
+ *
+ * This struct describes regulator and board/machine specific constraints.
+ */
+struct regulation_constraints {
+
+       char *name;
+
+       /* voltage output range (inclusive) - for voltage control */
+       int min_uV;
+       int max_uV;
+
+       /* current output range (inclusive) - for current control */
+       int min_uA;
+       int max_uA;
+
+       /* valid regulator operating modes for this machine */
+       unsigned int valid_modes_mask;
+
+       /* valid operations for regulator on this machine */
+       unsigned int valid_ops_mask;
+
+       /* regulator input voltage - only if supply is another regulator */
+       int input_uV;
+
+       /* regulator suspend states for global PMIC STANDBY/HIBERNATE */
+       struct regulator_state state_disk;
+       struct regulator_state state_mem;
+       struct regulator_state state_standby;
+       suspend_state_t initial_state; /* suspend state to set at init */
+
+       /* constriant flags */
+       unsigned always_on:1;   /* regulator never off when system is on */
+       unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
+       unsigned apply_uV:1;    /* apply uV constraint iff min == max */
+};
+
+int regulator_set_supply(const char *regulator, const char *regulator_supply);
+
+const char *regulator_get_supply(const char *regulator);
+
+int regulator_set_machine_constraints(const char *regulator,
+       struct regulation_constraints *constraints);
+
+int regulator_set_device_supply(const char *regulator, struct device *dev,
+                               const char *supply);
+
+int regulator_suspend_prepare(suspend_state_t state);
+
+#endif