Commit 561b35b3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'reg-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6

* '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
parents a7c2a10d 0eb5d5ab
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'
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.
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);
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
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);
......@@ -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
......
......@@ -1225,6 +1225,8 @@ source "drivers/dma/Kconfig"
source "drivers/dca/Kconfig"
source "drivers/regulator/Kconfig"
source "drivers/uio/Kconfig"
endmenu
......
......@@ -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/
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
#
# 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
/*
* 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");
/*
* 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);
/*
* 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");
/*
* 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");
/*
* 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;
};
/*
* 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
/*
* 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
/*
* 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
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment