From 8f21adbed40db490bec8ead6b8d50d2b3d1a4136 Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Tue, 4 May 2010 09:32:38 +0000
Subject: created codec control for ad9862, wip

---
 host/lib/usrp/usrp_e/clock_ctrl.cpp   |  39 ++++++++++-
 host/lib/usrp/usrp_e/codec_ctrl.cpp   | 122 ++++++++++++++++++++++++++++++++++
 host/lib/usrp/usrp_e/codec_ctrl.hpp   |  73 ++++++++++++++++++++
 host/lib/usrp/usrp_e/usrp_e_iface.cpp |   7 +-
 host/lib/usrp/usrp_e/usrp_e_impl.cpp  |   8 ++-
 host/lib/usrp/usrp_e/usrp_e_impl.hpp  |   8 +++
 6 files changed, 250 insertions(+), 7 deletions(-)
 create mode 100644 host/lib/usrp/usrp_e/codec_ctrl.cpp
 create mode 100644 host/lib/usrp/usrp_e/codec_ctrl.hpp

(limited to 'host/lib/usrp')

diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp
index fa4028cc5..2fe3c9294 100644
--- a/host/lib/usrp/usrp_e/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp
@@ -37,6 +37,7 @@ public:
 
     void enable_rx_dboard_clock(bool enb);
     void enable_tx_dboard_clock(bool enb);
+    void enable_codec_clock(bool enb);
 
 private:
     usrp_e_iface::sptr _iface;
