doc: documenting Platforms and Modules

Adding documentation for Platforms and Modules API.
diff --git a/doc/modules.rst b/doc/modules.rst
index 8dc27bd..8835663 100644
--- a/doc/modules.rst
+++ b/doc/modules.rst
@@ -1,3 +1,5 @@
+.. _modules:
+
 Modules
 =======
 
@@ -64,7 +66,7 @@
    :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
                ``1`` or ``"cpu1"``).
 
-.. method:: target.cpufreq.set_governor(cpu, governor, **kwargs)
+.. method:: target.cpufreq.set_governor(cpu, governor, \*\*kwargs)
 
    Sets the governor for the specified cpu.
 
@@ -83,7 +85,7 @@
    :param cpu: The cpu; could be a numeric or the corresponding string (e.g.
        ``1`` or ``"cpu1"``).
 
-.. method:: target.cpufreq.set_governor_tunables(cpu, **kwargs)
+.. method:: target.cpufreq.set_governor_tunables(cpu, \*\*kwargs)
 
    Set the tunables for the current governor on the specified CPU.
 
@@ -169,4 +171,192 @@
 API
 ---
 
-TODO
+Generic Module API Description
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Modules implement discrete, optional pieces of functionality ("optional" in the
+sense that the functionality may or may not be present on the target device, or
+that it may or may not be necessary for a particular application).
+
+Every module (ultimately) derives from :class:`Module` class.  A module must
+define the following class attributes:
+
+:name: A unique name for the module. This cannot clash with any of the existing
+       names and must be a valid Python identifier, but is otherwise free-from.
+:kind: This identifies the type of functionality a module implements, which in
+       turn determines the interface implemented by the module (all modules of
+       the same kind must expose a consistent interface). This must be a valid
+       Python identifier, but is otherwise free-form, though, where possible,
+       one should try to stick to an already-defined kind/interface, lest we end
+       up with a bunch of modules implementing similar functionality but
+       exposing slightly different interfaces.
+
+       .. note:: It is possible to omit ``kind`` when defining a module, in
+                 which case the module's ``name`` will be treated as its
+                 ``kind`` as well.
+
+:stage: This defines when the module will be installed into a :class:`Target`.
+        Currently, the following values are allowed:
+
+        :connected: The module is installed after a connection to the target has
+                    been established. This is the default.
+        :early: The module will be installed when a :class:`Target` is first
+                created. This should be used for modules that do not rely on a
+                live connection to the target.
+
+Additionally, a module must implement a static (or class) method :func:`probe`:
+
+.. method:: Module.probe(target)
+
+    This method takes a :class:`Target` instance and returns ``True`` if this
+    module is supported by that target, or ``False`` otherwise.
+
+    .. note:: If the moudule ``stage`` is ``"early"``, this method cannot assume
+              that a connection has been established (i.e. it can only access
+              attrubutes of the Target that do not rely on a connection).
+
+Installation and invocation
+***************************
+
+The default installation method will create an instance of a module (the
+:class:`Target` instance being the sole argument) and assign it to the target
+instance attribute named after the module's ``kind`` (or ``name`` if ``kind`` is
+``None``).
+
+It is possible to change the installation procedure for a module by overriding
+the default :func:`install` method. The method must have the following
+signature:
+
+.. method:: Module.install(cls, target, **kwargs)
+
+    Install the module into the target instance.
+
+
+Implementation and Usage Patterns
+*********************************
+
+There are two common ways to implement the above API, corresponding to the two
+common uses for modules:
+
+- If a module provides an interface to a particular set of functionality (e.g.
+  an OS subsystem), that  module would typically derive directly form
+  :class:`Module` and  would leave ``kind`` unassigned, so that it is accessed
+  by it name. Its instance's methods and attributes provide the interface for
+  interacting with its functionality. For examples of this type of module, see
+  the subsystem modules listed above (e.g. ``cpufreq``).
+- If a module provides a platform- or infrastructure-specific implementation of
+  a common function, the module would derive from one of :class:`Module`
+  subclasses that define the interface for that function. In that case the
+  module would be accessible via the common ``kind`` defined its super. The
+  module would typically implement :func:`__call__` and be invoked directly. For
+  examples of this type of module, see common function interface definitions
+  below.
+
+
+Common Function Interfaces
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section documents :class:`Module` classes defining interface for common
+functions. Classes derived from them provide concrete implementations for
+specific platforms.
+
+
+HardResetModule
+***************
+
+.. attribute:: HardResetModule.kind
+
+    "hard_reset"
+
+.. method:: HardResetModule.__call__()
+
+    Must be implemented by derived classes.
+    
+    Implements hard reset for a target devices. The equivalent of physically
+    power cycling the device.  This may be used by client code in situatians
+    where the target becomes unresponsive and/or a regular reboot is not
+    possible.
+
+
+BootModule
+**********
+
+.. attribute:: BootModule.kind
+
+    "hard_reset"
+
+.. method:: BootModule.__call__()
+
+    Must be implemented by derived classes.
+
+    Implements a boot proceedure. This takes the device from (hard or soft)
+    reset to a booted state where the device is ready to accept connections. For
+    a lot of commercial devices the process is entirely automatic, however some
+    devices (e.g. development boards), my require additional steps, such as
+    interactions with the bootloader, in order to boot into the OS.
+
+.. method:: Bootmodule.update(\*\*kwargs)
+
+    Update the boot settings. Some boot sequencies allow specifying settings
+    that will be utilized during boot (e.g. linux kernel boot command line). The
+    default implmentation will set each setting in ``kwargs`` as an attribute of
+    the boot module (or update the existing attribute).
+
+
+FlashModule
+***********
+
+.. attribute:: FlashModule.kind
+
+    "flash"
+
+.. method:: __call__(image_bundle=None, images=None, boot_config=None)
+
+    Must be implemented by derived classes.
+
+    Flash the target platform with the specified images.
+
+    :param image_bundle: A compressed bundle of image files with any associated
+                         metadata. The format of the bundle is specific to a
+                         particular implmentation.
+    :param images: A dict mapping image names/identifiers to the path on the
+                   host file system of the corresponding image file. If both
+                   this and ``image_bundle`` are specified, individual images
+                   will override those in the bundle.
+    :param boot_config: Some platforms require specifying boot arguments at the
+                        time of flashing the images, rather than during each
+                        reboot. For other platforms, this will be ignored.
+
+
+Module Registration
+~~~~~~~~~~~~~~~~~~~
+
+Modules are specified on :class:`Target` or :class:`Platform` creation by name.
+In order to find the class associated with the name, the module needs to be
+registered with ``devlib``. This is accomplished by passing the module class
+into :func:`register_module` method once it is defined.
+
+.. note:: If you're wiring a module to be included as part of ``devlib`` code
+          base, you can place the file with the module class under
+          ``devlib/modules/`` in the source and it will be automatically
+          enumarated. There is no need to explicitly register it in that case.
+
+The code snippet below illustrates an implementation of a hard reset function
+for an "Acme" device.
+
+.. code:: python
+
+    import os
+    from devlib import HardResetModule, register_module
+
+
+    class AcmeHardReset(HardResetModule):
+
+        name = 'acme_hard_reset'
+
+        def __call__(self):
+            # Assuming Acme board comes with a "reset-acme-board" utility 
+            os.system('reset-acme-board {}'.format(self.target.name))
+
+    register_module(AcmeHardReset)
+