tp_smapi version 0.30
IBM ThinkPad hardware functions driver

Author:  Shem Multinymous <multinymous@gmail.com>
Project: http://sourceforge.net/projects/tpctl
Wiki:    http://thinkwiki.org/wiki/tp_smapi
List:    linux-thinkpad@linux-thinkpad.org
         (http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad)

Description
-----------

ThinkPad laptops include a proprietary interface called SMAPI BIOS 
(System Management Application Program Interface) which provides some
hardware control functionality that is not accessible by other means.

This driver exposes some features of the SMAPI BIOS through a sysfs 
interface. It is suitable for newer models, on which SMAPI is invoked 
through IO port writes. Older models use a different SMAPI interface; 
for those, try the "thinkpad" module from the "tpctl" package.

WARNING: 
This driver uses undocumented features and direct hardware access.
It thus cannot be guaranteed to work, and may cause arbitrary damage
(especially on models it wasn't tested on).


Installation
------------

For testing, you can simply compile and load the driver within the current
working directory:
# make load

To compile and install into the kernel's module path:
# make install

If you use the HDAPS driver, use these instead to replace the hdaps module
with one patched for compatibility with tp_smapi (kernel source tree needed):
# make load HDAPS=1
or
# make install HDAPS=1

To prepare a stand-alone patch against the current kernel tree (including
a compatibility fixes to hdaps and Kconfig entries):
# make patch

To work against a kernel (other than the current one) that's
installed under /lib/modules/, add an appropriate KVER= parameter
# make patch KVER=2.6.16-rc2
To work against an uninstalled kernel, you'll need to set KSRC and KBUILD too:
# make patch KVER=2.6.16-rc2 KSRC=$HOME/2.6.16-rc2 KBUILD=$HOME/2.6.16-rc2

To delete all autogenerated files:
# make clean

Append "DEBUG=1" to "make load" to load tp_smapi with debug=1.

The original kernel tree is never modified by any these commands. 
The /lib/modules directory is modified only by "make install".

If your kernel doesn't have dmi-decode-and-save-oem-string-information
applied (see below) then all make commands except "make patch" will need
to invoke "dmidecode" using "sudo", to get information about your
hardware at compile time.


Module parameters
-----------------

tp_smapi module: 
  debug=1 enables verbose dmesg output.


Usage
-----

Control of battery charging thresholds (in percents of current full charge
capacity):

# echo 40 > /sys/devices/platform/smapi/BAT0/start_charge_thresh
# echo 70 > /sys/devices/platform/smapi/BAT0/stop_charge_thresh
# cat /sys/devices/platform/smapi/BAT0/*_charge_thresh

    (This is useful since Li-Ion batteries wear out much faster at very 
     high or low charge levels. The driver will also keeps the thresholds 
     across suspend-to-disk with AC disconnected; this isn't done 
     automatically by the hardware.)

Inhibiting battery charging for 17 minutes (overrides thresholds):

# echo 17 > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes
# echo 0  > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes  # stop
# cat /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes

    (This can be used to control which battery is charged when using an 
     Ultrabay battery.)

Forcing battery discharging even if AC power available:

# echo 1 > /sys/devices/platform/smapi/BAT0/force_discharge  # start discharge
# echo 0 > /sys/devices/platform/smapi/BAT0/force_discharge  # stop discharge
# cat /sys/devices/platform/smapi/BAT0/force_discharge

    (This can be used to control which battery is discharged when using an
     Ultrabay battery.)

Misc read-only battery status (see note about HDAPS below):

# cat /sys/devices/platform/smapi/BAT0/installed
# cat /sys/devices/platform/smapi/BAT0/state       # idle/charging/discharging
# cat /sys/devices/platform/smapi/BAT0/cycle_count
# cat /sys/devices/platform/smapi/BAT0/current_now # instantaneous current
# cat /sys/devices/platform/smapi/BAT0/current_avg # last minute average
# cat /sys/devices/platform/smapi/BAT0/power_now   # instantaneous power
# cat /sys/devices/platform/smapi/BAT0/power_avg   # last minute average
# cat /sys/devices/platform/smapi/BAT0/last_full_capacity
# cat /sys/devices/platform/smapi/BAT0/remaining_percent
# cat /sys/devices/platform/smapi/BAT0/remaining_running_time
# cat /sys/devices/platform/smapi/BAT0/remaining_charging_time
# cat /sys/devices/platform/smapi/BAT0/remaining_capacity
# cat /sys/devices/platform/smapi/BAT0/design_capacity
# cat /sys/devices/platform/smapi/BAT0/voltage
# cat /sys/devices/platform/smapi/BAT0/design_voltage
# cat /sys/devices/platform/smapi/BAT0/manufacturer
# cat /sys/devices/platform/smapi/BAT0/model
# cat /sys/devices/platform/smapi/BAT0/barcoding
# cat /sys/devices/platform/smapi/BAT0/chemistry
# cat /sys/devices/platform/smapi/BAT0/serial
# cat /sys/devices/platform/smapi/BAT0/manufacture_date
# cat /sys/devices/platform/smapi/BAT0/first_use_date
# cat /sys/devices/platform/smapi/BAT0/temperature # in milli-Celsius
# cat /sys/devices/platform/smapi/ac_connected


You can also get a hex dump of the raw status data, which contains additional data
now in the above (if you can figure it out). Some unused values are autodetected
and replaced by "--":

# cat /sys/devices/platform/smapi/BAT0/dump  

In all of the above, replace BAT0 with BAT1 to address the 2nd battery.


Controlling PCI bus power saving:

# cat /sys/devices/platform/smapi/enable_pci_power_saving_on_boot
# echo 1 > /sys/devices/platform/smapi/enable_pci_power_saving_on_boot # on
# echo 0 > /sys/devices/platform/smapi/enable_pci_power_saving_on_boot # off

This controls the "PCI bus power saving" option in the BIOS, and takes
effect at the next boot. On ThinkPad T43, this setting is stored in bit 0x40
of NVRAM byte 0x39, and turning it off increases idle power consumption 
by about 350mW. Out-of-the-box default is 1.


Raw SMAPI calls:

/sys/devices/platform/smapi/smapi_request
This performs raw SMAPI calls. It uses a bad interface that cannot handle
multiple simultaneous access. Don't touch it, it's for development only.
If you did touch it, you would so something like
# echo '211a 100 0 0' > /sys/devices/platform/smapi/smapi_request
# cat /sys/devices/platform/smapi/smapi_request
and notice that in the output "211a 34b b2 0 0 0 'OK'", the "4b" in the 2nd
parameter, converted to decimal is 75: the current charge stop threshold.


Model-specific status
---------------------

Works (at least partially) on the following ThinkPad model:
* A30
* G41
* R40, R50p, R51, R52
* T23, T40, T40p, T41, T41p, T42, T42p, T43, T43p, T60
* X24, X31, X32, X40, X41, X60
* Z60t, Z61m

Not all functions are available on all models; for detailed status, see:
  http://thinkwiki.org/wiki/tp_smapi

Please report success/failure by e-mail or on the Wiki. 
If you get a "not implemented" or "not supported" message, your laptop 
probably just can't do that (at least not via the SMAPI BIOS).
For negative reports, follow the bug reporting guidelines below.
If you send me the necessary technical data (i.e., SMAPI function 
interfaces), I will support additional models.


Conflict with HDAPS
-------------------

The extended battery status function conflicts with the "hdaps" kernel module
(they use the same IO ports). 

You can use HDAPS=1 (see Installation) to get a patched version of hdaps which
is compatible with tp_smapi.

Otherwise:

If you load "hdaps" first, tp_smapi will disable these functions (and log a
message in the kernel log). If you load "tp_smapi" first, "hdaps" will refuse
to load. To switch between the two, "rmmod" both and then load one you need.

Some of the battery status is also visible through ACPI (/proc/acpi/battery/).

The charging control files (*_charge_thresh, inhibit_charge_minutes and
force_discrage*) don't have this problem.


Bug reporting
-------------

Mail <multinymous@gmail.com>. Please include:
* Details about your model,
* Relevant "dmesg" output. Make sure thinkpad_ec and tp_smapi are loaded with
  the "debug=1" parameter (e.g., use "make load HDAPS=1 DEBUG=1").
* Output of "dmidecode | grep -C5 Product"
* Does the failed functionality works under Windows?


Files in this package
---------------------

README
  This file.
CHANGES
  Change log.
Makefile
  Makefile (see "Installation" above).
tp_smapi.c
  tp_smapi driver module (main code).
thinkpad_ec.*
  thinkpad_ec driver module (coordinates hardware access between tp_smapi and 
  hdaps)
hdaps.c
  Modified version of hdaps.c driver from mainline kernel, patched to use
  thinkpad_ec and several other improvements.
diff/dmi-decode-and-save-oem-string-information
  A patch from the kernel -mm series, needed for hardware detection. 
  If you don't have it, "make load" and "make install" will use a workaround
  kludge, and the result of "make patch" will include this patch.
diff/*  (excluding above)    
  Used by "make patch" to create a clean stand-alone patch.
include/
  Contains a symlink to make gcc happy in kernel builds.


Ideas for improvement
---------------------
(The best way to get these done is to send a patch.)

Don't create /sys files for unsupported functions, and don't access those
functions on suspend+resume (requires probing on module load or a huge 
white/blacklist).

Make inhibit_charge_minutes return the time left, not the time originally
set (as returned by the SMAPI BIOS). Requires remembering when 
inhibit_charge_minutes was set and comparing to current time.

Save and and restore inhibit_charge_minutes across suspend-to-disk, as done
for charge thresholds (requires the above time calculations too).


More about SMAPI
----------------

For hints about what may be possible via the SMAPI BIOS and how, see:

* IBM Technical Reference Manual for the ThinkPad 770
  (http://www-307.ibm.com/pc/support/site.wss/document.do?lndocid=PFAN-3TUQQD)
* Exported symbols in PWRMGRIF.DLL or TPPWRW32.DLL (e.g., use "objdump -x").
* drivers/char/mwave/smapi.c in the Linux kernel tree.*
* The "thinkpad" SMAPI module (http://tpctl.sourceforge.net).
* The SMAPI_* constants in tp_smapi.c (some of these are presently unused).

Note that in the above Technical Reference and in the "thinkpad" module,
SMAPI is invoked through a function call to some physical address. However,
the interface used by tp_smapi and the above mwave drive, and apparently 
required by newer ThinkPad, is different: you set the parameters up in the 
CPU's registers and write to ports 0xB2 (the APM control port) and 0x4F; this
triggers an SMI (System Management Interrupt), causing the CPU to enter
SMM (System Management Mode) and run the BIOS firmware; the results are 
returned in the CPU's registers. It is not clear what is the relation between 
the two variants of SMAPI, though the assignment of error codes seems to be 
similar.

In addition, the embedded controller on ThinkPad laptops has a non-standard 
interface at IO ports 0x1600-0x161F (mapped to LCP channel 3 of the H8S chip).
The interface provides various system management services (currently known: 
battery information and accelerometer readouts). For more information see the
thinkpad_ec modul and the H8S hardware documentation:
http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
