code:
=============
PCMCIA Driver
=============

sysfs
-----

New PCMCIA IDs may be added to a device driver pcmcia_device_id table at
runtime as shown below::

  echo "match_flags manf_id card_id func_id function device_no \
  prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \
  /sys/bus/pcmcia/drivers/{driver}/new_id

All fields are passed in as hexadecimal values (no leading 0x).
The meaning is described in the PCMCIA specification, the match_flags is
a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants
defined in include/linux/mod_devicetable.h.

Once added, the driver probe routine will be invoked for any unclaimed
PCMCIA device listed in its (newly updated) pcmcia_device_id list.

A common use-case is to add a new device according to the manufacturer ID
and the card ID (form the manf_id and card_id file in the device tree).
For this, just use::

  echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \
    /sys/bus/pcmcia/drivers/{driver}/new_id

after loading the driver.


code:
.. SPDX-License-Identifier: GPL-2.0

======
pcmcia
======

.. toctree::
    :maxdepth: 1

    driver
    devicetable
    locking
    driver-changes

.. only::  subproject and html

   Indices
   =======

   * :ref:`genindex`

repo_name: angery/linux


code:
=======
Locking
=======

This file explains the locking and exclusion scheme used in the PCCARD
and PCMCIA subsystems.

A) Overview, Locking Hierarchy:
===============================

pcmcia_socket_list_rwsem
	- protects only the list of sockets

- skt_mutex
	- serializes card insert / ejection

  - ops_mutex
	- serializes socket operation

B) Exclusion
============

The following functions and callbacks to struct pcmcia_socket must
be called with "skt_mutex" held::

	socket_detect_change()
	send_event()
	socket_reset()
	socket_shutdown()
	socket_setup()
	socket_remove()
	socket_insert()
	socket_early_resume()
	socket_late_resume()
	socket_resume()
	socket_suspend()

	struct pcmcia_callback	*callback

The following functions and callbacks to struct pcmcia_socket must
be called with "ops_mutex" held::

	socket_reset()
	socket_setup()

	struct pccard_operations	*ops
	struct pccard_resource_ops	*resource_ops;

Note that send_event() and `struct pcmcia_callback *callback` must not be
called with "ops_mutex" held.

C) Protection
=============

1. Global Data:
---------------
struct list_head	pcmcia_socket_list;

protected by pcmcia_socket_list_rwsem;

2. Per-Socket Data:
-------------------
The resource_ops and their data are protected by ops_mutex.

The "main" struct pcmcia_socket is protected as follows (read-only fields
or single-use fields not mentioned):

- by pcmcia_socket_list_rwsem::

	struct list_head	socket_list;

- by thread_lock::

	unsigned int		thread_events;

- by skt_mutex::

	u_int			suspended_state;
	void			(*tune_bridge);
	struct pcmcia_callback	*callback;
	int			resume_status;

- by ops_mutex::

	socket_state_t		socket;
	u_int			state;
	u_short			lock_count;
	pccard_mem_map		cis_mem;
	void __iomem 		*cis_virt;
	struct { }		irq;
	io_window_t		io[];
	pccard_mem_map		win[];
	struct list_head	cis_cache;
	size_t			fake_cis_len;
	u8			*fake_cis;
	u_int			irq_mask;
	void 			(*zoom_video);
	int 			(*power_hook);
	u8			resource...;
	struct list_head	devices_list;
	u8			device_count;
	struct 			pcmcia_state;

3. Per PCMCIA-device Data:
--------------------------

The "main" struct pcmcia_device is protected as follows (read-only fields
or single-use fields not mentioned):

- by pcmcia_socket->ops_mutex::

	struct list_head	socket_device_list;
	struct config_t		*function_config;
	u16			_irq:1;
	u16			_io:1;
	u16			_win:4;
	u16			_locked:1;
	u16			allow_func_id_match:1;
	u16			suspended:1;
	u16			_removed:1;

- by the PCMCIA driver::

	io_req_t		io;
	irq_req_t		irq;
	config_req_t		conf;
	window_handle_t		win;


code:
.. SPDX-License-Identifier: GPL-2.0-only

====================
Linux PECI Subsystem
====================

.. toctree::

   peci

.. only::  subproject and html

   Indices
   =======

   * :ref:`genindex`


code:
.. SPDX-License-Identifier: GPL-2.0-only

========
Overview
========

The Platform Environment Control Interface (PECI) is a communication
interface between Intel processor and management controllers
(e.g. Baseboard Management Controller, BMC).
PECI provides services that allow the management controller to
configure, monitor and debug platform by accessing various registers.
It defines a dedicated command protocol, where the management
controller is acting as a PECI originator and the processor - as
a PECI responder.
PECI can be used in both single processor and multiple-processor based
systems.

NOTE:
Intel PECI specification is not released as a dedicated document,
instead it is a part of External Design Specification (EDS) for given
Intel CPU. External Design Specifications are usually not publicly
available.

PECI Wire
---------

PECI Wire interface uses a single wire for self-clocking and data
transfer. It does not require any additional control lines - the
physical layer is a self-clocked one-wire bus signal that begins each
bit with a driven, rising edge from an idle near zero volts. The
duration of the signal driven high allows to determine whether the bit
value is logic '0' or logic '1'. PECI Wire also includes variable data
rate established with every message.

For PECI Wire, each processor package will utilize unique, fixed
addresses within a defined range and that address should
have a fixed relationship with the processor socket ID - if one of the
processors is removed, it does not affect addresses of remaining
processors.

PECI subsystem internals
------------------------

.. kernel-doc:: include/linux/peci.h
.. kernel-doc:: drivers/peci/internal.h
.. kernel-doc:: drivers/peci/core.c
.. kernel-doc:: drivers/peci/request.c

PECI CPU Driver API
-------------------
.. kernel-doc:: drivers/peci/cpu.c


code:
============
APM or ACPI?
============

If you have a relatively recent x86 mobile, desktop, or server system,
odds are it supports either Advanced Power Management (APM) or
Advanced Configuration and Power Interface (ACPI).  ACPI is the newer
of the two technologies and puts power management in the hands of the
operating system, allowing for more intelligent power management than
is possible with BIOS controlled APM.

The best way to determine which, if either, your system supports is to
build a kernel with both ACPI and APM enabled (as of 2.3.x ACPI is
enabled by default).  If a working ACPI implementation is found, the
ACPI driver will override and disable APM, otherwise the APM driver
will be used.

No, sorry, you cannot have both ACPI and APM enabled and running at
once.  Some people with broken ACPI or broken APM implementations
would like to use both to get a full set of working features, but you
simply cannot mix and match the two.  Only one power management
interface can be in control of the machine at once.  Think about it..

User-space Daemons
------------------
Both APM and ACPI rely on user-space daemons, apmd and acpid
respectively, to be completely functional.  Obtain both of these
daemons from your Linux distribution or from the Internet (see below)
and be sure that they are started sometime in the system boot process.
Go ahead and start both.  If ACPI or APM is not available on your
system the associated daemon will exit gracefully.

  =====  =======================================
  apmd   http://ftp.debian.org/pool/main/a/apmd/
  acpid  http://acpid.sf.net/
  =====  =======================================


