From eb0dea483fa120fc8c4252ba0c7331879fe3d189 Mon Sep 17 00:00:00 2001
From: Jared Boone <jboone@earfeast.com>
Date: Wed, 12 Nov 2014 13:56:58 -0800
Subject: [PATCH 39/68] I2C: Finish extracting from Si5351C code.

---
 firmware/common/hackrf_core.c | 31 ++++++++++++++++++++---
 firmware/common/i2c_bus.c     | 35 ++++++++++++++++++++++++++
 firmware/common/i2c_bus.h     | 50 +++++++++++++++++++++++++++++++++++++
 firmware/common/i2c_lpc.c     | 57 +++++++++++++++++++++++++++++++++++++++++++
 firmware/common/i2c_lpc.h     | 41 +++++++++++++++++++++++++++++++
 firmware/common/si5351c_drv.c | 34 ++------------------------
 firmware/common/si5351c_drv.h |  3 +++
 firmware/hackrf-common.cmake  |  2 ++
 firmware/libopencm3           |  2 +-
 9 files changed, 219 insertions(+), 36 deletions(-)
 create mode 100644 firmware/common/i2c_bus.c
 create mode 100644 firmware/common/i2c_bus.h
 create mode 100644 firmware/common/i2c_lpc.c
 create mode 100644 firmware/common/i2c_lpc.h

--- a/firmware/common/hackrf_core.c
+++ b/firmware/common/hackrf_core.c
@@ -34,7 +34,8 @@
 #include "w25q80bv_target.h"
 #include "sgpio.h"
 #include "rf_path.h"
-#include <libopencm3/lpc43xx/i2c.h>
+#include "i2c_bus.h"
+#include "i2c_lpc.h"
 #include <libopencm3/lpc43xx/cgu.h>
 #include <libopencm3/lpc43xx/gpio.h>
 #include <libopencm3/lpc43xx/scu.h>
@@ -42,7 +43,28 @@
 
 #define WAIT_CPU_CLOCK_INIT_DELAY   (10000)
 
+i2c_bus_t i2c0 = {
+	.obj = (void*)I2C0_BASE,
+	.init = i2c_lpc_init,
+	.transfer = i2c_lpc_transfer,
+};
+
+i2c_bus_t i2c1 = {
+	.obj = (void*)I2C1_BASE,
+	.init = i2c_lpc_init,
+	.transfer = i2c_lpc_transfer,
+};
+
+const i2c_lpc_config_t i2c_config_si5351c_slow_clock = {
+	.duty_cycle_count = 15,
+};
+
+const i2c_lpc_config_t i2c_config_si5351c_fast_clock = {
+	.duty_cycle_count = 255,
+};
+
 si5351c_driver_t clock_gen = {
+	.bus = &i2c0,
 	.i2c_address = 0x60,
 };
 
@@ -356,7 +378,7 @@
 	/* use IRC as clock source for APB3 */
 	CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
 
-	i2c0_init(15);
+	i2c_bus_init(clock_gen.bus, &i2c_config_si5351c_slow_clock);
 
 	si5351c_disable_all_outputs(&clock_gen);
 	si5351c_disable_oeb_pin_control(&clock_gen);
@@ -428,7 +450,7 @@
 
 	//FIXME disable I2C
 	/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
-	i2c0_init(255);
+	i2c_bus_init(clock_gen.bus, &i2c_config_si5351c_fast_clock);
 
 	/*
 	 * 12MHz clock is entering LPC XTAL1/OSC input now.  On
@@ -656,6 +678,9 @@
 	spi_init(&spi_ssp1, &ssp_config_max2837);
 	spi_init(&rffc5071_spi, NULL);
 
+	/* enable input on SCL and SDA pins */
+	SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
+
 	rf_path_pin_setup();
 	
 	/* Configure external clock in */
