1# 2# Copyright 2017 Ettus Research, a National Instruments Company 3# 4# SPDX-License-Identifier: GPL-3.0-or-later 5# 6""" 7LMK04828 parent driver class 8""" 9 10import math 11from builtins import object 12from usrp_mpm.mpmlog import get_logger 13 14class LMK04828(object): 15 """ 16 Generic driver class for LMK04828 access. 17 """ 18 LMK_CHIP_ID = 6 19 20 def __init__(self, regs_iface, parent_log=None): 21 self.log = \ 22 parent_log.getChild("LMK04828") if parent_log is not None \ 23 else get_logger("LMK04828") 24 self.regs_iface = regs_iface 25 assert hasattr(self.regs_iface, 'peek8') 26 assert hasattr(self.regs_iface, 'poke8') 27 self.poke8 = regs_iface.poke8 28 self.peek8 = regs_iface.peek8 29 30 def pokes8(self, addr_vals): 31 """ 32 Apply a series of pokes. 33 pokes8((0,1),(0,2)) is the same as calling poke8(0,1), poke8(0,2). 34 """ 35 for addr, val in addr_vals: 36 self.poke8(addr, val) 37 38 def get_chip_id(self): 39 """ 40 Read back the chip ID 41 """ 42 chip_id = self.peek8(0x03) 43 self.log.trace("Chip ID Readback: {}".format(chip_id)) 44 return chip_id 45 46 def verify_chip_id(self): 47 """ 48 Returns True if the chip ID matches what we expect, False otherwise. 49 """ 50 chip_id = self.get_chip_id() 51 if chip_id != self.LMK_CHIP_ID: 52 self.log.error("Wrong Chip ID 0x{:X}".format(chip_id)) 53 return False 54 return True 55 56 def check_plls_locked(self): 57 """ 58 Returns True if both PLLs are locked, False otherwise. 59 """ 60 def check_pll_lock(pll_id, addr): 61 """ 62 pll_id -- A string defining the PLL (e.g. 'PLL1') 63 addr -- The address to peek to see if it's locked 64 """ 65 pll_lock_status = self.regs_iface.peek8(addr) 66 if (pll_lock_status & 0x7) != 0x02: 67 self.log.debug("{} reporting unlocked... Status: 0x{:x}" 68 .format(pll_id, pll_lock_status)) 69 return False 70 return True 71 lock_status = \ 72 check_pll_lock("PLL1", 0x182) and \ 73 check_pll_lock("PLL2", 0x183) 74 return lock_status 75 76 77## Register bitfield definitions ## 78 79 def divide_to_cnth_cntl_reg(self, divide_val): 80 """ 81 From the divider value, returns the CNTL and CNTH register value. 82 Split divider value in half. If odd, round up for the CNTL and down 83 for the CNTH based on the datasheet recommendation. 84 """ 85 cntl = int(math.ceil( divide_val/2.0)) 86 cnth = int(math.floor(divide_val/2.0)) 87 reg_val = ((cnth & 0xF) << 4) | (cntl & 0xF) 88 self.log.trace("From divider value 0d{}, writing CNTH/L as 0x{:02X}." 89 .format(divide_val, reg_val)) 90 return reg_val 91 92 def divide_to_reg(self, divide_val, in_drive=0x1, out_drive=0x1): 93 """ 94 From the divider value, returns the register value combined with the other 95 register fields. 96 """ 97 reg_val = (divide_val & 0x1F) | ((in_drive & 0x1) << 5) | ((out_drive & 0x1) << 6) 98 self.log.trace("From divider value 0d{}, writing divider register as 0x{:02X}." 99 .format(divide_val, reg_val)) 100 return reg_val 101 102 def pll2_pre_to_reg(self, prescaler, osc_field=0x01, xtal_en=0x0, ref_2x_en=0x0): 103 """ 104 From the prescaler value, returns the register value combined with the other 105 register fields. 106 """ 107 # valid prescaler values are 2-8, where 8 is represented as 0x00. 108 assert prescaler in range(2, 8+1) 109 reg_val = ((prescaler & 0x07) << 5) \ 110 | ((osc_field & 0x7) << 2) \ 111 | ((xtal_en & 0x1) << 1) \ 112 | ((ref_2x_en & 0x1) << 0) 113 self.log.trace("From prescaler value 0d{}, writing register as 0x{:02X}." 114 .format(prescaler, reg_val)) 115 return reg_val 116 117