/* 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_USART_H
#define __CROS_EC_USART_H

/* STM32 USART driver for Chrome EC */

#include "common.h"
#include "consumer.h"
#include "producer.h"
#include "queue.h"

#include <stdint.h>

/*
 * Per-USART state stored in RAM.  This structure will be zero initialized by
 * BSS init.
 */
struct usart_state {
	/*
	 * Counter of bytes receieved and then dropped because of lack of space
	 * in the RX queue.
	 */
	uint32_t rx_dropped;

	/*
	 * Counter of the number of times an receive overrun condition is
	 * detected.  This will not usually be a count of the number of bytes
	 * that were lost due to overrun conditions.
	 */
	uint32_t rx_overrun;
};

struct usart_config;

struct usart_hw_ops {
	/*
	 * The generic USART initialization code calls this function to allow
	 * the variant HW specific code to perform any initialization.  This
	 * function is called before the USART is enabled, and should among
	 * other things enable the USARTs interrupt.
	 */
	void (*enable)(struct usart_config const *config);

	/*
	 * The generic USART shutdown code calls this function, allowing the
	 * variant specific code an opportunity to do any variant specific
	 * shutdown tasks.
	 */
	void (*disable)(struct usart_config const *config);
};

/*
 * The usart_rx/usart_tx structures contain functions pointers for the
 * interrupt handler and producer/consumer operations required to implement a
 * particular RX/TX strategy.
 *
 * These structures are defined by the various RX/TX implementations, and are
 * used to initialize the usart_config structure to configure the USART driver
 * for interrupt or DMA based transfer.
 */
struct usart_rx {
	void (*init)(struct usart_config const *config);
	void (*interrupt)(struct usart_config const *config);

	/*
	 * Print to the console any per-strategy diagnostic information, this
	 * is used by the usart_info command.  This can be NULL if there is
	 * nothing interesting to display.
	 */
	void (*info)(struct usart_config const *config);

	struct producer_ops producer_ops;
};

struct usart_tx {
	void (*init)(struct usart_config const *config);
	void (*interrupt)(struct usart_config const *config);

	/*
	 * Print to the console any per-strategy diagnostic information, this
	 * is used by the usart_info command.  This can be NULL if there is
	 * nothing interesting to display.
	 */
	void (*info)(struct usart_config const *config);

	struct consumer_ops consumer_ops;
};

extern struct usart_rx const usart_rx_interrupt;
extern struct usart_tx const usart_tx_interrupt;

/*
 * Per-USART hardware configuration stored in flash.  Instances of this
 * structure are provided by each variants driver, one per physical USART.
 */
struct usart_hw_config {
	int      index;
	intptr_t base;
	int      irq;

	uint32_t volatile *clock_register;
	uint32_t           clock_enable;

	struct usart_hw_ops const *ops;
};

/*
 * Compile time Per-USART configuration stored in flash.  Instances of this
 * structure are provided by the user of the USART.  This structure binds
 * together all information required to operate a USART.
 */
struct usart_config {
	/*
	 * Pointer to USART HW configuration.  There is one HW configuration
	 * per physical USART.
	 */
	struct usart_hw_config const *hw;

	struct usart_rx const *rx;
	struct usart_tx const *tx;

	/*
	 * Pointer to USART state structure.  The state structure maintains per
	 * USART information.
	 */
	struct usart_state volatile *state;

	/*
	 * Baud rate for USART.
	 */
	int baud;

	struct consumer consumer;
	struct producer producer;
};

/*
 * Convenience macro for defining USARTs and their associated state and buffers.
 * NAME is used to construct the names of the usart_state struct, and
 * usart_config struct, the latter is just called NAME.
 *
 * HW is the name of the usart_hw_config provided by the variant specific code.
 *
 * RX_QUEUE and TX_QUEUE are the names of the RX and TX queues that this USART
 * should write to and read from respectively.
 */
/*
 * The following assertions can not be made because they require access to
 * non-const fields, but should be kept in mind.
 *
 * BUILD_ASSERT(RX_QUEUE.unit_bytes == 1);
 * BUILD_ASSERT(TX_QUEUE.unit_bytes == 1);
 */
#define USART_CONFIG(HW, RX, TX, BAUD, RX_QUEUE, TX_QUEUE)	\
	((struct usart_config const) {				\
		.hw       = &HW,				\
		.rx       = &RX,				\
		.tx       = &TX,				\
		.state    = &((struct usart_state){}),		\
		.baud     = BAUD,				\
		.consumer = {					\
			.queue = &TX_QUEUE,			\
			.ops   = &TX.consumer_ops,		\
		},						\
		.producer = {					\
			.queue = &RX_QUEUE,			\
			.ops   = &RX.producer_ops,		\
		},						\
	})

/*
 * Initialize the given USART.  Once init is finished the USART streams are
 * available for operating on.
 */
void usart_init(struct usart_config const *config);

/*
 * Shutdown the given USART.
 */
void usart_shutdown(struct usart_config const *config);

/*
 * Handle a USART interrupt.  The per-variant USART code creates bindings
 * for the variants interrupts to call this generic USART interrupt handler
 * with the appropriate usart_config.
 */
void usart_interrupt(struct usart_config const *config);

/*
 * These are HW specific baud rate calculation and setting functions that the
 * peripheral variant code uses during initialization and clock frequency
 * change.  The baud rate divisor input frequency is passed in Hertz.
 */
void usart_set_baud_f0_l(struct usart_config const *config, int frequency_hz);
void usart_set_baud_f(struct usart_config const *config, int frequency_hz);

/*
 * Different families provide different ways of clearing the transmit complete
 * flag.  This function will be provided by the family specific implementation.
 */
void usart_clear_tc(struct usart_config const *config);

/*
 * Each family implementation provides the usart_get_configs function to access
 * a read only list of the configs that are currently enabled.
 */
struct usart_configs {
	/*
	 * The family's usart_config array, entries in the array for disabled
	 * configs will be NULL, enabled configs will point to the usart_config
	 * that was enabled.  And the following will be true:
	 *
	 * configs[i]->hw->index == i;
	 */
	struct usart_config const * const *configs;

	/*
	 * The total possible number of configs that this family supports.
	 * This will be the same as the number of usart_hw structs that the
	 * family provides in its family specific usart header.
	 */
	size_t count;
};

struct usart_configs usart_get_configs(void);

#endif /* __CROS_EC_USART_H */
