/******************************************************************************
  * File Name          : si5351.h
  * Description        : STM32 library/driver for the Si5351 clock chip
  *                      from Skyworks Solutions, Inc. (former SiLabs)
 ******************************************************************************
  * @author: Thomas Kuschel KW4NZ, created 2022-05-11
  *
  * originally written by Petr Polasek, created Feb 16, 2018
 ******************************************************************************
  * DO NOT EDIT THIS FILE FOR CONFIGURATION, USE THE FOLLOWING PROCEDURE:
  *
  * Inside your main.c program or within your STM32 code:
  * Include this header to the the main.c: #include "si5351.h"
  * You've to initialize the I2C functionality first (e.g. with STM32CubeIDE)
  * Afterwards, when there is a handle like  "I2C_HandleTypeDef hi2c1;",
  * you simply initialize this si5351 library in your main.c ,
  * just after the MX_I2C1_Init();
  * so between the USER CODE like using the given i2c handle "hi2c1" with default values:
  *
  * /\* USER CODE BEGIN 2 *\/
  *
  *  si5351_inst_t si5351_inst;
  *  si5351_initialize(&hi2c1);
  *
  * /\* USER CODE END 2 *\/
  *
  * The 7-bit device (slave) address of the Si5351 consist of a 6-bit fixed
  * address plus a user selectable LSB bit as shown in Figure 6 of the datasheet.
  * The LSB bit is selectable as 0 or 1 using the optional A0 pin which is useful
  * for applications that require more than one Si5351 on a single I2C bus.
  * Only the Si5351A 20-QFN and Si5351A 16-QFN have the A0 LSB pin option.
  * If a part does not have the A0 pin, the default address is 0x60 with
  * the A0 bit set to 0.
  *
  * So additionally you may drive more then one Si5351 at the same or
  * another I2C bus when calling the init function with the given
  * I2C bus address (default: 0x60)
  * ( - internally this I2C address is shifted to the left
  *     for the proper usage of the I2C HAL driver i.e. it becomes 0xC0 )
  *
  * Example:
  *  /\* Define handlers for the sum of three SI5351 clock generators: *\/
  *  si5351_HandleTypeDef hsi5351[3];
  *
  *  /\* 1st SI5351 chip and with an A0 = 0: *\/
  *  hsi5351[0] = si5351_init(&hi2c1, 0x60, 25000000);
  *  /\* 2nd SI5351 chip on the same I2C bus "hi2c1" but address line A0 = 1 *\/
  *  hsi5351[1] = si5351_init(&hi2c1, 0x61, 27000000);
  *  /\* 3rd SI5351 chip on another IC2 bus with handle "hi2c2" *\/
  *  hsi5351[2] = si5351_init(&hi2c2, 0x60, 25000000);
  *
  * PROs:
  * The library is preemptive and can be used within an operating system.
  * All structures and used variables are dynamically allocated.
  * CONs:
  * Not fully tested.
  * Tested with FreeRTOS and with 2 I2C bus systems.
  *
  * CHANGES:
  * - Removed several defines, enums, etc. from the header file, b/c we do not
  *   want to export them to other programs
 ******************************************************************************/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SI5351_H__
#define __SI5351_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
/* #include <errno.h>  could also be included */
/* Private includes ----------------------------------------------------------*/

/* Exported types ------------------------------------------------------------*/
/*!< Si5351 instance typedef -- handle as pointer */
typedef struct __SI5351_HandleTypeDef *si5351_inst_t;

/* Exported constants --------------------------------------------------------*/
/** @enum errno_t Error Number Constants,  @TODO you can also include <errno.h>
 */
#if !defined _SYS_ERRNO_H_ && !defined __ERRNO_H__ && !defined __AT1_ERROR_NUMBERS__
typedef enum {
	EPERM	=  1,	/*!< Operation not permitted	*/
	EIO		=  5,	/*!< I/O error	*/
	ENOMEM	= 12,	/*!< Out of memory		*/
	EFAULT	= 14,	/*!< Bad address		*/
	EBUSY 	= 16,	/*!< Device or resource busy	*/
	ENODEV	= 19,	/*!< No such device 	*/
	EINVAL	= 22,	/*!< Invalid argument	*/
	EADDRINUSE = 98,/*!< Address already in use	*/
	ETIMEDOUT = 116	/*!< Connection timed out	*/
} si5351_errno_t;
#endif

typedef enum {
	SI5351_PLLA = 0,
	SI5351_PLLB
}si5351_pll_t;

/* Exported variables --------------------------------------------------------*/

/* Exported macros -----------------------------------------------------------*/
#define __SI5351__             1
#define __SI5351_MINOR__       2
#define __SI5351_PATCHLEVEL__  0

#define SI5351_VERSION (__SI5351__ * 10000 \
		+ __SI5351_MINOR__ * 100 \
		+ __SI5351_PATCHLEVEL__)

#ifndef SI5351_DEFAULTS
#define SI5351_DEFAULTS  1
#define SI5351_I2C_ADDR_DEFAULT  0x60
#define SI5351_XTAL_DEFAULT      25000000u  /* default xtal frequency in [Hz] */
#define SI5351_NUMBER_OF_OUTPUTS 8
#endif

/* Exported functions --------------------------------------------------------*/
#if SI5351_DEFAULTS
si5351_inst_t si5351_initialize(void * i2c_handle);
int si5351_deinitialize(void);
#endif
si5351_inst_t si5351_init(void * i2c_handle, uint8_t i2c_address, uint32_t xtal_frequency);
int si5351_deinit(si5351_inst_t si5351_handle);
int si5351_i2c_ready(si5351_inst_t inst);
int si5351_enable_output(si5351_inst_t inst, uint8_t clk);
int si5351_disable_output(si5351_inst_t inst, uint8_t clk);
int si5351_set_clk0(si5351_inst_t inst, uint32_t frequency);
int si5351_set_clk(si5351_inst_t inst, uint8_t clk, uint32_t frequency, si5351_pll_t pll);

char * si5351_read_debug_msg(si5351_inst_t inst);
char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, uint8_t regaddr);

/* some functions for getting information */
int si5351_get_instance(si5351_inst_t *inst);
int si5351_get_i2c_address(si5351_inst_t inst);
void* si5351_get_i2c_handle(si5351_inst_t inst);

/* under development */
int si5351_set_clk_phase(si5351_inst_t inst, uint8_t clk, uint32_t frequency, double phase, si5351_pll_t pll);
int si5351_set_phase(si5351_inst_t inst, uint8_t clk, uint8_t phase);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __SI5351_H__ */