code:
=================================
Debugging hibernation and suspend
=================================

	(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL

1. Testing hibernation (aka suspend to disk or STD)
===================================================

To check if hibernation works, you can try to hibernate in the "reboot" mode::

	# echo reboot > /sys/power/disk
	# echo disk > /sys/power/state

and the system should create a hibernation image, reboot, resume and get back to
the command prompt where you have started the transition.  If that happens,
hibernation is most likely to work correctly.  Still, you need to repeat the
test at least a couple of times in a row for confidence.  [This is necessary,
because some problems only show up on a second attempt at suspending and
resuming the system.]  Moreover, hibernating in the "reboot" and "shutdown"
modes causes the PM core to skip some platform-related callbacks which on ACPI
systems might be necessary to make hibernation work.  Thus, if your machine
fails to hibernate or resume in the "reboot" mode, you should try the
"platform" mode::

	# echo platform > /sys/power/disk
	# echo disk > /sys/power/state

which is the default and recommended mode of hibernation.

Unfortunately, the "platform" mode of hibernation does not work on some systems
with broken BIOSes.  In such cases the "shutdown" mode of hibernation might
work::

	# echo shutdown > /sys/power/disk
	# echo disk > /sys/power/state

(it is similar to the "reboot" mode, but it requires you to press the power
button to make the system resume).

If neither "platform" nor "shutdown" hibernation mode works, you will need to
identify what goes wrong.

a) Test modes of hibernation
----------------------------

To find out why hibernation fails on your system, you can use a special testing
facility available if the kernel is compiled with CONFIG_PM_DEBUG set.  Then,
there is the file /sys/power/pm_test that can be used to make the hibernation
core run in a test mode.  There are 5 test modes available:

freezer
	- test the freezing of processes

devices
	- test the freezing of processes and suspending of devices

platform
	- test the freezing of processes, suspending of devices and platform
	  global control methods [1]_

processors
	- test the freezing of processes, suspending of devices, platform
	  global control methods [1]_ and the disabling of nonboot CPUs

core
	- test the freezing of processes, suspending of devices, platform global
	  control methods\ [1]_, the disabling of nonboot CPUs and suspending
	  of platform/system devices

.. [1]

    the platform global control methods are only available on ACPI systems
    and are only tested if the hibernation mode is set to "platform"

To use one of them it is necessary to write the corresponding string to
/sys/power/pm_test (eg. "devices" to test the freezing of processes and
suspending devices) and issue the standard hibernation commands.  For example,
to use the "devices" test mode along with the "platform" mode of hibernation,
you should do the following::

	# echo devices > /sys/power/pm_test
	# echo platform > /sys/power/disk
	# echo disk > /sys/power/state

Then, the kernel will try to freeze processes, suspend devices, wait a few
seconds (5 by default, but configurable by the suspend.pm_test_delay module
parameter), resume devices and thaw processes.  If "platform" is written to
/sys/power/pm_test , then after suspending devices the kernel will additionally
invoke the global control methods (eg. ACPI global control methods) used to
prepare the platform firmware for hibernation.  Next, it will wait a
configurable number of seconds and invoke the platform (eg. ACPI) global
methods used to cancel hibernation etc.

Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
hibernation/suspend operations.  Also, when open for reading, /sys/power/pm_test
contains a space-separated list of all available tests (including "none" that
represents the normal functionality) in which the current test level is
indicated by square brackets.

Generally, as you can see, each test level is more "invasive" than the previous
one and the "core" level tests the hardware and drivers as deeply as possible
without creating a hibernation image.  Obviously, if the "devices" test fails,
the "platform" test will fail as well and so on.  Thus, as a rule of thumb, you
should try the test modes starting from "freezer", through "devices", "platform"
and "processors" up to "core" (repeat the test on each level a couple of times
to make sure that any random factors are avoided).

If the "freezer" test fails, there is a task that cannot be frozen (in that case
it usually is possible to identify the offending task by analysing the output of
dmesg obtained after the failing test).  Failure at this level usually means
that there is a problem with the tasks freezer subsystem that should be
reported.

If the "devices" test fails, most likely there is a driver that cannot suspend
or resume its device (in the latter case the system may hang or become unstable
after the test, so please take that into consideration).  To find this driver,
you can carry out a binary search according to the rules:

- if the test fails, unload a half of the drivers currently loaded and repeat
  (that would probably involve rebooting the system, so always note what drivers
  have been loaded before the test),
- if the test succeeds, load a half of the drivers you have unloaded most
  recently and repeat.

Once you have found the failing driver (there can be more than just one of
them), you have to unload it every time before hibernation.  In that case please
make sure to report the problem with the driver.

It is also possible that the "devices" test will still fail after you have
unloaded all modules. In that case, you may want to look in your kernel
configuration for the drivers that can be compiled as modules (and test again
with these drivers compiled as modules).  You may also try to use some special
kernel command line options such as "noapic", "noacpi" or even "acpi=off".

If the "platform" test fails, there is a problem with the handling of the
platform (eg. ACPI) firmware on your system.  In that case the "platform" mode
of hibernation is not likely to work.  You can try the "shutdown" mode, but that
is rather a poor man's workaround.

If the "processors" test fails, the disabling/enabling of nonboot CPUs does not
work (of course, this only may be an issue on SMP systems) and the problem
should be reported.  In that case you can also try to switch the nonboot CPUs
off and on using the /sys/devices/system/cpu/cpu*/online sysfs attributes and
see if that works.

If the "core" test fails, which means that suspending of the system/platform
devices has failed (these devices are suspended on one CPU with interrupts off),
the problem is most probably hardware-related and serious, so it should be
reported.

A failure of any of the "platform", "processors" or "core" tests may cause your
system to hang or become unstable, so please beware.  Such a failure usually
indicates a serious problem that very well may be related to the hardware, but
please report it anyway.

b) Testing minimal configuration
--------------------------------

If all of the hibernation test modes work, you can boot the system with the
"init=/bin/bash" command line parameter and attempt to hibernate in the
"reboot", "shutdown" and "platform" modes.  If that does not work, there
probably is a problem with a driver statically compiled into the kernel and you
can try to compile more drivers as modules, so that they can be tested
individually.  Otherwise, there is a problem with a modular driver and you can
find it by loading a half of the modules you normally use and binary searching
in accordance with the algorithm:
- if there are n modules loaded and the attempt to suspend and resume fails,
unload n/2 of the modules and try again (that would probably involve rebooting
the system),
- if there are n modules loaded and the attempt to suspend and resume succeeds,
load n/2 modules more and try again.

Again, if you find the offending module(s), it(they) must be unloaded every time
before hibernation, and please report the problem with it(them).

c) Using the "test_resume" hibernation option
---------------------------------------------

/sys/power/disk generally tells the kernel what to do after creating a
hibernation image.  One of the available options is "test_resume" which
causes the just created image to be used for immediate restoration.  Namely,
after doing::

	# echo test_resume > /sys/power/disk
	# echo disk > /sys/power/state

a hibernation image will be created and a resume from it will be triggered
immediately without involving the platform firmware in any way.

That test can be used to check if failures to resume from hibernation are
related to bad interactions with the platform firmware.  That is, if the above
works every time, but resume from actual hibernation does not work or is
unreliable, the platform firmware may be responsible for the failures.

On architectures and platforms that support using different kernels to restore
hibernation images (that is, the kernel used to read the image from storage and
load it into memory is different from the one included in the image) or support
kernel address space randomization, it also can be used to check if failures
to resume may be related to the differences between the restore and image
kernels.

d) Advanced debugging
---------------------

