|  | /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #ifndef __CROS_EC_USB_SPI_H | 
|  | #define __CROS_EC_USB_SPI_H | 
|  |  | 
|  | /* STM32 USB SPI driver for Chrome EC */ | 
|  |  | 
|  | #include "compile_time_macros.h" | 
|  | #include "hooks.h" | 
|  | #include "usb_descriptor.h" | 
|  | #include "usb_hw.h" | 
|  |  | 
|  | /* | 
|  | * Command: | 
|  | *     +------------------+-----------------+------------------------+ | 
|  | *     | write count : 1B | read count : 1B | write payload : <= 62B | | 
|  | *     +------------------+-----------------+------------------------+ | 
|  | * | 
|  | *     write count:   1 byte, zero based count of bytes to write | 
|  | * | 
|  | *     read count:    1 byte, zero based count of bytes to read | 
|  | * | 
|  | *     write payload: up to 62 bytes of data to write, length must match | 
|  | *                    write count | 
|  | * | 
|  | * Response: | 
|  | *     +-------------+-----------------------+ | 
|  | *     | status : 2B | read payload : <= 62B | | 
|  | *     +-------------+-----------------------+ | 
|  | * | 
|  | *     status: 2 byte status | 
|  | *         0x0000: Success | 
|  | *         0x0001: SPI timeout | 
|  | *         0x0002: Busy, try again | 
|  | *             This can happen if someone else has acquired the shared memory | 
|  | *             buffer that the SPI driver uses as /dev/null | 
|  | *         0x0003: Write count invalid (> 62 bytes, or mismatch with payload) | 
|  | *         0x0004: Read count invalid (> 62 bytes) | 
|  | *         0x0005: The SPI bridge is disabled. | 
|  | *         0x8000: Unknown error mask | 
|  | *             The bottom 15 bits will contain the bottom 15 bits from the EC | 
|  | *             error code. | 
|  | * | 
|  | *     read payload: up to 62 bytes of data read from SPI, length will match | 
|  | *                   requested read count | 
|  | */ | 
|  |  | 
|  | enum usb_spi_error { | 
|  | USB_SPI_SUCCESS             = 0x0000, | 
|  | USB_SPI_TIMEOUT             = 0x0001, | 
|  | USB_SPI_BUSY                = 0x0002, | 
|  | USB_SPI_WRITE_COUNT_INVALID = 0x0003, | 
|  | USB_SPI_READ_COUNT_INVALID  = 0x0004, | 
|  | USB_SPI_DISABLED            = 0x0005, | 
|  | USB_SPI_UNKNOWN_ERROR       = 0x8000, | 
|  | }; | 
|  |  | 
|  | enum usb_spi_request { | 
|  | USB_SPI_REQ_ENABLE  = 0x0000, | 
|  | USB_SPI_REQ_DISABLE = 0x0001, | 
|  | }; | 
|  |  | 
|  | #define USB_SPI_MAX_WRITE_COUNT 62 | 
|  | #define USB_SPI_MAX_READ_COUNT  62 | 
|  |  | 
|  | BUILD_ASSERT(USB_MAX_PACKET_SIZE == (1 + 1 + USB_SPI_MAX_WRITE_COUNT)); | 
|  | BUILD_ASSERT(USB_MAX_PACKET_SIZE == (2 + USB_SPI_MAX_READ_COUNT)); | 
|  |  | 
|  | struct usb_spi_state { | 
|  | /* | 
|  | * The SPI bridge must be enabled both locally and by the host to allow | 
|  | * access to the SPI device.  The enabled_host flag is set and cleared | 
|  | * by sending USB_SPI_REQ_ENABLE and USB_SPI_REQ_DISABLE to the device | 
|  | * control endpoint.  The enabled_device flag is set by calling | 
|  | * usb_spi_enable. | 
|  | */ | 
|  | int enabled_host; | 
|  | int enabled_device; | 
|  |  | 
|  | /* | 
|  | * The current enabled state.  This is only updated in the deferred | 
|  | * callback.  Whenever either of the host or device specific enable | 
|  | * flags is changed the deferred callback is queued, and it will check | 
|  | * their combined state against this flag.  If the combined state is | 
|  | * different, then one of usb_spi_board_enable or usb_spi_board_disable | 
|  | * is called and this flag is updated.  This ensures that the board | 
|  | * specific state update routines are only called from the deferred | 
|  | * callback. | 
|  | */ | 
|  | int enabled; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Compile time Per-USB gpio configuration stored in flash.  Instances of this | 
|  | * structure are provided by the user of the USB gpio.  This structure binds | 
|  | * together all information required to operate a USB gpio. | 
|  | */ | 
|  | struct usb_spi_config { | 
|  | /* | 
|  | * In RAM state of the USB SPI bridge. | 
|  | */ | 
|  | struct usb_spi_state *state; | 
|  |  | 
|  | /* | 
|  | * Interface and endpoint indicies. | 
|  | */ | 
|  | int interface; | 
|  | int endpoint; | 
|  |  | 
|  | /* | 
|  | * Deferred function to call to handle SPI request. | 
|  | */ | 
|  | const struct deferred_data *deferred; | 
|  |  | 
|  | /* | 
|  | * Pointers to USB packet RAM and bounce buffer. | 
|  | */ | 
|  | uint16_t *buffer; | 
|  | usb_uint *rx_ram; | 
|  | usb_uint *tx_ram; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Convenience macro for defining a USB SPI bridge driver. | 
|  | * | 
|  | * NAME is used to construct the names of the trampoline functions and the | 
|  | * usb_spi_config struct, the latter is just called NAME. | 
|  | * | 
|  | * INTERFACE is the index of the USB interface to associate with this | 
|  | * SPI driver. | 
|  | * | 
|  | * ENDPOINT is the index of the USB bulk endpoint used for receiving and | 
|  | * transmitting bytes. | 
|  | */ | 
|  | #define USB_SPI_CONFIG(NAME,						\ | 
|  | INTERFACE,					\ | 
|  | ENDPOINT)					\ | 
|  | static uint16_t CONCAT2(NAME, _buffer_)[USB_MAX_PACKET_SIZE / 2]; \ | 
|  | static usb_uint CONCAT2(NAME, _ep_rx_buffer_)[USB_MAX_PACKET_SIZE / 2] __usb_ram; \ | 
|  | static usb_uint CONCAT2(NAME, _ep_tx_buffer_)[USB_MAX_PACKET_SIZE / 2] __usb_ram; \ | 
|  | static void CONCAT2(NAME, _deferred_)(void);			\ | 
|  | DECLARE_DEFERRED(CONCAT2(NAME, _deferred_));			\ | 
|  | struct usb_spi_state CONCAT2(NAME, _state_) = {			\ | 
|  | .enabled_host   = 0,					\ | 
|  | .enabled_device = 0,					\ | 
|  | .enabled        = 0,					\ | 
|  | };								\ | 
|  | struct usb_spi_config const NAME = {				\ | 
|  | .state     = &CONCAT2(NAME, _state_),			\ | 
|  | .interface = INTERFACE,					\ | 
|  | .endpoint  = ENDPOINT,					\ | 
|  | .deferred  = &CONCAT2(NAME, _deferred__data),		\ | 
|  | .buffer    = CONCAT2(NAME, _buffer_),			\ | 
|  | .rx_ram    = CONCAT2(NAME, _ep_rx_buffer_),		\ | 
|  | .tx_ram    = CONCAT2(NAME, _ep_tx_buffer_),		\ | 
|  | };								\ | 
|  | const struct usb_interface_descriptor				\ | 
|  | USB_IFACE_DESC(INTERFACE) = {					\ | 
|  | .bLength            = USB_DT_INTERFACE_SIZE,		\ | 
|  | .bDescriptorType    = USB_DT_INTERFACE,			\ | 
|  | .bInterfaceNumber   = INTERFACE,			\ | 
|  | .bAlternateSetting  = 0,				\ | 
|  | .bNumEndpoints      = 2,				\ | 
|  | .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,		\ | 
|  | .bInterfaceSubClass = USB_SUBCLASS_GOOGLE_SPI,		\ | 
|  | .bInterfaceProtocol = USB_PROTOCOL_GOOGLE_SPI,		\ | 
|  | .iInterface         = 0,				\ | 
|  | };								\ | 
|  | const struct usb_endpoint_descriptor				\ | 
|  | USB_EP_DESC(INTERFACE, 0) = {					\ | 
|  | .bLength          = USB_DT_ENDPOINT_SIZE,		\ | 
|  | .bDescriptorType  = USB_DT_ENDPOINT,			\ | 
|  | .bEndpointAddress = 0x80 | ENDPOINT,			\ | 
|  | .bmAttributes     = 0x02 /* Bulk IN */,			\ | 
|  | .wMaxPacketSize   = USB_MAX_PACKET_SIZE,		\ | 
|  | .bInterval        = 10,					\ | 
|  | };								\ | 
|  | const struct usb_endpoint_descriptor				\ | 
|  | USB_EP_DESC(INTERFACE, 1) = {					\ | 
|  | .bLength          = USB_DT_ENDPOINT_SIZE,		\ | 
|  | .bDescriptorType  = USB_DT_ENDPOINT,			\ | 
|  | .bEndpointAddress = ENDPOINT,				\ | 
|  | .bmAttributes     = 0x02 /* Bulk OUT */,		\ | 
|  | .wMaxPacketSize   = USB_MAX_PACKET_SIZE,		\ | 
|  | .bInterval        = 0,					\ | 
|  | };								\ | 
|  | static void CONCAT2(NAME, _ep_tx_)   (void) { usb_spi_tx   (&NAME); } \ | 
|  | static void CONCAT2(NAME, _ep_rx_)   (void) { usb_spi_rx   (&NAME); } \ | 
|  | static void CONCAT2(NAME, _ep_event_)(enum usb_ep_event evt)	\ | 
|  | {								\ | 
|  | usb_spi_event(&NAME, evt);				\ | 
|  | }								\ | 
|  | USB_DECLARE_EP(ENDPOINT,					\ | 
|  | CONCAT2(NAME, _ep_tx_),				\ | 
|  | CONCAT2(NAME, _ep_rx_),				\ | 
|  | CONCAT2(NAME, _ep_event_));			\ | 
|  | static int CONCAT2(NAME, _interface_)(usb_uint *rx_buf,		\ | 
|  | usb_uint *tx_buf)		\ | 
|  | { return usb_spi_interface(&NAME, rx_buf, tx_buf); }		\ | 
|  | USB_DECLARE_IFACE(INTERFACE,					\ | 
|  | CONCAT2(NAME, _interface_));			\ | 
|  | static void CONCAT2(NAME, _deferred_)(void)			\ | 
|  | { usb_spi_deferred(&NAME); } | 
|  |  | 
|  | /* | 
|  | * Handle SPI request in a deferred callback. | 
|  | */ | 
|  | void usb_spi_deferred(struct usb_spi_config const *config); | 
|  |  | 
|  | /* | 
|  | * Set the enable state for the USB-SPI bridge. | 
|  | * | 
|  | * The bridge must be enabled from both the host and device side | 
|  | * before the SPI bus is usable.  This allows the bridge to be | 
|  | * available for host tools to use without forcing the device to | 
|  | * disconnect or disable whatever else might be using the SPI bus. | 
|  | */ | 
|  | void usb_spi_enable(struct usb_spi_config const *config, int enabled); | 
|  |  | 
|  | /* | 
|  | * These functions are used by the trampoline functions defined above to | 
|  | * connect USB endpoint events with the generic USB GPIO driver. | 
|  | */ | 
|  | void usb_spi_tx(struct usb_spi_config const *config); | 
|  | void usb_spi_rx(struct usb_spi_config const *config); | 
|  | void usb_spi_event(struct usb_spi_config const *config, enum usb_ep_event evt); | 
|  | int  usb_spi_interface(struct usb_spi_config const *config, | 
|  | usb_uint *rx_buf, | 
|  | usb_uint *tx_buf); | 
|  |  | 
|  | /* | 
|  | * These functions should be implemented by the board to provide any board | 
|  | * specific operations required to enable or disable access to the SPI device. | 
|  | */ | 
|  | void usb_spi_board_enable(struct usb_spi_config const *config); | 
|  | void usb_spi_board_disable(struct usb_spi_config const *config); | 
|  |  | 
|  | #endif /* __CROS_EC_USB_SPI_H */ |