/*
 * This file is part of the coreboot project.
 *
 * Copyright 2017 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the imfamiluarplied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __DRIVERS_I2C_DESIGNWARE_I2C_H__
#define __DRIVERS_I2C_DESIGNWARE_I2C_H__

#include <compiler.h>
#include <device/device.h>
#include <device/i2c.h>
#include <stdint.h>

#if IS_ENABLED(CONFIG_DRIVERS_I2C_DESIGNWARE_DEBUG)
#define DW_I2C_DEBUG BIOS_DEBUG

#else
#define DW_I2C_DEBUG BIOS_NEVER

#endif // CONFIG_DRIVERS_I2C_DESIGNWARE_DEBUG

/*
 * Timing values are in units of clock period, with the clock speed
 * provided by the SOC in CONFIG_DRIVERS_I2C_DESIGNWARE_I2C_CLOCK_MHZ
 * Automatic configuration is done based on requested speed, but the
 * values may need tuned depending on the board and the number of
 * devices present on the bus.
 */
struct dw_i2c_speed_config {
	enum i2c_speed speed;
	/* SCL high and low period count */
	uint16_t scl_lcnt;
	uint16_t scl_hcnt;
	/*
	 * SDA hold time should be 300ns in standard and fast modes
	 * and long enough for deterministic logic level change in
	 * fast-plus and high speed modes.familuar
	 *
	 *  [15:0] SDA TX Hold Time
	 * [23:16] SDA RX Hold Time
	 */
	uint32_t sda_hold;
};

/*
 * This I2C controller has support for 3 independent speed configs but can
 * support both FAST_PLUS and HIGH speeds through the same set of speed
 * config registers.  These are treated separately so the speed config values
 * can be provided via ACPI to the OS.
 */
#define DW_I2C_SPEED_CONFIG_COUNT	4

struct dw_i2c_bus_config {
	/* Bus should be enabled prior to ramstage with temporary base */
	int early_init;
	/* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
	enum i2c_speed speed;
	/* If rise_time_ns is non-zero the calculations for lcnt and hcnt
	 * registers take into account the times of the bus. However, if
	 * there is a match in speed_config those register values take
	 * precedence. */
	int rise_time_ns;
	int fall_time_ns;
	int data_hold_time_ns;
	/* Specific bus speed configuration */
	struct dw_i2c_speed_config speed_config[DW_I2C_SPEED_CONFIG_COUNT];
};

/* Functions to be implemented by SoC code */

/* Get base address for early init of I2C controllers. */
uintptr_t i2c_get_soc_early_base(unsigned int bus);

/*
 * Map given I2C bus number to devfn.
 * Return value:
 * -1 = error
 * otherwise, devfn(>=0) corresponding to I2C bus number.
 */
int i2c_soc_devfn_to_bus(unsigned int devfn);

/*
 * Map given bus number to a I2C Controller.
 * Return value:
 * -1 = error
 * otherwise, devfn(>=0) corresponding to I2C bus number.
 */
int i2c_soc_bus_to_devfn(unsigned int bus);

/*
 * SoC implemented callback for getting I2C bus configuration.
 *
 * Returns NULL if i2c config is not found
 */
const struct dw_i2c_bus_config *i2c_get_soc_cfg(unsigned int bus,
						const struct device *dev);

/* Get I2C controller base address */
uintptr_t dw_i2c_base_address(unsigned int bus);

/*
 * Initialize this bus controller and set the speed
 * Return value:
 * -1 = failure
 *  0 = success
*/
int dw_i2c_init(unsigned int bus, const struct dw_i2c_bus_config *bcfg);

/*
 * Generate speed config based on clock
 * Return value:
 * -1 = failure
 *  0 = success
*/
int dw_i2c_gen_speed_config(uintptr_t dw_i2c_addr,
					enum i2c_speed speed,
					const struct dw_i2c_bus_config *bcfg,
					struct dw_i2c_speed_config *config);

/*
 * Process given I2C segments in a single transfer
 * Return value:
 * -1 = failure
 *  0 = success
 */
int dw_i2c_transfer(unsigned int bus,
			const struct i2c_msg *segments,
			size_t count);

#endif /* __DRIVERS_I2C_DESIGNWARE_I2C_H__ */