--- /dev/null
+++ b/firmware/common/i2c_bus.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
+ *
+ * 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 "i2c_bus.h"
+
+void i2c_bus_init(i2c_bus_t* const bus, const void* const config) {
+	bus->init(bus, config);
+}
+
+void i2c_bus_transfer(
+	i2c_bus_t* const bus,
+	const uint_fast8_t slave_address,
+	const uint8_t* const tx, const size_t tx_count,
+	uint8_t* const rx, const size_t rx_count
+) {
+	bus->transfer(bus, slave_address, tx, tx_count, rx, rx_count);
+}
--- /dev/null
+++ b/firmware/common/i2c_bus.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __I2C_BUS_H__
+#define __I2C_BUS_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+struct i2c_bus_t;
+typedef struct i2c_bus_t i2c_bus_t;
+
+struct i2c_bus_t {
+	void* const obj;
+	void (*init)(i2c_bus_t* const bus, const void* const config);
+	void (*transfer)(
+		i2c_bus_t* const bus,
+		const uint_fast8_t slave_address,
+		const uint8_t* const tx, const size_t tx_count,
+		uint8_t* const rx, const size_t rx_count
+	);
+};
+
+void i2c_bus_init(i2c_bus_t* const bus, const void* const config);
+void i2c_bus_transfer(
+	i2c_bus_t* const bus,
+	const uint_fast8_t slave_address,
+	const uint8_t* const tx, const size_t tx_count,
+	uint8_t* const rx, const size_t rx_count
+);
+
+#endif/*__I2C_BUS_H__*/
--- /dev/null
+++ b/firmware/common/i2c_lpc.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Michael Ossmann <mike@ossmann.com>
+ * Copyright 2012 Jared Boone <jared@sharebrained.com>
+ *
+ * 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 "i2c_lpc.h"
+
+#include <libopencm3/lpc43xx/i2c.h>
+
+/* FIXME return i2c0 status from each function */
+
+void i2c_lpc_init(i2c_bus_t* const bus, const void* const _config) {
+	const i2c_lpc_config_t* const config = _config;
+
+	const uint32_t port = (uint32_t)bus->obj;
+	i2c_init(port, config->duty_cycle_count);
+}
+
+void i2c_lpc_transfer(i2c_bus_t* const bus,
+	const uint_fast8_t slave_address,
+	const uint8_t* const data_tx, const size_t count_tx,
+	uint8_t* const data_rx, const size_t count_rx
+) {
+	const uint32_t port = (uint32_t)bus->obj;
+	i2c_tx_start(port);
+	i2c_tx_byte(port, (slave_address << 1) | I2C_WRITE);
+	for(size_t i=0; i<count_tx; i++) {
+		i2c_tx_byte(port, data_tx[i]);
+	}
+
+	if( data_rx ) {
+		i2c_tx_start(port);
+		i2c_tx_byte(port, (slave_address << 1) | I2C_READ);
+		for(size_t i=0; i<count_rx; i++) {
+			data_rx[i] = i2c_rx_byte(port);
+		}
+	}
+
+	i2c_stop(port);
+}
--- /dev/null
+++ b/firmware/common/i2c_lpc.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __I2C_LPC_H__
+#define __I2C_LPC_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "i2c_bus.h"
+
+typedef struct i2c_lpc_config_t {
+	const uint16_t duty_cycle_count;
+} i2c_lpc_config_t;
+
+void i2c_lpc_init(i2c_bus_t* const bus, const void* const config);
+void i2c_lpc_transfer(i2c_bus_t* const bus,
+	const uint_fast8_t slave_address,
+	const uint8_t* const data_tx, const size_t count_tx,
+	uint8_t* const data_rx, const size_t count_rx
+);
+
+#endif/*__I2C_LPC_H__*/
--- a/firmware/common/si5351c_drv.c
+++ b/firmware/common/si5351c_drv.c
@@ -22,36 +22,6 @@
 
 #include "si5351c_drv.h"
 
-#include <libopencm3/lpc43xx/i2c.h>
-
-#define SI5351C_I2C_ADDR (0x60 << 1)
-
-/* FIXME return i2c0 status from each function */
-
-static void i2c0_transfer(si5351c_driver_t* const drv,
-	const uint_fast8_t address,
-	const uint8_t* const data_tx, const size_t count_tx,
-	uint8_t* const data_rx, const size_t count_rx
-) {
-	(void)drv;
-	
-	i2c0_tx_start();
-	i2c0_tx_byte((address << 1) | I2C_WRITE);
-	for(size_t i=0; i<count_tx; i++) {
-		i2c0_tx_byte(data_tx[i]);
-	}
-
-	if( data_rx ) {
-		i2c0_tx_start();
-		i2c0_tx_byte((address << 1) | I2C_READ);
-		for(size_t i=0; i<count_rx; i++) {
-			data_rx[i] = i2c0_rx_byte();
-		}
-	}
-
-	i2c0_stop();
-}
-
 /* write to single register */
 void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val)
 {
@@ -64,7 +34,7 @@
 {
 	const uint8_t data_tx[] = { reg };
 	uint8_t data_rx[] = { 0x00 };
-	i2c0_transfer(drv, drv->i2c_address, data_tx, 1, data_rx, 1);
+	i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1);
 	return data_rx[0];
 }
 
@@ -74,5 +44,5 @@
  */
 void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count)
 {
-	i2c0_transfer(drv, drv->i2c_address, data, data_count, NULL, 0);
+	i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0);
 }
--- a/firmware/common/si5351c_drv.h
+++ b/firmware/common/si5351c_drv.h
@@ -31,7 +31,10 @@
 #include <stdint.h>
 #include <stddef.h>
 
+#include "i2c_bus.h"
+
 typedef struct {
+	i2c_bus_t* const bus;
 	uint8_t i2c_address;
 } si5351c_driver_t;
 