@@ -79,10 +80,22 @@ clock_ctrl_impl::clock_ctrl_impl(usrp_e_iface::sptr iface){
     _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5;
     _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO;
 
+    //setup fpga master clock
     _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS;
     _ad9522_regs.divider0_low_cycles = 2; //3 low
     _ad9522_regs.divider0_high_cycles = 1; //2 high
 
+    //setup codec clock
+    _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS;
+    _ad9522_regs.divider1_low_cycles = 2; //3 low
+    _ad9522_regs.divider1_high_cycles = 1; //2 high
+
+    //setup test clock (same divider as codec clock)
+    _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS;
+    _ad9522_regs.out4_cmos_configuration = (true)?
+        ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON :
+        ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF;
+
     //setup a list of register ranges to write
     typedef std::pair<boost::uint16_t, boost::uint16_t> range_t;
     static const std::vector<range_t> ranges = boost::assign::list_of
@@ -106,6 +119,8 @@ clock_ctrl_impl::clock_ctrl_impl(usrp_e_iface::sptr iface){
     //    reg, 24, true /*no*/
     //);
     //std::cout << "result " << std::hex << result << std::endl;
+    this->enable_rx_dboard_clock(false);
+    this->enable_tx_dboard_clock(false);
 }
 
 clock_ctrl_impl::~clock_ctrl_impl(void){
@@ -114,16 +129,34 @@ clock_ctrl_impl::~clock_ctrl_impl(void){
 }
 
 void clock_ctrl_impl::enable_rx_dboard_clock(bool enb){
-    
+    _ad9522_regs.out9_format = ad9522_regs_t::OUT9_FORMAT_CMOS;
+    _ad9522_regs.out9_cmos_configuration = (enb)?
+        ad9522_regs_t::OUT9_CMOS_CONFIGURATION_B_ON :
+        ad9522_regs_t::OUT9_CMOS_CONFIGURATION_OFF;
+    this->send_reg(0x0F9);
+
+    _ad9522_regs.divider3_low_cycles = 2; //3 low
+    _ad9522_regs.divider3_high_cycles = 1; //2 high
+    this->send_reg(0x199);
+    this->latch_regs();
 }
 
 void clock_ctrl_impl::enable_tx_dboard_clock(bool enb){
-    
+    _ad9522_regs.out6_format = ad9522_regs_t::OUT6_FORMAT_CMOS;
+    _ad9522_regs.out6_cmos_configuration = (enb)?
+        ad9522_regs_t::OUT6_CMOS_CONFIGURATION_B_ON :
+        ad9522_regs_t::OUT6_CMOS_CONFIGURATION_OFF;
+    this->send_reg(0x0F6);
+
+    _ad9522_regs.divider2_low_cycles = 2; //3 low
+    _ad9522_regs.divider2_high_cycles = 1; //2 high
+    this->send_reg(0x196);
+    this->latch_regs();
 }
 
 void clock_ctrl_impl::send_reg(boost::uint16_t addr){
     boost::uint32_t reg = _ad9522_regs.get_write_reg(addr);
-    std::cout << "clock control write reg: " << std::hex << reg << std::endl;
+    //std::cout << "clock control write reg: " << std::hex << reg << std::endl;
     _iface->transact_spi(
         UE_SPI_SS_AD9522,
         spi_config_t::EDGE_RISE,
diff --git a/host/lib/usrp/usrp_e/codec_ctrl.cpp b/host/lib/usrp/usrp_e/codec_ctrl.cpp
new file mode 100644
index 000000000..daa6ed3e3
--- /dev/null
+++ b/host/lib/usrp/usrp_e/codec_ctrl.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// 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/>.
+//
+
+#include "codec_ctrl.hpp"
+#include "ad9862_regs.hpp"
+#include <boost/cstdint.hpp>
+#include "usrp_e_regs.hpp" //spi slave constants
+#include <boost/assign/list_of.hpp>
+//#include <boost/foreach.hpp>
+//#include <utility>
+#include <iostream>
+
+    //test out codec ls dac/adc
+    //ad9862_regs_t ad9862_regs;
+    //ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1;
+    //ad9862_regs.aux_dac_a = 0xff/2;
+    //_iface->transact_spi(
+    //    UE_SPI_SS_AD9862,
+    //    spi_config_t::EDGE_RISE,
+    //    ad9862_regs.get_write_reg(34), 16, false /*no rb*/
+    //);
+    //_iface->transact_spi(
+    //    UE_SPI_SS_AD9862,
+    //    spi_config_t::EDGE_RISE,
+    //    ad9862_regs.get_write_reg(36), 16, false /*no rb*/
+    //);
+    //boost::uint32_t val = _iface->transact_spi(
+    //    UE_SPI_SS_AD9862,
+    //    spi_config_t::EDGE_RISE,
+    //    ad9862_regs.get_read_reg(29), 16, true
+    //);
+    //std::cout << "value: " << std::hex << val << std::endl;
+
+using namespace uhd;
+
+/***********************************************************************
+ * Codec Control Implementation
+ **********************************************************************/
+class codec_ctrl_impl : public codec_ctrl{
+public:
+    //structors
+    codec_ctrl_impl(usrp_e_iface::sptr iface);
+    ~codec_ctrl_impl(void);
+
+    //aux adc and dac control
+    float read_aux_adc(aux_adc_t which);
+    void read_aux_adc(aux_dac_t which, float volts);
+
+private:
+    usrp_e_iface::sptr _iface;
+    ad9862_regs_t _ad9862_regs;
+    void send_reg(boost::uint8_t addr);
+};
+
+/***********************************************************************
+ * Codec Control Methods
+ **********************************************************************/
+codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){
+    _iface = iface;
+
+    //soft reset
+    _ad9862_regs.soft_reset = 1;
+    this->send_reg(0);
+
+    //initialize the codec register settings
+    _ad9862_regs.sdio_bidir = ad9862_regs_t::SDIO_BIDIR_SDIO_SDO;
+    _ad9862_regs.lsb_first = ad9862_regs_t::LSB_FIRST_MSB;
+    _ad9862_regs.soft_reset = 0;
+
+    //write the register settings to the codec
+    for (uint8_t addr = 0; addr <= 50; addr++){
+        this->send_reg(addr);
+    }
+}
+
+codec_ctrl_impl::~codec_ctrl_impl(void){
+    _ad9862_regs.all_rx_pd = 1;
+    this->send_reg(1);
+    _ad9862_regs.tx_digital_pd = 1;
+    _ad9862_regs.tx_analog_pd = ad9862_regs_t::TX_ANALOG_PD_BOTH;
+    this->send_reg(8);
+}
+
+float codec_ctrl_impl::read_aux_adc(aux_adc_t which){
+    return 0;
+
+}
+
+void codec_ctrl_impl::read_aux_adc(aux_dac_t which, float volts){
+    
+}
+
+void codec_ctrl_impl::send_reg(boost::uint8_t addr){
+    boost::uint32_t reg = _ad9862_regs.get_write_reg(addr);
+    //std::cout << "codec control write reg: " << std::hex << reg << std::endl;
+    _iface->transact_spi(
+        UE_SPI_SS_AD9862,
+        spi_config_t::EDGE_RISE,
+        reg, 24, false /*no rb*/
+    );
+}
+
+/***********************************************************************
+ * Codec Control Make
+ **********************************************************************/
+codec_ctrl::sptr codec_ctrl::make(usrp_e_iface::sptr iface){
+    return sptr(new codec_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp_e/codec_ctrl.hpp b/host/lib/usrp/usrp_e/codec_ctrl.hpp
new file mode 100644
index 000000000..0fe70c4a2
--- /dev/null
+++ b/host/lib/usrp/usrp_e/codec_ctrl.hpp
@@ -0,0 +1,73 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// 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 INCLUDED_USRP_E_CODEC_CTRL_HPP
+#define INCLUDED_USRP_E_CODEC_CTRL_HPP
+
+#include "usrp_e_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+/*!
+ * The usrp-e codec control:
+ * - Init/power down codec.
+ * - Read aux adc, write aux dac.
+ */
+class codec_ctrl : boost::noncopyable{
+public:
+    typedef boost::shared_ptr<codec_ctrl> sptr;
+
+    /*!
+     * Make a new clock control object.
+     * \param iface the usrp_e iface object
+     * \return the clock control object
+     */
+    static sptr make(usrp_e_iface::sptr iface);
+
+    //! aux adc identifier constants
+    enum aux_adc_t{
+        AUX_ADC_A2 = 0xA2,
+        AUX_ADC_A1 = 0xA1,
+        AUX_ADC_B2 = 0xB2,
+        AUX_ADC_B1 = 0xB1
+    };
+
+    /*!
+     * Read the aux adc.
+     * \param which which of the 4 adcs
+     * \return a value in volts
+     */
+    virtual float read_aux_adc(aux_adc_t which) = 0;
+
+    //! aux dac identifier constants
+    enum aux_dac_t{
+        AUX_DAC_A = 0xA,
+        AUX_DAC_B = 0xB,
+        AUX_DAC_C = 0xC,
+        AUX_DAC_D = 0xD
+    };
+
+    /*!
+     * Write the aux dac.
+     * \param which which of the 4 dacs
+     * \param volts the level in in volts
+     */
+    virtual void read_aux_adc(aux_dac_t which, float volts) = 0;
+
+};
+
+#endif /* INCLUDED_USRP_E_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.cpp b/host/lib/usrp/usrp_e/usrp_e_iface.cpp
index 41737a716..1dbe383fa 100644
--- a/host/lib/usrp/usrp_e/usrp_e_iface.cpp
+++ b/host/lib/usrp/usrp_e/usrp_e_iface.cpp
@@ -20,6 +20,7 @@
 #include <sys/ioctl.h> //ioctl
 #include <linux/usrp_e.h> //ioctl structures and constants
 #include <boost/format.hpp>
+#include <boost/thread.hpp> //mutex
 #include <stdexcept>
 
 using namespace uhd;
@@ -42,6 +43,8 @@ public:
      * IOCTL: provides the communication base for all other calls
      ******************************************************************/
     void ioctl(int request, void *mem){
+        boost::mutex::scoped_lock lock(_ctrl_mutex);
+
         if (::ioctl(_node_fd, request, mem) < 0){
             throw std::runtime_error(str(
                 boost::format("ioctl failed with request %d") % request
@@ -167,7 +170,9 @@ public:
         return data.data;
     }
 
-private: int _node_fd;
+private:
+    int _node_fd;
+    boost::mutex _ctrl_mutex;
 };
 
 /***********************************************************************
diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.cpp b/host/lib/usrp/usrp_e/usrp_e_impl.cpp
index 52bbcdd32..b6fed6a74 100644
--- a/host/lib/usrp/usrp_e/usrp_e_impl.cpp
+++ b/host/lib/usrp/usrp_e/usrp_e_impl.cpp
@@ -23,7 +23,6 @@
 #include <boost/filesystem.hpp>
 #include <iostream>
 #include <fcntl.h> //open
-#include "clock_ctrl.hpp"
 
 using namespace uhd;
 using namespace uhd::usrp;
@@ -84,9 +83,12 @@ usrp_e_impl::usrp_e_impl(const std::string &node){
         ));
     }
 
-    _iface = usrp_e_iface::make(_node_fd);
+    sleep(1); //FIXME sleep here until the kernel driver stops hanging
 
-    clock_ctrl::sptr my_clk_ctrl = clock_ctrl::make(_iface);
+    //setup various interfaces into hardware
+    _iface = usrp_e_iface::make(_node_fd);
+    _clock_ctrl = clock_ctrl::make(_iface);
+    _codec_ctrl = codec_ctrl::make(_iface);
 
     //initialize the mboard
     mboard_init();
diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp
index 23e36ed05..6746e012a 100644
--- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp
+++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp
@@ -16,6 +16,8 @@
 //
 
 #include "usrp_e_iface.hpp"
+#include "clock_ctrl.hpp"
+#include "codec_ctrl.hpp"
 #include <uhd/usrp/usrp_e.hpp>
 #include <uhd/usrp/dboard_eeprom.hpp>
 #include <uhd/types/clock_config.hpp>
@@ -91,6 +93,12 @@ private:
 
     uhd::clock_config_t _clock_config;
 
+    //ad9522 clock control
+    clock_ctrl::sptr _clock_ctrl;
+
+    //ad9862 codec control
+    codec_ctrl::sptr _codec_ctrl;
+
     //device functions and settings
     void get(const wax::obj &, wax::obj &);
     void set(const wax::obj &, const wax::obj &);
-- 
cgit v1.2.3