In case that hibernation does not work on your system even in the minimal
configuration and compiling more drivers as modules is not practical or some
modules cannot be unloaded, you can use one of the more advanced debugging
techniques to find the problem.  First, if there is a serial port in your box,
you can boot the kernel with the 'no_console_suspend' parameter and try to log
kernel messages using the serial console.  This may provide you with some
information about the reasons of the suspend (resume) failure.  Alternatively,
it may be possible to use a FireWire port for debugging with firescope
(http://v3.sk/~lkundrak/firescope/).  On x86 it is also possible to
use the PM_TRACE mechanism documented in Documentation/power/s2ram.rst .

2. Testing suspend to RAM (STR)
===============================

To verify that the STR works, it is generally more convenient to use the s2ram
tool available from http://suspend.sf.net and documented at
http://en.opensuse.org/SDB:Suspend_to_RAM (S2RAM_LINK).

Namely, after writing "freezer", "devices", "platform", "processors", or "core"
into /sys/power/pm_test (available if the kernel is compiled with
CONFIG_PM_DEBUG set) the suspend code will work in the test mode corresponding
to given string.  The STR test modes are defined in the same way as for
hibernation, so please refer to Section 1 for more information about them.  In
particular, the "core" test allows you to test everything except for the actual
invocation of the platform firmware in order to put the system into the sleep
state.

Among other things, the testing with the help of /sys/power/pm_test may allow
you to identify drivers that fail to suspend or resume their devices.  They
should be unloaded every time before an STR transition.

Next, you can follow the instructions at S2RAM_LINK to test the system, but if
it does not work "out of the box", you may need to boot it with
"init=/bin/bash" and test s2ram in the minimal configuration.  In that case,
you may be able to search for failing drivers by following the procedure
analogous to the one described in section 1.  If you find some failing drivers,
you will have to unload them every time before an STR transition (ie. before
you run s2ram), and please report the problems with them.

There is a debugfs entry which shows the suspend to RAM statistics. Here is an
example of its output::

	# mount -t debugfs none /sys/kernel/debug
	# cat /sys/kernel/debug/suspend_stats
	success: 20
	fail: 5
	failed_freeze: 0
	failed_prepare: 0
	failed_suspend: 5
	failed_suspend_noirq: 0
	failed_resume: 0
	failed_resume_noirq: 0
	failures:
	  last_failed_dev:	alarm
				adc
	  last_failed_errno:	-16
				-16
	  last_failed_step:	suspend
				suspend

Field success means the success number of suspend to RAM, and field fail means
the failure number. Others are the failure number of different steps of suspend
to RAM. suspend_stats just lists the last 2 failed devices, error number and
failed step of suspend.


code:
===============
Charger Manager
===============

	(C) 2011 MyungJoo Ham <myungjoo.ham@samsung.com>, GPL

Charger Manager provides in-kernel battery charger management that
requires temperature monitoring during suspend-to-RAM state
and where each battery may have multiple chargers attached and the userland
wants to look at the aggregated information of the multiple chargers.

Charger Manager is a platform_driver with power-supply-class entries.
An instance of Charger Manager (a platform-device created with Charger-Manager)
represents an independent battery with chargers. If there are multiple
batteries with their own chargers acting independently in a system,
the system may need multiple instances of Charger Manager.

1. Introduction
===============

Charger Manager supports the following:

* Support for multiple chargers (e.g., a device with USB, AC, and solar panels)
	A system may have multiple chargers (or power sources) and some of
	they may be activated at the same time. Each charger may have its
	own power-supply-class and each power-supply-class can provide
	different information about the battery status. This framework
	aggregates charger-related information from multiple sources and
	shows combined information as a single power-supply-class.

* Support for in suspend-to-RAM polling (with suspend_again callback)
	While the battery is being charged and the system is in suspend-to-RAM,
	we may need to monitor the battery health by looking at the ambient or
	battery temperature. We can accomplish this by waking up the system
	periodically. However, such a method wakes up devices unnecessarily for
	monitoring the battery health and tasks, and user processes that are
	supposed to be kept suspended. That, in turn, incurs unnecessary power
	consumption and slow down charging process. Or even, such peak power
	consumption can stop chargers in the middle of charging
	(external power input < device power consumption), which not
	only affects the charging time, but the lifespan of the battery.

	Charger Manager provides a function "cm_suspend_again" that can be
	used as suspend_again callback of platform_suspend_ops. If the platform
	requires tasks other than cm_suspend_again, it may implement its own
	suspend_again callback that calls cm_suspend_again in the middle.
	Normally, the platform will need to resume and suspend some devices
	that are used by Charger Manager.

* Support for premature full-battery event handling
	If the battery voltage drops by "fullbatt_vchkdrop_uV" after
	"fullbatt_vchkdrop_ms" from the full-battery event, the framework
	restarts charging. This check is also performed while suspended by
	setting wakeup time accordingly and using suspend_again.

* Support for uevent-notify
	With the charger-related events, the device sends
	notification to users with UEVENT.

2. Global Charger-Manager Data related with suspend_again
=========================================================
In order to setup Charger Manager with suspend-again feature
(in-suspend monitoring), the user should provide charger_global_desc
with setup_charger_manager(`struct charger_global_desc *`).
This charger_global_desc data for in-suspend monitoring is global
as the name suggests. Thus, the user needs to provide only once even
if there are multiple batteries. If there are multiple batteries, the
multiple instances of Charger Manager share the same charger_global_desc
and it will manage in-suspend monitoring for all instances of Charger Manager.

The user needs to provide all the three entries to `struct charger_global_desc`
properly in order to activate in-suspend monitoring:

`char *rtc_name;`
	The name of rtc (e.g., "rtc0") used to wakeup the system from
	suspend for Charger Manager. The alarm interrupt (AIE) of the rtc
	should be able to wake up the system from suspend. Charger Manager
	saves and restores the alarm value and use the previously-defined
	alarm if it is going to go off earlier than Charger Manager so that
	Charger Manager does not interfere with previously-defined alarms.

`bool (*rtc_only_wakeup)(void);`
	This callback should let CM know whether
	the wakeup-from-suspend is caused only by the alarm of "rtc" in the
	same struct. If there is any other wakeup source triggered the
	wakeup, it should return false. If the "rtc" is the only wakeup
	reason, it should return true.

`bool assume_timer_stops_in_suspend;`
	if true, Charger Manager assumes that
	the timer (CM uses jiffies as timer) stops during suspend. Then, CM
	assumes that the suspend-duration is same as the alarm length.

3. How to setup suspend_again
=============================
Charger Manager provides a function "extern bool cm_suspend_again(void)".
When cm_suspend_again is called, it monitors every battery. The suspend_ops
callback of the system's platform_suspend_ops can call cm_suspend_again
function to know whether Charger Manager wants to suspend again or not.
If there are no other devices or tasks that want to use suspend_again
feature, the platform_suspend_ops may directly refer to cm_suspend_again
for its suspend_again callback.

The cm_suspend_again() returns true (meaning "I want to suspend again")
if the system was woken up by Charger Manager and the polling
(in-suspend monitoring) results in "normal".

4. Charger-Manager Data (struct charger_desc)
=============================================
For each battery charged independently from other batteries (if a series of
batteries are charged by a single charger, they are counted as one independent
battery), an instance of Charger Manager is attached to it. The following

struct charger_desc elements:

`char *psy_name;`
	The power-supply-class name of the battery. Default is
	"battery" if psy_name is NULL. Users can access the psy entries
	at "/sys/class/power_supply/[psy_name]/".

`enum polling_modes polling_mode;`
	  CM_POLL_DISABLE:
		do not poll this battery.
	  CM_POLL_ALWAYS:
		always poll this battery.
	  CM_POLL_EXTERNAL_POWER_ONLY:
		poll this battery if and only if an external power
		source is attached.
	  CM_POLL_CHARGING_ONLY:
		poll this battery if and only if the battery is being charged.

`unsigned int fullbatt_vchkdrop_ms; / unsigned int fullbatt_vchkdrop_uV;`
	If both have non-zero values, Charger Manager will check the
	battery voltage drop fullbatt_vchkdrop_ms after the battery is fully
	charged. If the voltage drop is over fullbatt_vchkdrop_uV, Charger
	Manager will try to recharge the battery by disabling and enabling
	chargers. Recharge with voltage drop condition only (without delay
	condition) is needed to be implemented with hardware interrupts from
	fuel gauges or charger devices/chips.

`unsigned int fullbatt_uV;`
	If specified with a non-zero value, Charger Manager assumes
	that the battery is full (capacity = 100) if the battery is not being
	charged and the battery voltage is equal to or greater than
	fullbatt_uV.

`unsigned int polling_interval_ms;`
	Required polling interval in ms. Charger Manager will poll
	this battery every polling_interval_ms or more frequently.

`enum data_source battery_present;`
	CM_BATTERY_PRESENT:
		assume that the battery exists.
	CM_NO_BATTERY:
		assume that the battery does not exists.
	CM_FUEL_GAUGE:
		get battery presence information from fuel gauge.
	CM_CHARGER_STAT:
		get battery presence from chargers.

`char **psy_charger_stat;`
	An array ending with NULL that has power-supply-class names of
	chargers. Each power-supply-class should provide "PRESENT" (if
	battery_present is "CM_CHARGER_STAT"), "ONLINE" (shows whether an
	external power source is attached or not), and "STATUS" (shows whether
	the battery is {"FULL" or not FULL} or {"FULL", "Charging",
	"Discharging", "NotCharging"}).

`int num_charger_regulators; / struct regulator_bulk_data *charger_regulators;`
	Regulators representing the chargers in the form for
	regulator framework's bulk functions.

`char *psy_fuel_gauge;`
	Power-supply-class name of the fuel gauge.

`int (*temperature_out_of_range)(int *mC); / bool measure_battery_temp;`
	This callback returns 0 if the temperature is safe for charging,
	a positive number if it is too hot to charge, and a negative number
	if it is too cold to charge. With the variable mC, the callback returns
	the temperature in 1/1000 of centigrade.
	The source of temperature can be battery or ambient one according to
	the value of measure_battery_temp.

5. Notify Charger-Manager of charger events: cm_notify_event()
==============================================================
If there is an charger event is required to notify
Charger Manager, a charger device driver that triggers the event can call
cm_notify_event(psy, type, msg) to notify the corresponding Charger Manager.
In the function, psy is the charger driver's power_supply pointer, which is
associated with Charger-Manager. The parameter "type"
is the same as irq's type (enum cm_event_types). The event message "msg" is
optional and is effective only if the event type is "UNDESCRIBED" or "OTHERS".

6. Other Considerations
=======================

At the charger/battery-related events such as battery-pulled-out,
charger-pulled-out, charger-inserted, DCIN-over/under-voltage, charger-stopped,
and others critical to chargers, the system should be configured to wake up.
At least the following should wake up the system from a suspend:
a) charger-on/off b) external-power-in/out c) battery-in/out (while charging)

