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