/* SPDX-License-Identifier: GPL-2.0-only */

#include <console/i2c_smbus.h>
#include <device/i2c.h>
#include <device/smbus_host.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include "sc16is7xx_init.h"

/*
 * Datasheet - SC16IS740/750/760, Rev. 7 - 9 June 2011
 * https://web.archive.org/web/20210612105830/https://www.nxp.com/docs/en/data-sheet/SC16IS740_750_760.pdf
 */

// Bits [6:3] of the subaddress is to address device internal registers
#define INTERNAL_REG_SUB_ADDR_SHIFT	3

#define REG_THR 0x00    // Transmit Holding Register
#define REG_LCR 0x03    // Line Control Register

// Special Register Set is accessible only when LCR[7] is logic 1
#define REG_DLL 0x00    // divisor latch LSB
#define REG_DLH 0x01    // divisor latch MSB

#define LCR_WORD_LEN_BIT_0	BIT(0)
#define LCR_WORD_LEN_BIT_1	BIT(1)
#define LCR_STOP_BIT		BIT(2)
#define LCR_PARITY_BIT_0	BIT(3)
#define LCR_PARITY_BIT_1	BIT(4)
#define LCR_PARITY_BIT_2	BIT(5)
#define LCR_BREAK_CTL_BIT	BIT(6)
#define LCR_SPEC_REG_SET_EN	BIT(7)

#define UART_8_N_1	(LCR_WORD_LEN_BIT_0 | LCR_WORD_LEN_BIT_1)

/*
 *	UART configuration: 8 bit word length, No parity, 1 stop bit (8-N-1)
 *	Divisor value set here is calculated for 115200 baud rate
 *	in 14.7MHz clock input to chip.
 */

#define BAUD_115200_DLL	0x08
#define BAUD_115200_DLH	0x00

void sc16is7xx_write_byte(uint8_t reg, unsigned char c)
{
	do_smbus_write_byte(CONFIG_FIXED_SMBUS_IO_BASE,
			CONFIG_CONSOLE_I2C_SMBUS_SLAVE_ADDRESS, reg, c);
}

void sc16is7xx_init(void)
{
	// Configure 8-N-1 and enable special register set
	sc16is7xx_write_byte(REG_LCR << INTERNAL_REG_SUB_ADDR_SHIFT,
				(UART_8_N_1 | LCR_SPEC_REG_SET_EN));

	sc16is7xx_write_byte(REG_DLL << INTERNAL_REG_SUB_ADDR_SHIFT, BAUD_115200_DLL);
	sc16is7xx_write_byte(REG_DLH << INTERNAL_REG_SUB_ADDR_SHIFT, BAUD_115200_DLH);

	// Disable special register set
	sc16is7xx_write_byte(REG_LCR << INTERNAL_REG_SUB_ADDR_SHIFT,
				(UART_8_N_1 & ~LCR_SPEC_REG_SET_EN));
}