It is usually accomplished by configuring the PMIC as a wakeup source.


code:
====================================================
Testing suspend and resume support in device drivers
====================================================

	(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL

1. Preparing the test system
============================

Unfortunately, to effectively test the support for the system-wide suspend and
resume transitions in a driver, it is necessary to suspend and resume a fully
functional system with this driver loaded.  Moreover, that should be done
several times, preferably several times in a row, and separately for hibernation
(aka suspend to disk or STD) and suspend to RAM (STR), because each of these
cases involves slightly different operations and different interactions with
the machine's BIOS.

Of course, for this purpose the test system has to be known to suspend and
resume without the driver being tested.  Thus, if possible, you should first
resolve all suspend/resume-related problems in the test system before you start
testing the new driver.  Please see Documentation/power/basic-pm-debugging.rst
for more information about the debugging of suspend/resume functionality.

2. Testing the driver
=====================

Once you have resolved the suspend/resume-related problems with your test system
without the new driver, you are ready to test it:

a) Build the driver as a module, load it and try the test modes of hibernation
   (see: Documentation/power/basic-pm-debugging.rst, 1).

b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
   "platform" modes (see: Documentation/power/basic-pm-debugging.rst, 1).

c) Compile the driver directly into the kernel and try the test modes of
   hibernation.

d) Attempt to hibernate with the driver compiled directly into the kernel
   in the "reboot", "shutdown" and "platform" modes.

e) Try the test modes of suspend (see:
   Documentation/power/basic-pm-debugging.rst, 2).  [As far as the STR tests are
   concerned, it should not matter whether or not the driver is built as a
   module.]

f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
   (see: Documentation/power/basic-pm-debugging.rst, 2).

Each of the above tests should be repeated several times and the STD tests
should be mixed with the STR tests.  If any of them fails, the driver cannot be
regarded as suspend/resume-safe.


code:
.. SPDX-License-Identifier: GPL-2.0

=======================
Energy Model of devices
=======================

1. Overview
-----------

The Energy Model (EM) framework serves as an interface between drivers knowing
the power consumed by devices at various performance levels, and the kernel
subsystems willing to use that information to make energy-aware decisions.

The source of the information about the power consumed by devices can vary greatly
from one platform to another. These power costs can be estimated using
devicetree data in some cases. In others, the firmware will know better.
Alternatively, userspace might be best positioned. And so on. In order to avoid
each and every client subsystem to re-implement support for each and every
possible source of information on its own, the EM framework intervenes as an
abstraction layer which standardizes the format of power cost tables in the
kernel, hence enabling to avoid redundant work.

The power values might be expressed in micro-Watts or in an 'abstract scale'.
Multiple subsystems might use the EM and it is up to the system integrator to
check that the requirements for the power value scale types are met. An example
can be found in the Energy-Aware Scheduler documentation
Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or
powercap power values expressed in an 'abstract scale' might cause issues.
These subsystems are more interested in estimation of power used in the past,
thus the real micro-Watts might be needed. An example of these requirements can
be found in the Intelligent Power Allocation in
Documentation/driver-api/thermal/power_allocator.rst.
Kernel subsystems might implement automatic detection to check whether EM
registered devices have inconsistent scale (based on EM internal flag).
Important thing to keep in mind is that when the power values are expressed in
an 'abstract scale' deriving real energy in micro-Joules would not be possible.

The figure below depicts an example of drivers (Arm-specific here, but the
approach is applicable to any architecture) providing power costs to the EM
framework, and interested clients reading the data from it::

       +---------------+  +-----------------+  +---------------+
       | Thermal (IPA) |  | Scheduler (EAS) |  |     Other     |
       +---------------+  +-----------------+  +---------------+
               |                   | em_cpu_energy()   |
               |                   | em_cpu_get()      |
               +---------+         |         +---------+
                         |         |         |
                         v         v         v
                        +---------------------+
                        |    Energy Model     |
                        |     Framework       |
                        +---------------------+
                           ^       ^       ^
                           |       |       | em_dev_register_perf_domain()
                +----------+       |       +---------+
                |                  |                 |
        +---------------+  +---------------+  +--------------+
        |  cpufreq-dt   |  |   arm_scmi    |  |    Other     |
        +---------------+  +---------------+  +--------------+
                ^                  ^                 ^
                |                  |                 |
        +--------------+   +---------------+  +--------------+
        | Device Tree  |   |   Firmware    |  |      ?       |
        +--------------+   +---------------+  +--------------+

