dahdi-linux/drivers/dahdi/xpp/init_card_6_30
Dima Stoliarov 24648e6eb3 xpp: init_card_6_3: broadcasts for faster calibration
FXS module type 6: Use broadcast write for a much faster
calibration at init time.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2017-06-26 17:58:29 +03:00

1178 lines
29 KiB
Perl

#! /usr/bin/perl -w
use strict;
# Make warnings fatal
local $SIG{__WARN__} = sub { die @_ };
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2017, Xorcom
#
# All rights reserved.
#
# 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 2 of the License, or
# (at your option) any later version.
#
# See the file LICENSE in the top level of this tarball.
#
#
# $Id$
#
# Data format:
# - A comment start with ';' or '#' until the end of line
# - Blank lines are ignored
# - Fields are whitespace separated (spaces or tabs)
#
# The fields are (in command line order):
# 1. SLIC select in decimal (range 0-7).
# * is a special value which means ALL SLICS (only some registers
# accept settings for ALL SLICS).
# 2. Command word:
# - RD Read Direct register.
# - RS Read Sub-register.
# - WD Write Direct register.
# - WS Write Sub-register.
# 3. Register number in hexadecimal.
# 4. Low data byte in hexadecimal. (for WD and WS commands).
# 5. High data byte in hexadecimal. (for WS command only).
#
#
package main;
use File::Basename;
use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
my $eeprom_release_201 = 0;
getopts('o:', \%opts);
my %settings;
$settings{debug} = 0;
$settings{fxs_skip_calib} = 0;
my $chipregs;
my $command;
my $expander_cmd;
my $ring_registers;
sub logit {
print STDERR "$unit_id: @_\n";
}
sub debug {
logit @_ if $settings{debug};
}
# Arrange for error logging
if (-t STDERR) {
$unit_id = 'Interactive';
debug "Interactive startup";
} else {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
open (STDERR, "| logger -t $program -p kern.info") || die;
debug "Non Interactive startup";
foreach my $k (qw(
XBUS_NAME
XBUS_NUMBER
XBUS_MODEL_STRING
UNIT_NUMBER
UNIT_TYPE
UNIT_SUBUNITS
UNIT_SUBUNITS_DIR
XBUS_REVISION
XBUS_CONNECTOR
XBUS_LABEL)) {
unless(defined $ENV{$k}) {
logit "Missing ENV{$k}\n";
die;
}
}
logit "XBUS_MODEL_STRING='$ENV{XBUS_MODEL_STRING}'";
if ($ENV{XBUS_MODEL_STRING} =~ m{.*/.*/201}) {
$eeprom_release_201 = 1;
}
$chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs",
$ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
$command = "/proc/xpp/$ENV{XBUS_NAME}/command";
if(! -f $chipregs) {
my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
$chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
if -f $chipregs;
}
$ring_registers = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/fxs_ring_registers",
$ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
logit "OLD DRIVER: missing '$ring_registers' -- fallback to hard-coded defaults"
unless -f $ring_registers;
}
sub set_output() {
my $output;
if($opts{o}) {
$output = $opts{o};
} else {
# No subunits in FXS (everything is subunit 0)
$output = $chipregs;
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
my $oldfh = select REG;
main::logit "# Setting output" if $opts{o};
return $oldfh;
}
sub mysleep($) {
my $timeout = shift;
select(undef,undef,undef,$timeout);
}
package FXS;
sub gen {
my $fmt = shift;
$| = 1;
printf "$fmt\n", @_;
}
my @SlicNums;
sub write_to_slic_file($) {
my $write_str = shift;
open(SLICS,">$chipregs") or
die("Failed writing to chipregs file $chipregs");
print SLICS $write_str;
close(SLICS) or die "Failed writing '$write_str' to '$chipregs': $!";
main::mysleep(0.001);
}
sub write_to_ring_register($) {
my $write_str = shift;
open(SLICS,">$ring_registers") or
die("Failed writing to ring_registers file $ring_registers");
print SLICS $write_str;
close(SLICS) or die "Failed writing '$write_str' to '$ring_registers': $!";
main::mysleep(0.001);
}
sub read_reg($$$;$) {
my $slic = shift;
my $addr = shift;
my $direct = shift;
my $bits_shift = shift;
$bits_shift = 0 unless defined $bits_shift;
my $addr_low;
my $addr_high;
main::debug("read_reg: $slic, $addr, $direct");
$addr_low = $addr & 0xFF;
$addr_high = $addr >> 8;
my $str;
if ($direct eq 'D') {
$str = sprintf "%s RD %02X",
$slic, $addr_low;
} else {
$str = sprintf "%s RR %02X %02X",
$slic, $addr_low, $addr_high;
}
write_to_slic_file($str);
my $retries = 10;
my $reply = "";
# If the command queue is long, we may need to wait...
WAIT_RESULTS:
{
my @results;
# The time to sleep is a tradeoff:
# - Too long is a waste of time.
# - Too short will cause many retries, wastes time.
# So the current value (after trial and error) is...
main::mysleep(0.013);
open(SLICS,$chipregs) or
die("Failed reading from chipregs file $chipregs");
while(<SLICS>){
s/#.*//;
next unless /\S/;
if ($direct eq 'D') {
@results = /^\s*(\d+)\s+[RW][DR]\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]*)/;
} else {
@results = /^\s*(\d+)\s+[RW][DR]\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]*)/;
}
if(($direct eq 'D' && @results != 4) || ($direct eq 'R' && @results != 7)) {
main::logit "Failed reading from '$chipregs' ($direct, $slic,$addr)";
die;
}
}
close(SLICS);
my $read_addr;
if ($direct eq 'D') {
$read_addr = hex($results[1]);
} else {
$read_addr = hex(sprintf "0x$results[2]$results[1]");
}
if($results[0] ne $slic || $read_addr ne $addr) {
# We read obsolete values, need to wait some more
if(--$retries) {
main::debug "$slic R$direct $addr -- retry (@results, $read_addr)";
redo WAIT_RESULTS;
} else {
main::logit "Failed: $slic R$direct $addr returned @results, $addr";
die;
}
}
# Good.
$results[0] = "";
$results[1] = "";
if ($direct eq 'R') {
$results[2] = "";
}
foreach my $val (@results) {
$reply = sprintf("%s%s", $val, $reply);
}
$reply = hex(sprintf("0x%s", $reply));
}
return $reply >> $bits_shift;
}
# TODO: rearange arguments
sub write_reg{#($$$) {
my $slic = shift;
my $reg = shift;
my $val = shift;
my $str = sprintf "%s WD %02X %02X",
$slic, $reg, $val;
main::debug("write_reg: $slic, $reg, $val");
write_to_slic_file($str);
}
#
# BITS:
# 3 - port num
# 1 - read/write
# 1 - Register / RAM
# 11 - address
# 29 - data
sub write_ram($$$$) {
my $slic = shift;
my $addr = shift;
my $value = shift;
my $bits_shift = shift;
my $addr_low;
my $addr_high;
my $value_0;
my $value_1;
my $value_2;
my $value_3;
my $log_output = sprintf("write_ram: %s, %4d, 0x%08X", $slic, $addr, $value);
main::debug($log_output);
$value = $value << $bits_shift;
$addr_low = $addr & 0xFF;
$addr_high = $addr >> 8;
$value_0 = $value & 0xFF;
$value >>= 8;
$value_1 = $value & 0xFF;
$value >>= 8;
$value_2 = $value & 0xFF;
$value >>= 8;
$value_3 = $value & 0xFF;
my $str = sprintf "%s WR %02X %02X %02X %02X %02X %02X",
$slic, $addr_low, $addr_high,
$value_0, $value_1, $value_2, $value_3;
write_to_slic_file($str);
}
sub set_user_mode {
my $slic = shift;
my $on = shift;
my $current = read_reg($slic, 0x7E, 'D');
$current &= 0x1;
$on &= 0x1;
main::debug("::set_user_mode($slic, $on): " . $current . " -> " . $on . "\n");
return 1 if $current == $on;
write_reg($slic, 126, 0x02);
write_reg($slic, 126, 0x08);
write_reg($slic, 126, 0x0E);
write_reg($slic, 126, 0x00);
return 1;
}
sub init_early() {
# I/O Expander initialization
$expander_cmd = sprintf "echo 0A 00 0F %1d0 05 08 00 00 00 FF > %s",
$ENV{UNIT_NUMBER}, $command; # enable outputs for Greed LEDs
system("$expander_cmd");
$expander_cmd = sprintf "echo 0A 00 0F %1d0 05 08 01 00 AA 55 > %s",
$ENV{UNIT_NUMBER}, $command; # enable outputs for Red LEDs and relays
system("$expander_cmd");
$expander_cmd = sprintf "echo 0A 00 0F %1d0 05 08 0D 00 AA AA > %s",
$ENV{UNIT_NUMBER}, $command; # enable pull-ups for inputs
system("$expander_cmd");
}
sub load_patch($) {
my $slics_ref = shift;
my @slics = @{ $slics_ref };
my $slic;
main::debug "Loading patch based on si3226x_patch_C_TSS_ISO_2014JUN18.c";
foreach $slic (@slics) {
FXS::set_user_mode($slic, 1); # Turn on user mode
}
write_reg('*', 81, 0x00); # JMPEN, disable the patch
main::debug "=====Patch data======";
my @patch_data_array = (
141541,
540867,
141541,
543427,
141541,
553155,
141541,
577731,
141541,
579779,
141541,
581315,
141541,
592579,
141541,
633027,
141541,
637635,
141541,
639683,
141541,
650947,
141541,
651459,
141541,
651971,
141541,
652483,
141541,
652995,
141541,
653507,
736,
491712,
452200,
141541,
491200,
5733,
524290,
142565,
550083,
3685,
519266,
5220,
144098,
550083,
3685,
524291,
141541,
551619,
5221,
3682,
524292,
5,
141541,
135362,
98021,
727745,
474213,
17637,
557251,
101093,
557251,
473701,
515653,
843365,
188002,
843355,
145125,
560835,
524290,
660069,
518053,
517224,
518244,
142565,
564419,
524288,
521733,
843365,
188002,
524315,
145125,
568003,
843365,
522850,
523387,
147685,
573123,
522363,
145125,
575171,
521826,
141541,
575683,
518757,
521826,
141541,
575683,
521824,
522245,
522338,
141541,
716481,
173669,
523845,
141541,
730304,
523877,
141541,
690368,
614117,
588995,
457221,
558181,
457122,
457333,
143077,
588995,
144608,
587971,
524292,
141541,
588483,
524304,
671746,
558181,
410018,
437365,
143586,
100034,
141541,
98498,
550117,
619715,
558181,
410018,
403061,
143077,
619715,
524290,
143589,
608963,
402533,
524290,
400901,
29189,
431717,
408133,
432741,
406085,
392805,
407621,
792165,
405573,
406629,
792133,
408677,
431680,
432645,
409189,
392785,
402949,
141541,
630979,
560741,
400482,
398852,
143077,
615107,
402533,
398946,
400901,
29186,
400389,
141541,
630979,
400997,
262242,
143077,
618691,
524291,
400901,
29189,
141541,
630979,
558181,
407458,
524309,
694789,
558085,
694789,
403045,
524290,
143077,
630979,
405605,
792133,
408165,
431685,
406117,
432709,
407653,
392768,
402949,
694789,
560645,
694789,
743525,
119426,
141541,
1003201,
560741,
524290,
143584,
636099,
141541,
191682,
694789,
141541,
859842,
171109,
170565,
141541,
963776,
524291,
144613,
641731,
199685,
667365,
644803,
431717,
197189,
136805,
198725,
170597,
262242,
524291,
144613,
647875,
170501,
667365,
886464,
136805,
180293,
141541,
886464,
524293,
524293,
524293,
524293,
524293,
524293,
);
write_ram('*', 1358, 0x00000000, 3); # PRAM_ADDR, reset the patch RAM address
foreach my $val (@patch_data_array) {
write_ram('*', 1359, $val, 12); # PRAM_DATA, shl 12, addr auto inc
}
main::debug "=====Patch entries======"; # lowest 8 entries are registers
my @patch_entries_array = (
950,
4347,
3431,
1425,
1347,
4287,
4006,
4469,
1881,
1720,
);
my $jmp_table_low = 82;
my $jmp_table_high = 1597;
foreach my $val (@patch_entries_array) {
last if $val == 0;
if ($jmp_table_low <= 97) {
write_reg('*', $jmp_table_low, $val & 0xFF);# JMPnLO
$jmp_table_low++;
write_reg('*', $jmp_table_low, $val >> 8 );# JMPnHI
$jmp_table_low++;
} else {
write_ram('*', $jmp_table_high, $val & 0x1FFF, 3); # shl 3
$jmp_table_high++;
}
}
write_ram('*', 448, 0x06182014, 3); # PATCH_ID, shl 3, a unique code which is a hash of the patch.
main::debug "=====Patch support======";
my @patch_support_addr_array = (
800,
795,
799,
798,
794,
787,
786,
782,
892,
893,
925,
926,
1014,
1020,
1021,
1022,
333,
334,
352,
);
my @patch_support_data_array = (
0x200000,
0x7D80000,
0x69580EA,
0x82C58C,
0x1500000,
0x0,
0x320000,
0x0,
0x400000,
0x0,
0xA00000,
0x1F00000,
0x2D8000,
0x0,
0x2075F60,
0x220335B,
0x0,
0x0,
0x0,
);
for (my $i = 0; $i < @patch_support_addr_array; $i++) {
my $addr = $patch_support_addr_array[$i];
my $val = $patch_support_data_array[$i];
write_ram('*', $addr, $val, 3);
}
if ($settings{debug}) {
foreach $slic (@slics) {
main::debug "=====Verify patch=======";
my $read_val;
# PRAM_ADDR, reset the patch RAM address:
write_ram($slic, 1358, 0x00000000, 3);
foreach my $val (@patch_data_array) {
# PRAM_DATA, shr 12, addr auto inc
$read_val = read_reg($slic, 1359, 'R', 12);
if ($val != $read_val) {
printf "0x%X =? 0x%X\n", $val, $read_val;
printf "patch verification failed\n";
exit 0;
}
}
main::debug "Patch has been verified!";
main::debug "=====Verify patch entries=======";
$jmp_table_low = 82;
$jmp_table_high = 1597;
foreach my $val (@patch_entries_array) {
last if $val == 0;
if ($jmp_table_low <= 97) {
$read_val = read_reg($slic, $jmp_table_low, 'D');# JMPnLO
$jmp_table_low++;
$read_val |= read_reg($slic, $jmp_table_low, 'D') << 8;# JMPnHI
$jmp_table_low++;
} else {
$read_val = read_reg($slic, $jmp_table_high, 'R', 3); # PRAM_DATA, shr 3
$read_val &= 0x1FFF;
$jmp_table_high++;
}
if ($val != $read_val) {
printf "0x%X =? 0x%X\n", $val, $read_val;
printf "patch entries verification failed\n";
exit 0;
}
}
main::debug "Patch entries has been verified!";
main::debug "=====Verify patch support=======";
for (my $i = 0; $i < @patch_support_addr_array; $i++) {
my $addr = $patch_support_addr_array[$i];
my $val = $patch_support_data_array[$i];
$read_val = read_reg($slic, $addr, 'R', 3);
if ($val != $read_val) {
printf "0x%X =? 0x%X\n", $val, $read_val;
printf "Patch support verification failed\n";
exit 0;
}
}
main::debug "patch support has been verified!";
}
}
write_reg('*', 81, 0x01); # JMPEN, enable the patch
write_reg('*', 05, 0x00); # RAM_ADDR_HI, back to normal RAM access
foreach $slic (@slics) {
FXS::set_user_mode($slic, 0); # Turn off user mode
}
}
sub load_general_params($) {
my $slics_ref = shift;
my @slics = @{ $slics_ref };
my $slic;
main::debug "Loading patch based on si3226x_patch_C_TSS_ISO_2014JUN18.c";
foreach $slic (@slics) {
FXS::set_user_mode($slic, 1); # Turn on user mode
}
write_reg('*', 47, 0x00); # ENHANCE
write_reg('*', 80, 0x2F); # AUTO
write_ram('*', 764, 0x0050C480, 3); #BAT_HYST
# Ringing parameters 65Vrms 0Vdc 20Hz LPR
# Loop = 500.0 ft @ 0.044 ohms/ft, REN = 5, Rcpe = 600 ohms
# Rprot = 30 ohms, Type = LPR, Waveform = SINE
write_ram('*', 637, 0x15E5200E, 3); #ringing impedance = 100 ohms
write_ram('*', 766, 0xA3D705, 3); #VBATL_EXPECT 10 V
write_ram('*', 767, 0xA3D705, 3); #VBATH_EXPECT 10 V
write_ram('*', 768, 0x5ED285F, 3); #VBATR_EXPECT 92.6 V
write_ram('*', 768, 0xFFF0000, 3); #PWRSAVE_TIMER
write_ram('*', 916, 0x0F5C28F, 3); #OFFHOOK_THRESH
write_ram('*', 919, 0x00F00000, 3); #VBAT_TRACK_MIN
write_ram('*', 920, 0x02000000, 3); #VBAT_TRACK_MIN_RNG
write_ram('*', 970, 0x00800000, 3); #THERM_DBI
write_ram('*', 1004, 0x00F18900, 3); #DCDC_VERR
write_ram('*', 1005, 0x0080C480, 3); #DCDC_VERR_HYST
write_ram('*', 1006, 0x00800000, 3); #DCDC_OITHRESH_LO
write_ram('*', 1007, 0x01F00000, 3); #DCDC_OITHRESH_HI
write_ram('*', 1540, 0x00200000, 3); #PD_UVLO
write_ram('*', 1541, 0x00300000, 3); #PD_OVLO
write_ram('*', 1542, 0x00200000, 3); #PD_OCLO
write_ram('*', 1545, 0x00C00000, 3); #DCDC_UVHYST, (94v - 90v -1) / 0.257v = 12
write_ram('*', 1546, 0x03D00000, 3); #DCDC_UVTHRESH, 94v / 1.543v = 61
write_ram('*', 1547, 0x1200000, 3); #DCDC_OVTHRESH
write_ram('*', 1554, 0x07700000, 3); #DCDC_UVPOL
write_ram('*', 1558, 0x00000000, 3); #DCDC_VREF_CTRL
write_ram('*', 1560, 0x00200000, 3); #DCDC_RNGTYPE
write_ram('*', 1585, 0x00300000, 3); #DCDC_ANA_GAIN
write_ram('*', 1586, 0x00300000, 3); #DCDC_ANA_TOFF
write_ram('*', 1587, 0x00100000, 3); #DCDC_ANA_TONMIN
write_ram('*', 1588, 0x00FFC000, 3); #DCDC_ANA_TONMAX
write_ram('*', 1589, 0x00F00000, 3); #DCDC_ANA_DSHIFT
write_ram('*', 1590, 0x0FDA4000, 3); #DCDC_ANA_LPOLY
write_ram('*', 759, 0x07FEB800, 3); # COEF_P_HVIC
write_ram('*', 756, 0x0048D15B, 3); # P_TH_HVIC
write_ram('*', 967, 0x03A2E8BA, 3); # SCALE_KAUDIO
# /* GC RAM locations that moved from RevB to RevC */
write_ram('*', 1018, 0x03000000, 3); # LKG_OFHK_OFFSET
write_ram('*', 1017, 0x05000000, 3); # LKG_LB_OFFSET
write_ram('*', 1013, 0x02200000, 3); # VBATH_DELTA
write_ram('*', 1012, 0x03700000, 3); # UVTHRESH_MAX
write_ram('*', 1011, 0x04F80200, 3); # UVTHRESH_SCALE
write_ram('*', 1010, 0x00A23000, 3); # UVTHRESH_BIAS
# /* Hardcoded mods to default settings */
write_reg('*', 98, 0x80); #PDN
write_ram('*', 626, 0x723F235, 3); # ROW0_C2
write_ram('*', 627, 0x57A9804, 3); # ROW1_C2
write_ram('*', 918, 0x36000, 3); # XTALK_TIMER
write_ram('*', 1616, 0x1100000, 3); # DCDC_CPUMP_LP_MASK
#/* Smart VOV Default Settings - set here in case no ring preset is loaded */
write_ram('*', 973, 0xFFFFFF, 3); # VOV_DCDC_SLOPE
write_ram('*', 974, 0xA18937, 3); # VOV_DCDC_OS
write_ram('*', 975, 0xE49BA5, 3); # VOV_RING_BAT_MAX
write_ram('*', 516, 0x10038D, 3); # VDIFFLPF
write_ram('*', 513, 0x4EDDB9, 3); # ILOOPLPF
write_ram('*', 514, 0x806D6, 3); # ILONGLPF
write_ram('*', 517, 0x10059F, 3); # VCMLPF
write_ram('*', 708, 0xF0000, 3); # CM_SPEEDUP_TIMER
write_ram('*', 709, 0x106240, 3); # VCM_TH
# /* Prevent Ref Osc from powering down in PLL Freerun mode (pd_ref_osc) */
# write_ram('*', 709, 0x106240, 3); # PWRSAVE_CTRL_LO shall be arithmetic here
# batType == VCM_HYST
write_ram('*', 1565, 0xC00000, 3); #
write_ram('*', 750, 0x0306280, 3); #VCM_HYST
write_ram('*', 971, 0x2A00000, 3); #LPR_SCALE
write_ram('*', 972, 0x061EB80, 3); #LPR_CM_OS
write_ram('*', 1565, 0x0A00000, 3); #DCDC_OIMASK
write_ram('*', 1643, 0x000000, 3); #DCDC_OV_DEBOUNCE
write_ram('*', 1641, 0x0D00000, 3); #DCDC_UV_DEBOUNCE
write_ram('*', 1512, 0x00200000, 3); # PD_OFFLD_DAC
write_ram('*', 1513, 0x00200000, 3); # PD_OFFLD_GM
write_ram('*', 1592, 0x0300000, 3); #DCDC_PD_ANA
write_ram('*', 897, 0x0480CBF, 3); #P_TH_OFFLOAD
write_reg('*', 35, 0x03); #OFFLOAD
write_ram('*', 1553, 0x00000000, 3); #DCDC_SWDRV_POL
write_ram('*', 860, 0x008B9ACA, 3); # IRING_LIM (90.000 mA)
foreach $slic (@slics) {
FXS::set_user_mode($slic, 0); # Turn on user mode
}
# Loading Coeff before cal to ensure accurate zsynth results in OHT
# This set of coefficients are for the following input parameters:
# Device = Si3217x, R1 = 600, R2 = 0, C = 0, R_surge = 20, R_fuse = 24, 10.txt
# Generated on 9/30/2009 2:51:17 PM
# TXACEQ
write_ram('*', 540, 0x07F55480, 3); #TXACEQ_CO
write_ram('*', 541, 0x000D6400, 3); #TXACEQ_C1
write_ram('*', 542, 0x00011A00, 3); #TXACEQ_C2
write_ram('*', 543, 0x1FFD7F00, 3); #TXACEQ_C3
# RXACEQ
write_ram('*', 546, 0x07F04900, 3); #RXACEQ_CO
write_ram('*', 547, 0x00126A00, 3); #RXACEQ_C1
write_ram('*', 548, 0x1FFE1D00, 3); #RXACEQ_C2
write_ram('*', 549, 0x1FFC9480, 3); #RXACEQ_C3
# ECFIR/ECIIR
write_ram('*', 563, 0x0012A580, 3); #ECFIR_C2
write_ram('*', 564, 0x1FE59900, 3); #ECFIR_C3
write_ram('*', 565, 0x01BCB180, 3); #ECFIR_C4
write_ram('*', 566, 0x00790780, 3); #ECFIR_C5
write_ram('*', 567, 0x02113380, 3); #ECFIR_C6
write_ram('*', 568, 0x1F172380, 3); #ECFIR_C7
write_ram('*', 569, 0x00805080, 3); #ECFIR_C8
write_ram('*', 570, 0x1FD6E600, 3); #ECFIR_C9
write_ram('*', 571, 0x1FFDF800, 3); #ECIIR_B0
write_ram('*', 572, 0x00010980, 3); #ECIIR_B1
write_ram('*', 573, 0x0E46D280, 3); #ECIIR_A1
write_ram('*', 574, 0x19B4F900, 3); #ECIIR_A2
# ZSYNTH
write_ram('*', 653, 0x007A8C00, 3); #ZSYNTH_B0
write_ram('*', 654, 0x1F0BB880, 3); #ZSYNTH_B1
write_ram('*', 655, 0x0079BD00, 3); #ZSYNTH_B2
write_ram('*', 656, 0x0FF66D00, 3); #ZSYNTH_A1
write_ram('*', 657, 0x18099080, 3); #ZSYNTH_A2
write_reg('*', 45, 0x59); #RA
# TXGAIN/RXGAIN
write_ram('*', 544, 0x08769A80, 3); #TXACGAIN
write_ram('*', 545, 0x0141E080, 3); #RXACGAIN
write_ram('*', 906, 0x0141E080, 3); #RXACGAIN_SAVE
# RXACHPF
write_ram('*', 658, 0x07AC0400, 3); #RXACHPF_B0_1
write_ram('*', 659, 0x1853FC80, 3); #RXACHPF_B1_1
write_ram('*', 660, 0x07580880, 3); #RXACHPF_A1_1
write_ram('*', 666, 0x8000000, 3); #RXACHPF_GAIN
foreach $slic (@slics) {
FXS::set_user_mode($slic, 1); # Turn on user mode
}
write_reg('*', 98, 0x80); # Power up MADC
foreach $slic (@slics) {
FXS::set_user_mode($slic, 0); # Turn off user mode
}
}
sub calibrate_slics($$$$) {
my $slic = shift;
my $cal0 = shift;
my $cal1 = shift;
my $cal2 = shift;
main::debug "Calibrating channel $slic";
write_reg($slic, 26, $cal0); # CAL0
write_reg($slic, 27, $cal1); # CAL1
write_reg($slic, 28, $cal2); # CAL2
write_reg($slic, 29, 0x80); # CAL3, CAN_EN
# wait until all slics have finished calibration, or for timeout
# time periods in seconds:
my $sleep_time = 0.001;
my $timeout_time = 0.600; # Maximum from the spec
my @curr_slics;
my $sleep_cnt = 0;
push(@curr_slics, $slic);
CALIB_LOOP:
while(1) {
main::mysleep($sleep_time);
my @next_slics;
for my $slic (@curr_slics) {
main::debug("checking slic $slic");
my $val = read_reg($slic, 29, 'D');
push(@next_slics, $slic) if ($val & 0x80) != 0;
}
@curr_slics = @next_slics;
last unless @curr_slics;
if ($sleep_cnt * $sleep_time > $timeout_time) {
main::logit("Auto Calibration: Exiting on timeout: $timeout_time.");
last CALIB_LOOP;
}
main::debug("auto_calibrate not done yet($sleep_cnt): @curr_slics");
$sleep_cnt++;
}
#log_calib_params();
}
sub dc_powerup($) {
my $slic = shift;
FXS::set_user_mode($slic, 1); # Turn on user mode
write_ram($slic, 1538, 0x700000, 3); # PD_DCDC, In case OV or UV previously occurred
# write_ram($slic, 1555, 0x100000, 3); # DCDC_CPUMP, Turn on charge pump
main::mysleep(0.010);
# write_ram($slic, 1538, 0x00600000, 3); # start up converter
main::mysleep(0.500);
write_ram($slic, 1555, 0x000000, 3); # DCDC_CPUMP, Turn off charge pump
write_ram($slic, 1542, 0x300000, 3); # PD_OCLO
write_ram($slic, 1551, 0x00000000, 3); # sClear DCDC status
main::mysleep(0.030);
write_ram($slic, 1538, 0x00400000, 3);
FXS::set_user_mode($slic, 0); # Turn off user mode
}
sub read_defaults() {
if(XppConfig::read_config(\%settings)) {
main::logit "Defaults from $settings{xppconf}";
} else {
main::logit "No defaults file, use hard-coded defaults.";
}
}
sub soft_reset() {
write_reg('*', 1, 0x03); # RESET
}
# Try to identify which slics are valid
sub check_slics() {
my @slics;
main::debug "check_slics()";
foreach my $slic (0 .. 7) {
my $value = read_reg($slic, 0, 'D');
#main::logit sprintf "Slic($slic): RD 00 0x%X\n", $value;
next if($value != 0xC3);
write_reg($slic, 14, 0x40);
$value = read_reg($slic, 14, 'D');
#main::logit sprintf "Slic($slic): RD 14 0x%X\n", $value;
next if($value != 0x40);
$value = read_reg($slic, 3, 'D') & 0x1F;
#main::logit sprintf "Slic($slic): RD 03 0x%X\n", $value;
push(@slics, $slic) if $value == 0x1F;
}
main::logit "Found " . scalar(@slics) . " SLICS (@slics)";
return @slics;
}
sub load_custom_preset($) {
my $slics_ref = shift;
my @slics = @{ $slics_ref };
my $slic;
main::debug "Loading patch based on si3226x_patch_C_TSS_ISO_2014JUN18.c";
foreach $slic (@slics) {
FXS::set_user_mode($slic, 1); # Turn on user mode
}
write_ram('*', 755, 0x00050000, 3); #RTPER
write_ram('*', 844, 0x7EFE000, 3); #RINGFR = 20Hz
write_ram('*', 845, 0x00208847, 3); #RINGAMP = 53 Vrms open circuit with 100ohm ring impedance
write_ram('*', 846, 0x00000000, 3); #RINGPHAS
write_ram('*', 843, 0x00000000, 3); #RINGOF
write_ram('*', 637, 0x15E5200E, 3); #SLOPE_RING (100.000 ohms)
write_ram('*', 848, 0x007B9068, 3); #RTACTH (68.236 mA)
write_ram('*', 847, 0x0FFFFFFF, 3); #RTDCTH (450.000 mA) */
write_ram('*', 850, 0x00006000, 3); #RTACDB (75.000 ms)
write_ram('*', 849, 0x00006000, 3); #RTDCDB (75.000 ms)
write_ram('*', 753, 0x00C49BA0, 3); # VOV_RING_BAT (12.000 v)
write_ram('*', 896, 0x00000000, 3); # VOV_RING_GND (0.000 v)
write_ram('*', 975, 0xE49BA5, 3);#vov_ring_bat_max = ~14V
write_reg('*', 39, 0x80); #RINGTALO
write_reg('*', 40, 0x3E); #RINGTAHI
write_reg('*', 41, 0x00); #RINGTILO
write_reg('*', 42, 0x7D); #RINGTIHI
write_reg('*', 38, 0x80); #RINGCON Both timers are disabled; enable LPR
write_ram('*', 483, 0x28C000, 3);#delta_vcm: This means ring side needs 2v extra.
write_ram('*', 973, 0xFFFFFF, 3);# slope_vov_dcdc
write_ram('*', 974, 0xA18937, 3);# vov_dcdc_os = ~10v
write_ram('*', 509, 0x00C49BA0, 3);# VOV_RING_BAT (12.000 v)
write_ram('*', 975, 0xE49BA5, 3);#vov_ring_bat_max = ~14V
write_ram('*', 971, 0x2A00000, 3);# scale for LPR amplitude, full scale 28-bit
write_ram('*', 972, 0x61EB80, 3);# 6v CM offset
write_ram('*', 970, 0x800000, 3);#
# DC_FEED:
write_ram('*', 634, 0x1C8A024C, 3); # SLOPE_VLIM
write_ram('*', 635, 0x1E3081AA, 3); # SLOPE_RFEED
write_ram('*', 636, 0x0040A0E0, 3); # SLOPE_ILIM
write_ram('*', 638, 0x1B27130B, 3); # SLOPE_DELTA1
write_ram('*', 639, 0x1DD87A3E, 3); # SLOPE_DELTA2
# write_ram('*', 640, 0x043AA4A6, 3); # V_VLIM (36.000 v)
write_ram('*', 640, 0x034A1036, 3); # V_VLIM (28.000 v)
write_ram('*', 641, 0x03A446AC, 3); # V_RFEED (31.000 v)
write_ram('*', 642, 0x034A0E48, 3); # V_ILIM (28.000 v)
write_ram('*', 643, 0x01363429, 3); # CONST_RFEED (15.000 mA)
write_ram('*', 644, 0x005D0FA6, 3); # CONST_ILIM = 20 mA
write_ram('*', 645, 0x00222A30, 3); # I_VLIM = 0.000 mA
write_ram('*', 853, 0x005B0AFB, 3); # LCRONHK (10.000 mA)
write_ram('*', 852, 0x006D4060, 3); # LCROFFHK (12.000 mA)
write_ram('*', 701, 0x00008000, 3); # LCRDBI (5.000 ms)
write_ram('*', 858, 0x0048D595, 3); # LONGHITH (8.000 mA)
write_ram('*', 859, 0x003FBAE2, 3); # LONGLOTH (7.000 mA)
write_ram('*', 702, 0x00008000, 3); # LONGDBI (5.000 ms)
write_ram('*', 854, 0x000F0000, 3); # LCRMASK (150.000 ms)
write_ram('*', 855, 0x00080000, 3); # LCRMASK_POLREV (80.000 ms)
write_ram('*', 856, 0x00140000, 3); # LCRMASK_STATE (200.000 ms)
write_ram('*', 857, 0x00140000, 3); # LCRMASK_LINECAP (200.000 ms)
write_ram('*', 748, 0x01BA5E35, 3); # VCM_OH (27.000 v)
write_ram('*', 752, 0x0051EB85, 3); # VOV_BAT (5.000 v)
write_ram('*', 751, 0x00415F45, 3); # VOV_GND (3.990 v)
write_reg('*', 46, 0x04); # zcal_en
write_reg('*', 23, 0x10); # DTMF_EN = 1 Enable Interupts in IRQ2 Register 19
write_reg('*', 24, 0x03); # P_HVIC_IE = 1, P_THERM_IE = 1 Enable Interupts in IRQ3 Register 20
write_reg('*', 66, 0x00); # USERSTAT
write_reg('*', 71, 0x00); # DIAG1
write_ram('*', 799, 95 * 1074 * 1000, 3); #PRAM_VBATH_NEON = -95 V
write_ram('*', 786, 70 * 65536, 3); #PRAM_LCRMASK_MWI = 70 mSec
foreach $slic (@slics) {
FXS::set_linefeed($slic, 1);
}
write_ram('*', 918, 0x36000, 3);
foreach $slic (@slics) {
FXS::set_user_mode($slic, 1); # Turn on user mode
}
write_ram('*', 1018, 0x03000000, 3); # LKG_OFHK_OFFSET
write_ram('*', 1017, 0x05000000, 3); # LKG_LB_OFFSET
foreach $slic (@slics) {
if (($slic & 0x01) == 0) {
FXS::set_linefeed($slic, 0);
write_ram($slic, 1538, 0x00600000, 3);
} else {
write_ram($slic & 0xFE, 1538, 0x00400000, 3);
}
FXS::set_user_mode($slic, 0); # Turn off user mode
}
}
sub configure_pcm($) {
my $slic = shift;
main::debug "Configure_pcm()";
my $pcm_offset = $slic * 8;
write_reg($slic, 12, $pcm_offset); #PCMTXLO
write_reg($slic, 13, 0x00); #PCMTXHI
write_reg($slic, 14, $pcm_offset); #PCMTXLO
write_reg($slic, 15, 0x00); #PCMTXHI
write_reg($slic, 11, 0x11); #PCMMODE, u-Law
# write_reg($slic, 43, 0x00); #LOOPBACK
# write_reg($slic, 44, 0x00); #DIGCON
}
sub set_linefeed($$) {
my $slic = shift;
my $lfd = shift;
write_reg($slic, 30, $lfd); #LINEFEED
}
sub overwrite_ring_registers() {
}
package main;
main::logit "Starting '$0' (@SlicNums)\n";
FXS::read_defaults();
FXS::soft_reset();
@SlicNums = FXS::check_slics();
FXS::init_early();
FXS::load_patch(\@SlicNums);
FXS::load_general_params(\@SlicNums);
if($settings{fxs_skip_calib}) {
main::logit "==== WARNING: SKIPPED SLIC CALIBRATION =====";
} else {
foreach my $slic (@SlicNums) {
FXS::calibrate_slics($slic, 0x00, 0x00, 0x01);
}
main::mysleep(0.060);
foreach my $slic (@SlicNums) {
FXS::dc_powerup($slic);
FXS::calibrate_slics($slic, 0x00, 0xC0, 0x18); # remaining cals (except mads, lb)
}
main::mysleep(0.700);
foreach my $slic (@SlicNums) {
FXS::set_linefeed($slic, 0);
FXS::set_linefeed($slic, 1);
}
main::mysleep(0.010);
#FXS::calibrate_slics($slic, 0x0F, 0x00, 0x00); #
main::mysleep(1.000);
}
FXS::load_custom_preset(\@SlicNums);
foreach my $slic (@SlicNums) {
FXS::configure_pcm($slic);
FXS::set_linefeed($slic, 1);
}
set_output;
while(<DATA>) {
chomp;
s/[#;].*$//; # remove comments
s/^\s+//; # trim whitespace
s/\s+$//; # trim whitespace
s/\t+/ /g; # replace tabs with spaces (for logs)
next unless /\S/; # Skip empty lines
main::debug "writing: '$_'";
print "$_\n";
}
close REG;
FXS::overwrite_ring_registers();
main::debug "Ending '$0'";
close STDERR;
exit 0;
# ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
__DATA__