diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md
new file mode 100644
index 0000000000..67043f4ee8
--- /dev/null
+++ b/docs/porting/target/spi.md
@@ -0,0 +1,130 @@
+
Serial Peripheral Interface (SPI)
+
+The **Serial Peripheral Interface** allows you to send or receive a data stream over a synchronous serial interface made of 3 to 4 lines.
+
+- MISO: Master in, slave out.
+- MOSI: Master out, slave in.
+- MCLK: Clock.
+- SS: Slave select.
+
+A typical use case of this interface is with SDCard, memory blocks and DACs or ADCs.
+
+This highly configurable interface has elements you can adjust:
+
+- Frame length.
+- Clocks polarity and phase.
+
+**Warning:** We are introducing the SPI API in an upcoming release of Mbed OS. This page documents code that exists on a feature branch of Mbed OS. You can find details on how it may affect you in the [implementing the SPI API](#implementing-the-spi-api) section.
+
+### Assumptions
+
+#### Defined behaviors
+
+- `spi_get_module()` returns the `SPIName` unique identifier to the peripheral associated to this SPI channel.
+- `spi_get_capabilities()` fills the given `spi_capabilities_t` instance.
+- `spi_get_capabilities()` should consider the `ssel` pin when evaluating the `support_slave_mode` capability.
+- If the given `ssel` pin cannot be managed by hardware in slave mode, `support_slave_mode` should be false.
+- At least a symbol width of 8 bit must be supported.
+- The supported frequency range must include the range 0.2-2 MHz.
+- The shortest part of the duty cycle must not be shorter than 50% of the expected period.
+- `spi_init()` initializes the pins leaving the configuration registers unchanged.
+- `spi_init()` if `is_slave` is false:
+ - If `ssel` is `NC`, the HAL implementation ignores this pin.
+ - If `ssel` is not `NC`, then the HAL implementation owns the pin and its management.
+- When managed by the HAL implementation, `ssel` is always considered active low.
+- When the hardware supports the half-duplex (3-wire) mode, if `miso` (exclusive) or `mosi` is missing in any function that expects pins, the bus is assumed to be half-duplex.
+- `spi_free()` resets the pins to their default state.
+- `spi_free()` disables the peripheral clock.
+- `spi_format()` sets:
+ - The number of bits per symbol.
+ - The mode:
+ .0 Clock idle state is *low*, data are sampled when the clock becomes *active* (polarity = 0, phase = 0).
+ .1 Clock idle state is *low*, data are sampled when the clock becomes *inactive* (polarity = 0, phase = 1).
+ .2 Clock idle state is *high*, data are sampled when the clock becomes *active* (polarity = 1, phase = 0).
+ .3 Clock idle state is *high*, data are sampled when the clock becomes *inactive* (polarity = 1, phase = 1).
+ - The bit ordering (lsb/msb first).
+- `spi_format()` updates the configuration of the peripheral except the baud rate generator.
+- `spi_frequency()` sets the frequency to use during the transfer.
+- `spi_frequency()` returns the actual frequency that is used.
+- `spi_frequency()` updates the baud rate generator leaving other configurations unchanged.
+- `spi_init()`, `spi_frequency()` and `spi_format()` must be called at least once each before initiating any transfer.
+- `spi_transfer()`:
+ - Writes `tx_len` symbols to the bus.
+ - Reads `rx_len` symbols from the bus.
+ - If `rx` is NULL, then inputs are discarded.
+ - If `tx` is NULL, then `fill_symbol` is used instead.
+ - Returns the number of symbol clocked on the bus during this transfer.
+ - Expects symbols types to be the closest stdint type bigger or equal to its size following the platform's endianness. For example:
+ - 7bits => uint8_t.
+ - 15bits => uint16_t.
+ - 16bits => uint16_t.
+ - 17bits => uint32_t.
+ - In full-duplex mode:
+ - If `rx_len` > `tx_len` then it sends `(rx_len-tx_len)` additional `fill_symbol` to the bus.
+ - In half-duplex mode:
+ - As master, `spi_transfer()` sends `tx_len` symbols and then reads `rx_len` symbols.
+ - As slave, `spi_transfer()` receives `rx_len` symbols and then sends `tx_len` symbols.
+- `spi_transter_async()` schedules a transfer to be process the same way `spi_transfer()` would have but asynchronously.
+- `spi_transter_async()` returns immediately with a boolean indicating whether the transfer was successfully scheduled or not.
+- The callback given to `spi_transfer_async()` is invoked when the transfer completes (with a success or an error).
+- `spi_transfer_async()` saves the handler and the `ctx` pointer.
+- The `ctx` is passed to the callback on transfer completion.
+- Unless the transfer is aborted, the callback is invoked on completion. The completion may be when all symbols have been transmitted
+ or when, in slave mode, the master deasserts the chip select.
+- The `spi_transfer_async()` function may use the `DMAUsage` hint to select the appropriate asynchronous algorithm.
+- The `spi_async_event_t` must be filled with the number of symbols clocked on the bus during this transfer and a boolean value indicated if an error has occurred.
+- `spi_transfer_async_abort()` aborts an ongoing asynchronous transfer.
+
+#### Undefined behaviors
+
+- Calling `spi_init()` multiple times on the same `spi_t` without `spi_free()`'ing it first.
+- Calling any method other than `spi_init()` on an uninitialized or freed `spi_t`.
+- Passing both `miso` and `mosi` as `NC` to `spi_get_module` or `spi_init`.
+- Passing `miso` or `mosi` as `NC` on target that does not support half-duplex mode.
+- Passing `mclk` as `NC` to `spi_get_module` or `spi_init`.
+- Passing an invalid pointer as `cap` to `spi_get_capabilities`.
+- Passing pins that cannot be on the same peripheral.
+- Passing an invalid pointer as `obj` to any method.
+- Giving an `ssel` pin to `spi_init()` when using in master mode.
+- SS must be managed by hardware in slave mode and must **NOT** be managed by hardware in master mode.
+- Setting a frequency outside of the range given by `spi_get_capabilities()`.
+- Setting a frequency in slave mode.
+- Setting `bits` in `spi_format` to a value out of the range given by `spi_get_capabilities()`.
+- Passing an invalid pointer as `fill_symbol` to `spi_transfer` and `spi_transfer_async` while they would be required by the transfer (`rx_len != tx_len` or `tx==NULL`).
+- Passing an invalid pointer as `handler` to `spi_transfer_async`.
+- Calling `spi_transfer_async_abort()` while no asynchronous transfer is being processed (no transfer or a synchronous transfer).
+- In half-duplex mode, any mechanism (if any is present) to detect or prevent collision is implementation defined.
+
+#### Other requirements
+
+A target must also define these elements:
+
+- `#define SPI_COUNT (xxxxxU)`.
+- The number of SPI peripherals available on the device. A good place for that macro is `PeripheralNames.h` next to the `SPIName` enumeration.
+
+**Note:** You can find more details about the design choices in the [SPI design document](https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-spi/docs/design-documents/hal/0000-spi-overhaul.md).
+
+### Dependencies
+
+Hardware SPI capabilities.
+
+### Implementing the SPI API
+
+You can find the API and specification for the SPI API in the following class reference:
+
+[](http://os.mbed.com/docs/development/feature-hal-spec-spi-doxy/classmbed_1_1_s_p_i.html)
+
+To enable SPI support in Mbed OS, add the `SPI` label in the `device_has` option of the target's section in the `targets.json` file.
+You can also add the `SPI_ASYNCH` label in the `device_has` option to enable the asynchronous API.
+
+### Testing
+
+The Mbed OS HAL provides a set of conformance tests for SPI. You can use these tests to validate the correctness of your implementation. To run the SPI HAL tests, use the following command:
+
+```
+mbed test -t -m -n "tests-mbed_hal-spi*"
+```
+
+You can read more about the test cases:
+
+[](http://os.mbed.com/docs/development/feature-hal-spec-spi-doxy/group__hal__spi__tests.html)