In case of CPU devices the EM framework manages power cost tables per
'performance domain' in the system. A performance domain is a group of CPUs
whose performance is scaled together. Performance domains generally have a
1-to-1 mapping with CPUFreq policies. All CPUs in a performance domain are
required to have the same micro-architecture. CPUs in different performance
domains can have different micro-architectures.

2. Core APIs
------------

2.1 Config options
^^^^^^^^^^^^^^^^^^

CONFIG_ENERGY_MODEL must be enabled to use the EM framework.

2.2 Registration of performance domains
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Registration of 'advanced' EM
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The 'advanced' EM gets it's name due to the fact that the driver is allowed
to provide more precised power model. It's not limited to some implemented math
formula in the framework (like it's in 'simple' EM case). It can better reflect
the real power measurements performed for each performance state. Thus, this
registration method should be preferred in case considering EM static power
(leakage) is important.

Drivers are expected to register performance domains into the EM framework by
calling the following API::

  int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
		struct em_data_callback *cb, cpumask_t *cpus, bool microwatts);

Drivers must provide a callback function returning <frequency, power> tuples
for each performance state. The callback function provided by the driver is free
to fetch data from any relevant location (DT, firmware, ...), and by any mean
deemed necessary. Only for CPU devices, drivers must specify the CPUs of the
performance domains using cpumask. For other devices than CPUs the last
argument must be set to NULL.
The last argument 'microwatts' is important to set with correct value. Kernel
subsystems which use EM might rely on this flag to check if all EM devices use
the same scale. If there are different scales, these subsystems might decide
to return warning/error, stop working or panic.
See Section 3. for an example of driver implementing this
callback, or Section 2.4 for further documentation on this API

Registration of EM using DT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The  EM can also be registered using OPP framework and information in DT
"operating-points-v2". Each OPP entry in DT can be extended with a property
"opp-microwatt" containing micro-Watts power value. This OPP DT property
allows a platform to register EM power values which are reflecting total power
(static + dynamic). These power values might be coming directly from
experiments and measurements.

Registration of 'artificial' EM
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There is an option to provide a custom callback for drivers missing detailed
knowledge about power value for each performance state. The callback
.get_cost() is optional and provides the 'cost' values used by the EAS.
This is useful for platforms that only provide information on relative
efficiency between CPU types, where one could use the information to
create an abstract power model. But even an abstract power model can
sometimes be hard to fit in, given the input power value size restrictions.
The .get_cost() allows to provide the 'cost' values which reflect the
efficiency of the CPUs. This would allow to provide EAS information which
has different relation than what would be forced by the EM internal
formulas calculating 'cost' values. To register an EM for such platform, the
driver must set the flag 'microwatts' to 0, provide .get_power() callback
and provide .get_cost() callback. The EM framework would handle such platform
properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such
platform. Special care should be taken by other frameworks which are using EM
to test and treat this flag properly.

Registration of 'simple' EM
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The 'simple' EM is registered using the framework helper function
cpufreq_register_em_with_opp(). It implements a power model which is tight to
math formula::

	Power = C * V^2 * f

The EM which is registered using this method might not reflect correctly the
physics of a real device, e.g. when static power (leakage) is important.

2.3 Accessing performance domains
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are two API functions which provide the access to the energy model:
em_cpu_get() which takes CPU id as an argument and em_pd_get() with device
pointer as an argument. It depends on the subsystem which interface it is
going to use, but in case of CPU devices both functions return the same
performance domain.

Subsystems interested in the energy model of a CPU can retrieve it using the
em_cpu_get() API. The energy model tables are allocated once upon creation of
the performance domains, and kept in memory untouched.

The energy consumed by a performance domain can be estimated using the
em_cpu_energy() API. The estimation is performed assuming that the schedutil
CPUfreq governor is in use in case of CPU device. Currently this calculation is
not provided for other type of devices.

More details about the above APIs can be found in ``<linux/energy_model.h>``
or in Section 2.4

2.4 Description details of this API
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. kernel-doc:: include/linux/energy_model.h
   :internal:

.. kernel-doc:: kernel/power/energy_model.c
   :export:

3. Example driver
-----------------

The CPUFreq framework supports dedicated callback for registering
the EM for a given CPU(s) 'policy' object: cpufreq_driver::register_em().
That callback has to be implemented properly for a given driver,
because the framework would call it at the right time during setup.
This section provides a simple example of a CPUFreq driver registering a
performance domain in the Energy Model framework using the (fake) 'foo'
protocol. The driver implements an est_power() function to be provided to the
EM framework::

  -> drivers/cpufreq/foo_cpufreq.c

  01	static int est_power(struct device *dev, unsigned long *mW,
  02			unsigned long *KHz)
  03	{
  04		long freq, power;
  05
  06		/* Use the 'foo' protocol to ceil the frequency */
  07		freq = foo_get_freq_ceil(dev, *KHz);
  08		if (freq < 0);
  09			return freq;
  10
  11		/* Estimate the power cost for the dev at the relevant freq. */
  12		power = foo_estimate_power(dev, freq);
  13		if (power < 0);
  14			return power;
  15
  16		/* Return the values to the EM framework */
  17		*mW = power;
  18		*KHz = freq;
  19
  20		return 0;
  21	}
  22
  23	static void foo_cpufreq_register_em(struct cpufreq_policy *policy)
  24	{
  25		struct em_data_callback em_cb = EM_DATA_CB(est_power);
  26		struct device *cpu_dev;
  27		int nr_opp;
  28
  29		cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
  30
  31     	/* Find the number of OPPs for this policy */
  32     	nr_opp = foo_get_nr_opp(policy);
  33
  34     	/* And register the new performance domain */
  35     	em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus,
  36					    true);
  37	}
  38
  39	static struct cpufreq_driver foo_cpufreq_driver = {
  40		.register_em = foo_cpufreq_register_em,
  41	};


code:
=================
Freezing of tasks
=================

