aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mpm/python/usrp_mpm/chips/CMakeLists.txt1
-rw-r--r--mpm/python/usrp_mpm/chips/__init__.py1
-rw-r--r--mpm/python/usrp_mpm/chips/lmk03328.py84
3 files changed, 86 insertions, 0 deletions
diff --git a/mpm/python/usrp_mpm/chips/CMakeLists.txt b/mpm/python/usrp_mpm/chips/CMakeLists.txt
index 9bd7b9372..1f64d8e2d 100644
--- a/mpm/python/usrp_mpm/chips/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/chips/CMakeLists.txt
@@ -9,6 +9,7 @@ set(USRP_MPM_CHIP_FILES
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/lmk04828.py
${CMAKE_CURRENT_SOURCE_DIR}/lmk04832.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/lmk03328.py
${CMAKE_CURRENT_SOURCE_DIR}/adf400x.py
${CMAKE_CURRENT_SOURCE_DIR}/ds125df410.py
)
diff --git a/mpm/python/usrp_mpm/chips/__init__.py b/mpm/python/usrp_mpm/chips/__init__.py
index 60368ad6a..453ab5c2a 100644
--- a/mpm/python/usrp_mpm/chips/__init__.py
+++ b/mpm/python/usrp_mpm/chips/__init__.py
@@ -10,3 +10,4 @@ Chips submodule
from .adf400x import ADF400x
from .lmk04828 import LMK04828
from .lmk04832 import LMK04832
+from .lmk03328 import LMK03328
diff --git a/mpm/python/usrp_mpm/chips/lmk03328.py b/mpm/python/usrp_mpm/chips/lmk03328.py
new file mode 100644
index 000000000..461cf7f38
--- /dev/null
+++ b/mpm/python/usrp_mpm/chips/lmk03328.py
@@ -0,0 +1,84 @@
+#
+# Copyright 2020 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+LMK03328 parent driver class
+"""
+
+from usrp_mpm.mpmlog import get_logger
+
+class LMK03328():
+ """
+ Generic driver class for LMK03328 access.
+ """
+ LMK_CHIP_ID = 0x32
+
+ def __init__(self, regs_iface, parent_log=None):
+ self.log = \
+ parent_log.getChild("LMK03328") if parent_log is not None \
+ else get_logger("LMK03328")
+ self.regs_iface = regs_iface
+ assert hasattr(self.regs_iface, 'peek8')
+ assert hasattr(self.regs_iface, 'poke8')
+ self.poke8 = regs_iface.poke8
+ self.peek8 = regs_iface.peek8
+
+ def pokes8(self, addr_vals):
+ """
+ Apply a series of pokes.
+ pokes8([(0,1),(0,2)]) is the same as calling poke8(0,1), poke8(0,2).
+ """
+ for addr, val in addr_vals:
+ self.poke8(addr, val)
+
+ def get_chip_id(self):
+ """
+ Read back the chip ID
+ """
+ chip_id = self.peek8(0x02)
+ self.log.trace("Chip ID Readback: {}".format(chip_id))
+ return chip_id
+
+ def verify_chip_id(self):
+ """
+ Returns True if the chip ID matches what we expect, False otherwise.
+ """
+ chip_id = self.get_chip_id()
+ if chip_id != self.LMK_CHIP_ID:
+ self.log.error("Wrong Chip ID 0x{:X}".format(chip_id))
+ return False
+ return True
+
+ def check_pll_locked(self, pll_num):
+ """
+ Returns True if the specified PLL is locked, False otherwise.
+ """
+ if pll_num not in (1, 2):
+ self.log.warning("PLL{} is not a valid PLL"
+ .format(pll_num))
+ return False
+ pll_lock_status = self.peek8(13)
+
+ # Lock status for PLL1 is bits [7:6] and PLL2 is bits [4:3]
+ pll_lock_mask = 0xC0 if pll_num == 1 else 0x18
+
+ if (pll_lock_status & pll_lock_mask) != 0x0:
+ self.log.debug("PLL{} reporting unlocked... Status: 0x{:x}"
+ .format(pll_num, pll_lock_status))
+ return False
+ return True
+
+ def soft_reset(self, value=True):
+ """
+ Performs a soft reset of the LMK03328 by setting or unsetting the software
+ reset register. The adjacent contents of the register are preserved by
+ reading their value prior to re-writing the corresponding byte.
+ """
+ reset_bit = 0x80
+ reset_addr = 12
+ old_reg_val = self.peek8(reset_addr)
+ # The reset register is active low so if value is True, write 0. Otherwise, write 1
+ new_reg_val = (old_reg_val & (~reset_bit)) if value else (old_reg_val | reset_bit)
+ self.poke8(reset_addr, new_reg_val)