mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
107 lines
3.3 KiB
Python
107 lines
3.3 KiB
Python
#
|
|
# Copyright 2018 Ettus Research, a National Instruments Company
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
"""
|
|
DS125DF410 driver class
|
|
|
|
For use with TI's retimer chip
|
|
"""
|
|
|
|
import math
|
|
from builtins import object
|
|
from usrp_mpm.mpmlog import get_logger
|
|
|
|
LINE_RATE_PRESETS = {'Ethernet': 0xF6, 'CPRI1': 0x36, 'CPRI2': 0x46}
|
|
ALL_CHANS = range(4)
|
|
|
|
|
|
class DS125DF410(object):
|
|
"""
|
|
Driver class for DS125DF410 access.
|
|
|
|
Inputs:
|
|
regs_iface : regs_iface bus driver to access device
|
|
parent_log : logger of parent
|
|
"""
|
|
|
|
# (deemphasis, swing)
|
|
DRIVER_PRESETS = {}
|
|
|
|
def __init__(self, regs_iface, parent_log=None):
|
|
self.log = \
|
|
parent_log.getChild("DS125DF410") if parent_log is not None \
|
|
else get_logger("DS125DF410")
|
|
self.regs_iface = regs_iface
|
|
# Set channel select register to control set
|
|
self.regs_iface.poke8(0xFF, 0)
|
|
# Probe chip ID
|
|
chip_id = self.regs_iface.peek8(0x01)
|
|
assert chip_id == 0xd1
|
|
self.log.debug("Probed DS125DF410 retimer")
|
|
for chan in ALL_CHANS:
|
|
self._set_chan_select(chan)
|
|
# Reset channel registers
|
|
self.regs_iface.poke8(0x00, 0x04)
|
|
# Enable DFE mode
|
|
self.regs_iface.poke8(0x1E, 0xE1)
|
|
self.regs_iface.poke8(0x31, 0x40)
|
|
|
|
def _rmw(self, addr, data, mask):
|
|
""" Read, modify, write """
|
|
base = self.regs_iface.peek8(addr) & ~mask
|
|
data = (data & mask) | base
|
|
self.regs_iface.poke8(addr, data)
|
|
|
|
def _set_chan_select(self, chan):
|
|
"""
|
|
Channel select
|
|
"""
|
|
assert chan in ALL_CHANS
|
|
self.regs_iface.poke8(0xFF, chan + 4)
|
|
|
|
def set_rate_preset(self, preset, channels=None):
|
|
"""
|
|
Set rate preset
|
|
"""
|
|
channels = channels or ALL_CHANS
|
|
assert preset in LINE_RATE_PRESETS.keys()
|
|
for chan in channels:
|
|
self._set_chan_select(chan)
|
|
self.regs_iface.poke8(0x2F, LINE_RATE_PRESETS[preset])
|
|
|
|
def set_rate(self, rate, channels=None):
|
|
"""
|
|
Set rate
|
|
"""
|
|
channels = channels or ALL_CHANS
|
|
self.log.trace("Writing custom line rate {}".format(rate))
|
|
ppm_val = int(math.ceil(rate*1280.0))
|
|
assert ppm_val <= 0x7FFF
|
|
for chan in channels:
|
|
assert chan in ALL_CHANS
|
|
self._set_chan_select(chan)
|
|
# Set VCO divider to 1
|
|
self.regs_iface.poke8(0x2F, 0xC6)
|
|
# Set frequency range detection
|
|
self.regs_iface.poke8(0x60, (ppm_val & 0x00FF))
|
|
self.regs_iface.poke8(0x62, (ppm_val & 0x00FF))
|
|
self.regs_iface.poke8(0x61, 0x80 | ((ppm_val >> 8) & 0x00FF))
|
|
self.regs_iface.poke8(0x63, 0x80 | ((ppm_val >> 8) & 0x00FF))
|
|
# Set VCO tolerance range to max
|
|
self.regs_iface.poke8(0x64, 0xFF)
|
|
|
|
def set_driver_preset(self, preset, channels=None):
|
|
"""
|
|
Set driver preset
|
|
"""
|
|
channels = channels or ALL_CHANS
|
|
assert preset in self.DRIVER_PRESETS.keys()
|
|
self.log.trace("Setting retimer's driver for " + preset + " preset")
|
|
deemphasis, swing = self.DRIVER_PRESETS[preset]
|
|
for chan in channels:
|
|
self._set_chan_select(chan)
|
|
self._rmw(0x15, deemphasis, 0x47)
|
|
self._rmw(0x2D, swing, 0x07)
|
|
|