(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL

I. What is the freezing of tasks?
=================================

The freezing of tasks is a mechanism by which user space processes and some
kernel threads are controlled during hibernation or system-wide suspend (on some
architectures).

II. How does it work?
=====================

There are three per-task flags used for that, PF_NOFREEZE, PF_FROZEN
and PF_FREEZER_SKIP (the last one is auxiliary).  The tasks that have
PF_NOFREEZE unset (all user space processes and some kernel threads) are
regarded as 'freezable' and treated in a special way before the system enters a
suspend state as well as before a hibernation image is created (in what follows
we only consider hibernation, but the description also applies to suspend).

Namely, as the first step of the hibernation procedure the function
freeze_processes() (defined in kernel/power/process.c) is called.  A system-wide
variable system_freezing_cnt (as opposed to a per-task flag) is used to indicate
whether the system is to undergo a freezing operation. And freeze_processes()
sets this variable.  After this, it executes try_to_freeze_tasks() that sends a
fake signal to all user space processes, and wakes up all the kernel threads.
All freezable tasks must react to that by calling try_to_freeze(), which
results in a call to __refrigerator() (defined in kernel/freezer.c), which sets
the task's PF_FROZEN flag, changes its state to TASK_UNINTERRUPTIBLE and makes
it loop until PF_FROZEN is cleared for it. Then, we say that the task is
'frozen' and therefore the set of functions handling this mechanism is referred
to as 'the freezer' (these functions are defined in kernel/power/process.c,
kernel/freezer.c & include/linux/freezer.h). User space processes are generally
frozen before kernel threads.

__refrigerator() must not be called directly.  Instead, use the
try_to_freeze() function (defined in include/linux/freezer.h), that checks
if the task is to be frozen and makes the task enter __refrigerator().

For user space processes try_to_freeze() is called automatically from the
signal-handling code, but the freezable kernel threads need to call it
explicitly in suitable places or use the wait_event_freezable() or
wait_event_freezable_timeout() macros (defined in include/linux/freezer.h)
that combine interruptible sleep with checking if the task is to be frozen and
calling try_to_freeze().  The main loop of a freezable kernel thread may look
like the following one::

	set_freezable();
	do {
		hub_events();
		wait_event_freezable(khubd_wait,
				!list_empty(&hub_event_list) ||
				kthread_should_stop());
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));

(from drivers/usb/core/hub.c::hub_thread()).

If a freezable kernel thread fails to call try_to_freeze() after the freezer has
initiated a freezing operation, the freezing of tasks will fail and the entire
hibernation operation will be cancelled.  For this reason, freezable kernel
threads must call try_to_freeze() somewhere or use one of the
wait_event_freezable() and wait_event_freezable_timeout() macros.

After the system memory state has been restored from a hibernation image and
devices have been reinitialized, the function thaw_processes() is called in
order to clear the PF_FROZEN flag for each frozen task.  Then, the tasks that
have been frozen leave __refrigerator() and continue running.

Rationale behind the functions dealing with freezing and thawing of tasks
-------------------------------------------------------------------------

freeze_processes():
  - freezes only userspace tasks

freeze_kernel_threads():
  - freezes all tasks (including kernel threads) because we can't freeze
    kernel threads without freezing userspace tasks

thaw_kernel_threads():
  - thaws only kernel threads; this is particularly useful if we need to do
    anything special in between thawing of kernel threads and thawing of
    userspace tasks, or if we want to postpone the thawing of userspace tasks

thaw_processes():
  - thaws all tasks (including kernel threads) because we can't thaw userspace
    tasks without thawing kernel threads

III. Which kernel threads are freezable?
========================================

Kernel threads are not freezable by default.  However, a kernel thread may clear
PF_NOFREEZE for itself by calling set_freezable() (the resetting of PF_NOFREEZE
directly is not allowed).  From this point it is regarded as freezable
and must call try_to_freeze() in a suitable place.

IV. Why do we do that?
======================

Generally speaking, there is a couple of reasons to use the freezing of tasks:

1. The principal reason is to prevent filesystems from being damaged after
   hibernation.  At the moment we have no simple means of checkpointing
   filesystems, so if there are any modifications made to filesystem data and/or
   metadata on disks, we cannot bring them back to the state from before the
   modifications.  At the same time each hibernation image contains some
   filesystem-related information that must be consistent with the state of the
   on-disk data and metadata after the system memory state has been restored
   from the image (otherwise the filesystems will be damaged in a nasty way,
   usually making them almost impossible to repair).  We therefore freeze
   tasks that might cause the on-disk filesystems' data and metadata to be
   modified after the hibernation image has been created and before the
   system is finally powered off. The majority of these are user space
   processes, but if any of the kernel threads may cause something like this
   to happen, they have to be freezable.

2. Next, to create the hibernation image we need to free a sufficient amount of
   memory (approximately 50% of available RAM) and we need to do that before
   devices are deactivated, because we generally need them for swapping out.
   Then, after the memory for the image has been freed, we don't want tasks
   to allocate additional memory and we prevent them from doing that by
   freezing them earlier. [Of course, this also means that device drivers
   should not allocate substantial amounts of memory from their .suspend()
   callbacks before hibernation, but this is a separate issue.]

3. The third reason is to prevent user space processes and some kernel threads
   from interfering with the suspending and resuming of devices.  A user space
   process running on a second CPU while we are suspending devices may, for
   example, be troublesome and without the freezing of tasks we would need some
   safeguards against race conditions that might occur in such a case.

