/*
 * Copyright (C) 2015 Jason Milldrum <milldrum@gmail.com>
 * Many defines derived from clk-si5351.h in the Linux kernel.
 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 * Rabeeh Khoury <rabeeh@solid-run.com>
 *
 * 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __SI5351_H__
#define __SI5351_H__

#include "main.h"

//definitions
#define SI5351_BUS_BASE_ADDR				(0x60 << 1)
#define SI5351_XTAL_FREQ					27000000	//### With 25000000 waves jitter too much.
#define SI5351_PLL_FIXED					900000000ULL

#define SI5351_MULTISYNTH_MIN_FREQ			1000000
#define SI5351_MULTISYNTH_DIVBY4_FREQ		150000000

#define SI5351_CLK0_CTRL					16
#define SI5351_CLK_INTEGER_MODE				(1<<6)
#define SI5351_CLK_DRIVE_STRENGTH_2MA		(0<<0)
#define SI5351_CLK_DRIVE_STRENGTH_4MA		(1<<0)
#define SI5351_CLK_DRIVE_STRENGTH_6MA		(2<<0)
#define SI5351_CLK_DRIVE_STRENGTH_8MA		(3<<0)

#define SI5351_PLLA_PARAMETERS				26
#define SI5351_PLLB_PARAMETERS				34
#define SI5351_CLK0_PARAMETERS				42
#define SI5351_CLK1_PARAMETERS				50
#define SI5351_CLK2_PARAMETERS				58
#define SI5351_OUTPUT_CLK_DIV_SHIFT			4
#define SI5351_OUTPUT_CLK_DIV_1				0
#define SI5351_OUTPUT_CLK_DIVBY4			(3<<2)

#define SI5351_PLL_RESET					177
#define  SI5351_PLL_RESET_B					(1<<7)
#define  SI5351_PLL_RESET_A					(1<<5)

//### Each of 3 values below produces a difference of some 100 Hz on the chosen MHz frequency.
#define SI5351_CRYSTAL_LOAD					183
#define SI5351_CRYSTAL_LOAD_6PF				(1<<6)
#define SI5351_CRYSTAL_LOAD_8PF				(2<<6)
#define SI5351_CRYSTAL_LOAD_10PF			(3<<6)

enum si5351_clock
{
	SI5351_CLK0,
	SI5351_CLK1,
	SI5351_CLK2
};

enum si5351_pll
{
	SI5351_PLLA, SI5351_PLLB
};

enum si5351_drive
{
	SI5351_DRIVE_2MA, SI5351_DRIVE_4MA, SI5351_DRIVE_6MA, SI5351_DRIVE_8MA
};

/* Struct definitions */

struct Si5351Frac
{
	uint16_t a;
	uint32_t b;
	uint32_t c;
};

struct Si5351RegSet
{
	uint32_t p1;
	uint32_t p2;
	uint32_t p3;
};

/* Function prototypes */
void si5351_init(uint8_t);
void si5351_set_freq(uint64_t freq, enum si5351_clock clk);
void si5351_set_pll(struct Si5351Frac, enum si5351_pll target_pll);
void si5351_set_ms(enum si5351_clock, struct Si5351Frac, uint8_t, uint8_t,
		uint8_t);
void si5351_drive_strength(enum si5351_clock, enum si5351_drive);
void si5351_pll_reset(enum si5351_pll);
void si5351_set_int(enum si5351_clock, uint8_t);
void si5351_set_ms_div(enum si5351_clock, uint8_t, uint8_t);
uint8_t si5351_write_bulk(uint8_t, uint8_t, uint8_t*);
uint8_t si5351_write(uint8_t, uint8_t);
uint8_t si5351_read(uint8_t, uint8_t*);

#endif
