diff --git a/firmware/common/jellybean.c b/firmware/common/jellybean.c new file mode 100644 index 00000000..2cfc03a4 --- /dev/null +++ b/firmware/common/jellybean.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone + * + * This file is part of HackRF. + * + * 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 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "si5351c.h" + +/* initial configuration for Jellybean with Lemondrop attached */ +void jellybean_init(void) +{ + //FIXME I2C setup + + si5351c_disable_all_outputs(); + si5351c_disable_oeb_pin_control(); + si5351c_power_down_all_clocks(); + si5351c_set_crystal_configuration(); + si5351c_enable_xo_and_ms_fanout(); + si5351c_configure_pll_sources_for_xtal(); + si5351c_configure_pll1_multisynth(); + + /* MS0/CLK0 is the source for the MAX2837 clock input. */ + si5351c_configure_multisynth(0, 2048, 0, 1); /* 40MHz */ + + /* MS1/CLK1 is the source for the MAX5864 codec. */ + si5351c_configure_multisynth(1, 4608, 0, 1); /* 20MHz */ + + /* MS4/CLK4 is the source for the LPC43xx microcontroller. */ + si5351c_configure_multisynth(4, 8021, 1, 3); /* 12MHz */ + + si5351c_configure_clock_control(); + si5351c_enable_clock_outputs(); + + //FIXME disable I2C + + /* + * 12MHz clock is entering LPC XTAL1/OSC input now. + * Set up PLL1 to run from XTAL1 input. + */ + + //FIXME CGU setup +} diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c new file mode 100644 index 00000000..d77a9fe1 --- /dev/null +++ b/firmware/common/si5351c.c @@ -0,0 +1,191 @@ +/* + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone + * + * This file is part of HackRF. + * + * 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 2, 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +#define SI5351C_I2C_ADDR (0x60 << 1) + +/* FIXME return i2c0 status from each function */ + +/* write to single register */ +void si5351c_write_single(uint8_t reg, uint8_t val) +{ + i2c0_tx_start(); + i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + i2c0_tx_byte(reg); + i2c0_tx_byte(val); + i2c0_stop(); +} + +/* read single register */ +uint8_t si5351c_read_reg(uint8_t reg) +{ + uint8_t val; + + /* set register address with write */ + i2c0_tx_start(); + i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + i2c0_tx_byte(reg); + + /* read the value */ + i2c0_tx_start(); + i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ); + val = i2c0_rx_byte(); + i2c0_stop(); + + return val; +} + +/* + * Write to one or more contiguous registers. data[0] should be the first + * register number, one or more values follow. + */ +void si5351c_write(uint8_t* const data, const uint_fast8_t data_count) +{ + uint_fast8_t i; + + i2c0_tx_start(); + i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); + + for (i = 0; i < data_count; i++) + i2c0_tx_byte(data[i]); + i2c0_stop(); +} + +/* Disable all CLKx outputs. */ +void si5351c_disable_all_outputs() +{ + uint8_t data[] = { 3, 0xFF }; + si5351c_write(data, sizeof(data)); +} + +/* Turn off OEB pin control for all CLKx */ +void si5351c_disable_oeb_pin_control() +{ + uint8_t data[] = { 9, 0xFF }; + si5351c_write(data, sizeof(data)); +} + +/* Power down all CLKx */ +void si5351c_power_down_all_clocks() +{ + uint8_t data[] = { 16, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + si5351c_write(data, sizeof(data)); +} + +/* + * Register 183: Crystal Internal Load Capacitance + * Reads as 0xE4 on power-up + * Set to 10pF (until I find out what loading the crystal/PCB likes best) + */ +void si5351c_set_crystal_configuration() +{ + uint8_t data[] = { 183, 0xE4 }; + si5351c_write(data, sizeof(data)); +} + +/* + * Register 187: Fanout Enable + * Turn on XO and MultiSynth fanout only. + */ +void si5351c_enable_xo_and_ms_fanout() +{ + uint8_t data[] = { 187, 0x50 }; + si5351c_write(data, sizeof(data)); +} + +/* + * Register 15: PLL Input Source + * CLKIN_DIV=0 (Divide by 1) + * PLLB_SRC=0 (XTAL input) + * PLLA_SRC=0 (XTAL input) + */ +void si5351c_configure_pll_sources_for_xtal() +{ + uint8_t data[] = { 15, 0x00 }; + si5351c_write(data, sizeof(data)); +} + +/* MultiSynth NA (PLL1) */ +void si5351c_configure_pll1_multisynth() +{ + uint8_t data[] = { 26, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 }; + si5351c_write(data, sizeof(data)); +} + +void si5351c_configure_multisynth( const uint_fast8_t ms_number, + const uint32_t p1, const uint32_t p2, const uint32_t p3) +{ + /* + * TODO: Check for p3 > 0? 0 has no meaning in fractional mode? + * And it makes for more jitter in integer mode. + */ + const uint_fast8_t register_number = 42 + (ms_number * 8); + uint8_t data[] = { + register_number, + (p3 >> 8) & 0xFF, + (p3 >> 0) & 0xFF, + (0 << 4) | (0 << 2) | ((p1 >> 16) & 0x3), + (p1 >> 8) & 0xFF, + (p1 >> 0) & 0xFF, + (((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0), + (p2 >> 8) & 0xFF, + (p2 >> 0) & 0xFF }; + si5351c_write(data, sizeof(data)); +} + +/* + * Registers 16 through 23: CLKx Control + * CLK0: + * CLK0_PDN=0 (powered up) + * MS0_INT=1 (integer mode) + * MS0_SRC=0 (PLLA as source for MultiSynth 0) + * CLK0_INV=0 (not inverted) + * CLK0_SRC=3 (MS0 as input source) + * CLK0_IDRV=3 (8mA) + * CLK1: + * CLK1_PDN=0 (powered up) + * MS1_INT=1 (integer mode) + * MS1_SRC=0 (PLLA as source for MultiSynth 1) + * CLK1_INV=0 (not inverted) + * CLK1_SRC=3 (MS1 as input source) + * CLK1_IDRV=3 (8mA) + * CLK4: + * CLK4_PDN=0 (powered up) + * MS4_INT=0 (fractional mode -- to support 12MHz to LPC for USB DFU) + * MS4_SRC=0 (PLLA as source for MultiSynth 4) + * CLK4_INV=0 (not inverted) + * CLK4_SRC=3 (MS4 as input source) + * CLK4_IDRV=3 (8mA) + */ +void si5351c_configure_clock_control() +{ + uint8_t data[] = { 16, 0x4F, 0x4F, 0x80, 0x80, 0x0F, 0x80, 0x80, 0x80 }; + si5351c_write(data, sizeof(data)); +} + +/* Enable CLK outputs 0, 1, 4 only. */ +void si5351c_enable_clock_outputs() +{ + uint8_t data[] = { 3, 0xEC }; + si5351c_write(data, sizeof(data)); +}