Although Linus Torvalds doesn't like the freezing of tasks, he said this in one
of the discussions on LKML (https://lore.kernel.org/r/alpine.LFD.0.98.0704271801020.9964@woody.linux-foundation.org):

"RJW:> Why we freeze tasks at all or why we freeze kernel threads?

Linus: In many ways, 'at all'.

I **do** realize the IO request queue issues, and that we cannot actually do
s2ram with some devices in the middle of a DMA.  So we want to be able to
avoid *that*, there's no question about that.  And I suspect that stopping
user threads and then waiting for a sync is practically one of the easier
ways to do so.

So in practice, the 'at all' may become a 'why freeze kernel threads?' and
freezing user threads I don't find really objectionable."

Still, there are kernel threads that may want to be freezable.  For example, if
a kernel thread that belongs to a device driver accesses the device directly, it
in principle needs to know when the device is suspended, so that it doesn't try
to access it at that time.  However, if the kernel thread is freezable, it will
be frozen before the driver's .suspend() callback is executed and it will be
thawed after the driver's .resume() callback has run, so it won't be accessing
the device while it's suspended.

4. Another reason for freezing tasks is to prevent user space processes from
   realizing that hibernation (or suspend) operation takes place.  Ideally, user
   space processes should not notice that such a system-wide operation has
   occurred and should continue running without any problems after the restore
   (or resume from suspend).  Unfortunately, in the most general case this
   is quite difficult to achieve without the freezing of tasks.  Consider,
   for example, a process that depends on all CPUs being online while it's
   running.  Since we need to disable nonboot CPUs during the hibernation,
   if this process is not frozen, it may notice that the number of CPUs has
   changed and may start to work incorrectly because of that.

V. Are there any problems related to the freezing of tasks?
===========================================================

Yes, there are.

First of all, the freezing of kernel threads may be tricky if they depend one
on another.  For example, if kernel thread A waits for a completion (in the
TASK_UNINTERRUPTIBLE state) that needs to be done by freezable kernel thread B
and B is frozen in the meantime, then A will be blocked until B is thawed, which
may be undesirable.  That's why kernel threads are not freezable by default.

Second, there are the following two problems related to the freezing of user
space processes:

1. Putting processes into an uninterruptible sleep distorts the load average.
2. Now that we have FUSE, plus the framework for doing device drivers in
   userspace, it gets even more complicated because some userspace processes are
   now doing the sorts of things that kernel threads do
   (https://lists.linux-foundation.org/pipermail/linux-pm/2007-May/012309.html).

The problem 1. seems to be fixable, although it hasn't been fixed so far.  The
other one is more serious, but it seems that we can work around it by using
hibernation (and suspend) notifiers (in that case, though, we won't be able to
avoid the realization by the user space processes that the hibernation is taking
place).

There are also problems that the freezing of tasks tends to expose, although
they are not directly related to it.  For example, if request_firmware() is
called from a device driver's .resume() routine, it will timeout and eventually
fail, because the user land process that should respond to the request is frozen
at this point.  So, seemingly, the failure is due to the freezing of tasks.
Suppose, however, that the firmware file is located on a filesystem accessible
only through another device that hasn't been resumed yet.  In that case,
request_firmware() will fail regardless of whether or not the freezing of tasks
is used.  Consequently, the problem is not really related to the freezing of
tasks, since it generally exists anyway.

A driver must have all firmwares it may need in RAM before suspend() is called.
If keeping them is not practical, for example due to their size, they must be
requested early enough using the suspend notifier API described in
Documentation/driver-api/pm/notifiers.rst.

VI. Are there any precautions to be taken to prevent freezing failures?
=======================================================================

Yes, there are.

First of all, grabbing the 'system_transition_mutex' lock to mutually exclude a
piece of code from system-wide sleep such as suspend/hibernation is not
encouraged.  If possible, that piece of code must instead hook onto the
suspend/hibernation notifiers to achieve mutual exclusion. Look at the
CPU-Hotplug code (kernel/cpu.c) for an example.

However, if that is not feasible, and grabbing 'system_transition_mutex' is
deemed necessary, it is strongly discouraged to directly call
mutex_[un]lock(&system_transition_mutex) since that could lead to freezing
failures, because if the suspend/hibernate code successfully acquired the
'system_transition_mutex' lock, and hence that other entity failed to acquire
the lock, then that task would get blocked in TASK_UNINTERRUPTIBLE state. As a
consequence, the freezer would not be able to freeze that task, leading to
freezing failure.

However, the [un]lock_system_sleep() APIs are safe to use in this scenario,
since they ask the freezer to skip freezing this task, since it is anyway
"frozen enough" as it is blocked on 'system_transition_mutex', which will be
released only after the entire suspend/hibernation sequence is complete.  So, to
summarize, use [un]lock_system_sleep() instead of directly using
mutex_[un]lock(&system_transition_mutex). That would prevent freezing failures.

V. Miscellaneous
================

/sys/power/pm_freeze_timeout controls how long it will cost at most to freeze
all user space processes or all freezable kernel threads, in unit of
millisecond.  The default value is 20000, with range of unsigned integer.


code:
.. SPDX-License-Identifier: GPL-2.0

================
Power Management
================

.. toctree::
    :maxdepth: 1

    apm-acpi
    basic-pm-debugging
    charger-manager
    drivers-testing
    energy-model
    freezing-of-tasks
    opp
    pci
    pm_qos_interface
    power_supply_class
    runtime_pm
    s2ram
    suspend-and-cpuhotplug
    suspend-and-interrupts
    swsusp-and-swap-files
    swsusp-dmcrypt
    swsusp
    video
    tricks

    userland-swsusp

    powercap/powercap
    powercap/dtpm

    regulator/consumer
    regulator/design
    regulator/machine
    regulator/overview
    regulator/regulator

.. only::  subproject and html

   Indices
   =======

   * :ref:`genindex`


code:
==========================================
Operating Performance Points (OPP) Library
==========================================

(C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated

.. Contents

  1. Introduction
  2. Initial OPP List Registration
  3. OPP Search Functions
  4. OPP Availability Control Functions
  5. OPP Data Retrieval Functions
  6. Data Structures

1. Introduction
===============

1.1 What is an Operating Performance Point (OPP)?
-------------------------------------------------

Complex SoCs of today consists of a multiple sub-modules working in conjunction.
In an operational system executing varied use cases, not all modules in the SoC
need to function at their highest performing frequency all the time. To
facilitate this, sub-modules in a SoC are grouped into domains, allowing some
domains to run at lower voltage and frequency while other domains run at
voltage/frequency pairs that are higher.

The set of discrete tuples consisting of frequency and voltage pairs that
the device will support per domain are called Operating Performance Points or
OPPs.

As an example:

Let us consider an MPU device which supports the following:
{300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V},
{1GHz at minimum voltage of 1.3V}

We can represent these as three OPPs as the following {Hz, uV} tuples:

- {300000000, 1000000}
- {800000000, 1200000}
- {1000000000, 1300000}

1.2 Operating Performance Points Library
----------------------------------------

OPP library provides a set of helper functions to organize and query the OPP
information. The library is located in drivers/opp/ directory and the header
is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
Instrument's OMAP framework allows to optionally boot at a certain OPP without
needing cpufreq.

Typical usage of the OPP library is as follows::

 (users)	-> registers a set of default OPPs		-> (library)
 SoC framework	-> modifies on required cases certain OPPs	-> OPP layer
		-> queries to search/retrieve information	->

OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
This initial list contains a set of OPPs that the framework expects to be safely
enabled by default in the system.

Note on OPP Availability
^^^^^^^^^^^^^^^^^^^^^^^^

As the system proceeds to operate, SoC framework may choose to make certain
OPPs available or not available on each device based on various external
factors. Example usage: Thermal management or other exceptional situations where
SoC framework might choose to disable a higher frequency OPP to safely continue
operations until that OPP could be re-enabled if possible.

OPP library facilitates this concept in its implementation. The following
operational functions operate only on available opps:
dev_pm_opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq,
dev_pm_opp_get_opp_count.

dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer
which can then be used for dev_pm_opp_enable/disable functions to make an
opp available as required.

WARNING: Users of OPP library should refresh their availability count using
get_opp_count if dev_pm_opp_enable/disable functions are invoked for a
device, the exact mechanism to trigger these or the notification mechanism
to other dependent subsystems such as cpufreq are left to the discretion of
the SoC specific framework which uses the OPP library. Similar care needs
to be taken care to refresh the cpufreq table in cases of these operations.

2. Initial OPP List Registration
================================
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
device. It is expected that the SoC framework will register the OPP entries
optimally- typical numbers range to be less than 5. The list generated by
registering the OPPs is maintained by OPP library throughout the device
operation. The SoC framework can subsequently control the availability of the
OPPs dynamically using the dev_pm_opp_enable / disable functions.

dev_pm_opp_add
	Add a new OPP for a specific domain represented by the device pointer.
	The OPP is defined using the frequency and voltage. Once added, the OPP
	is assumed to be available and control of its availability can be done
	with the dev_pm_opp_enable/disable functions. OPP library
	internally stores and manages this information in the dev_pm_opp struct.
	This function may be used by SoC framework to define a optimal list
	as per the demands of SoC usage environment.

	WARNING:
		Do not use this function in interrupt context.

	Example::

	 soc_pm_init()
	 {
		/* Do things */
		r = dev_pm_opp_add(mpu_dev, 1000000, 900000);
		if (!r) {
			pr_err("%s: unable to register mpu opp(%d)\n", r);
			goto no_cpufreq;
		}
		/* Do cpufreq things */
	 no_cpufreq:
		/* Do remaining things */
	 }

3. OPP Search Functions
=======================
High level framework such as cpufreq operates on frequencies. To map the
frequency back to the corresponding OPP, OPP library provides handy functions
to search the OPP list that OPP library internally manages. These search
functions return the matching pointer representing the opp if a match is
found, else returns error. These errors are expected to be handled by standard
error checks such as IS_ERR() and appropriate actions taken by the caller.

Callers of these functions shall call dev_pm_opp_put() after they have used the
OPP. Otherwise the memory for the OPP will never get freed and result in
memleak.

dev_pm_opp_find_freq_exact
	Search for an OPP based on an *exact* frequency and
	availability. This function is especially useful to enable an OPP which
	is not available by default.
	Example: In a case when SoC framework detects a situation where a
	higher frequency could be made available, it can use this function to
	find the OPP prior to call the dev_pm_opp_enable to actually make
	it available::

	 opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
	 dev_pm_opp_put(opp);
	 /* dont operate on the pointer.. just do a sanity check.. */
	 if (IS_ERR(opp)) {
		pr_err("frequency not disabled!\n");
		/* trigger appropriate actions.. */
	 } else {
		dev_pm_opp_enable(dev,1000000000);
	 }

	NOTE:
	  This is the only search function that operates on OPPs which are
	  not available.

dev_pm_opp_find_freq_floor
	Search for an available OPP which is *at most* the
	provided frequency. This function is useful while searching for a lesser
	match OR operating on OPP information in the order of decreasing
	frequency.
	Example: To find the highest opp for a device::

	 freq = ULONG_MAX;
	 opp = dev_pm_opp_find_freq_floor(dev, &freq);
	 dev_pm_opp_put(opp);

dev_pm_opp_find_freq_ceil
	Search for an available OPP which is *at least* the
	provided frequency. This function is useful while searching for a
	higher match OR operating on OPP information in the order of increasing
	frequency.
	Example 1: To find the lowest opp for a device::

	 freq = 0;
	 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
	 dev_pm_opp_put(opp);

	Example 2: A simplified implementation of a SoC cpufreq_driver->target::

	 soc_cpufreq_target(..)
	 {
		/* Do stuff like policy checks etc. */
		/* Find the best frequency match for the req */
		opp = dev_pm_opp_find_freq_ceil(dev, &freq);
		dev_pm_opp_put(opp);
		if (!IS_ERR(opp))
			soc_switch_to_freq_voltage(freq);
		else
			/* do something when we can't satisfy the req */
		/* do other stuff */
	 }

4. OPP Availability Control Functions
=====================================
A default OPP list registered with the OPP library may not cater to all possible
situation. The OPP library provides a set of functions to modify the
availability of a OPP within the OPP list. This allows SoC frameworks to have
fine grained dynamic control of which sets of OPPs are operationally available.
These functions are intended to *temporarily* remove an OPP in conditions such
as thermal considerations (e.g. don't use OPPx until the temperature drops).

WARNING:
	Do not use these functions in interrupt context.

dev_pm_opp_enable
	Make a OPP available for operation.
	Example: Lets say that 1GHz OPP is to be made available only if the
	SoC temperature is lower than a certain threshold. The SoC framework
	implementation might choose to do something as follows::

	 if (cur_temp < temp_low_thresh) {
		/* Enable 1GHz if it was disabled */
		opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
		dev_pm_opp_put(opp);
		/* just error check */
		if (!IS_ERR(opp))
			ret = dev_pm_opp_enable(dev, 1000000000);
		else
			goto try_something_else;
	 }

dev_pm_opp_disable
	Make an OPP to be not available for operation
	Example: Lets say that 1GHz OPP is to be disabled if the temperature
	exceeds a threshold value. The SoC framework implementation might
	choose to do something as follows::

	 if (cur_temp > temp_high_thresh) {
		/* Disable 1GHz if it was enabled */
		opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
		dev_pm_opp_put(opp);
		/* just error check */
		if (!IS_ERR(opp))
			ret = dev_pm_opp_disable(dev, 1000000000);
		else
			goto try_something_else;
	 }

5. OPP Data Retrieval Functions
===============================
Since OPP library abstracts away the OPP information, a set of functions to pull
information from the dev_pm_opp structure is necessary. Once an OPP pointer is
retrieved using the search functions, the following functions can be used by SoC
framework to retrieve the information represented inside the OPP layer.

dev_pm_opp_get_voltage
	Retrieve the voltage represented by the opp pointer.
	Example: At a cpufreq transition to a different frequency, SoC
	framework requires to set the voltage represented by the OPP using
	the regulator framework to the Power Management chip providing the
	voltage::

	 soc_switch_to_freq_voltage(freq)
	 {
		/* do things */
		opp = dev_pm_opp_find_freq_ceil(dev, &freq);
		v = dev_pm_opp_get_voltage(opp);
		dev_pm_opp_put(opp);
		if (v)
			regulator_set_voltage(.., v);
		/* do other things */
	 }

dev_pm_opp_get_freq
	Retrieve the freq represented by the opp pointer.
	Example: Lets say the SoC framework uses a couple of helper functions
	we could pass opp pointers instead of doing additional parameters to
	handle quiet a bit of data parameters::

	 soc_cpufreq_target(..)
	 {
		/* do things.. */
		 max_freq = ULONG_MAX;
		 max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
		 requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
		 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
			r = soc_test_validity(max_opp, requested_opp);
		 dev_pm_opp_put(max_opp);
		 dev_pm_opp_put(requested_opp);
		/* do other things */
	 }
	 soc_test_validity(..)
	 {
		 if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp))
			 return -EINVAL;
		 if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp))
			 return -EINVAL;
		/* do things.. */
	 }

dev_pm_opp_get_opp_count
	Retrieve the number of available opps for a device
	Example: Lets say a co-processor in the SoC needs to know the available
	frequencies in a table, the main processor can notify as following::

	 soc_notify_coproc_available_frequencies()
	 {
		/* Do things */
		num_available = dev_pm_opp_get_opp_count(dev);
		speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
		/* populate the table in increasing order */
		freq = 0;
		while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
			speeds[i] = freq;
			freq++;
			i++;
			dev_pm_opp_put(opp);
		}

		soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
		/* Do other things */
	 }

6. Data Structures
==================
Typically an SoC contains multiple voltage domains which are variable. Each
domain is represented by a device pointer. The relationship to OPP can be
represented as follows::

  SoC
   |- device 1
   |	|- opp 1 (availability, freq, voltage)
   |	|- opp 2 ..
   ...	...
   |	`- opp n ..
   |- device 2
   ...
   `- device m

OPP library maintains a internal list that the SoC framework populates and
accessed by various functions as described above. However, the structures
representing the actual OPPs and domains are internal to the OPP library itself
to allow for suitable abstraction reusable across systems.

struct dev_pm_opp
	The internal data structure of OPP library which is used to
	represent an OPP. In addition to the freq, voltage, availability
	information, it also contains internal book keeping information required
	for the OPP library to operate on.  Pointer to this structure is
	provided back to the users such as SoC framework to be used as a
	identifier for OPP in the interactions with OPP layer.

	WARNING:
	  The struct dev_pm_opp pointer should not be parsed or modified by the
	  users. The defaults of for an instance is populated by
	  dev_pm_opp_add, but the availability of the OPP can be modified
	  by dev_pm_opp_enable/disable functions.

struct device
	This is used to identify a domain to the OPP layer. The
	nature of the device and its implementation is left to the user of
	OPP library such as the SoC framework.

Overall, in a simplistic view, the data structure operations is represented as
following::

  Initialization / modification:
              +-----+        /- dev_pm_opp_enable
  dev_pm_opp_add --> | opp | <-------
    |         +-----+        \- dev_pm_opp_disable
    \-------> domain_info(device)

  Search functions:
               /-- dev_pm_opp_find_freq_ceil  ---\   +-----+
  domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
               \-- dev_pm_opp_find_freq_floor ---/   +-----+

  Retrieval functions:
  +-----+     /- dev_pm_opp_get_voltage
  | opp | <---
  +-----+     \- dev_pm_opp_get_freq

  domain_info <- dev_pm_opp_get_opp_count