| /* |
| * SBE 2T3E3 synchronous serial card driver for Linux |
| * |
| * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License |
| * as published by the Free Software Foundation. |
| * |
| * This code is based on a driver written by SBE Inc. |
| */ |
| |
| #include <linux/types.h> |
| #include "2t3e3.h" |
| #include "ctrl.h" |
| |
| void t3e3_set_frame_type(struct channel *sc, u32 mode) |
| { |
| if (sc->p.frame_type == mode) |
| return; |
| |
| if (sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP) { |
| dev_err(&sc->pdev->dev, "SBE 2T3E3: changing frame type during active connection\n"); |
| return; |
| } |
| |
| exar7300_set_frame_type(sc, mode); |
| exar7250_set_frame_type(sc, mode); |
| cpld_set_frame_type(sc, mode); |
| |
| sc->p.frame_type = mode; |
| } |
| |
| void t3e3_set_loopback(struct channel *sc, u32 mode) |
| { |
| u32 tx, rx; |
| |
| if (sc->p.loopback == mode) |
| return; |
| |
| tx = sc->p.transmitter_on; |
| rx = sc->p.receiver_on; |
| if (tx == SBE_2T3E3_ON) |
| dc_transmitter_onoff(sc, SBE_2T3E3_OFF); |
| if (rx == SBE_2T3E3_ON) |
| dc_receiver_onoff(sc, SBE_2T3E3_OFF); |
| |
| /* stop current loopback if any exists */ |
| switch (sc->p.loopback) { |
| case SBE_2T3E3_LOOPBACK_NONE: |
| break; |
| case SBE_2T3E3_LOOPBACK_ETHERNET: |
| dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_OFF); |
| break; |
| case SBE_2T3E3_LOOPBACK_FRAMER: |
| exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_OFF); |
| break; |
| case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: |
| case SBE_2T3E3_LOOPBACK_LIU_ANALOG: |
| case SBE_2T3E3_LOOPBACK_LIU_REMOTE: |
| exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_OFF); |
| break; |
| default: |
| return; |
| } |
| |
| switch (mode) { |
| case SBE_2T3E3_LOOPBACK_NONE: |
| break; |
| case SBE_2T3E3_LOOPBACK_ETHERNET: |
| dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_INTERNAL); |
| break; |
| case SBE_2T3E3_LOOPBACK_FRAMER: |
| exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_ON); |
| break; |
| case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: |
| exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_DIGITAL); |
| break; |
| case SBE_2T3E3_LOOPBACK_LIU_ANALOG: |
| exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_ANALOG); |
| break; |
| case SBE_2T3E3_LOOPBACK_LIU_REMOTE: |
| exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_REMOTE); |
| break; |
| default: |
| return; |
| } |
| |
| sc->p.loopback = mode; |
| |
| if (tx == SBE_2T3E3_ON) |
| dc_transmitter_onoff(sc, SBE_2T3E3_ON); |
| if (rx == SBE_2T3E3_ON) |
| dc_receiver_onoff(sc, SBE_2T3E3_ON); |
| } |
| |
| |
| void t3e3_reg_read(struct channel *sc, u32 *reg, u32 *val) |
| { |
| u32 i; |
| |
| *val = 0; |
| |
| switch (reg[0]) { |
| case SBE_2T3E3_CHIP_21143: |
| if (!(reg[1] & 7)) |
| *val = dc_read(sc->addr, reg[1] / 8); |
| break; |
| case SBE_2T3E3_CHIP_CPLD: |
| for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) |
| if (cpld_reg_map[i][sc->h.slot] == reg[1]) { |
| *val = cpld_read(sc, i); |
| break; |
| } |
| break; |
| case SBE_2T3E3_CHIP_FRAMER: |
| for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) |
| if (t3e3_framer_reg_map[i] == reg[1]) { |
| *val = exar7250_read(sc, i); |
| break; |
| } |
| break; |
| case SBE_2T3E3_CHIP_LIU: |
| for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) |
| if (t3e3_liu_reg_map[i] == reg[1]) { |
| *val = exar7300_read(sc, i); |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void t3e3_reg_write(struct channel *sc, u32 *reg) |
| { |
| u32 i; |
| |
| switch (reg[0]) { |
| case SBE_2T3E3_CHIP_21143: |
| dc_write(sc->addr, reg[1], reg[2]); |
| break; |
| case SBE_2T3E3_CHIP_CPLD: |
| for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) |
| if (cpld_reg_map[i][sc->h.slot] == reg[1]) { |
| cpld_write(sc, i, reg[2]); |
| break; |
| } |
| break; |
| case SBE_2T3E3_CHIP_FRAMER: |
| for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) |
| if (t3e3_framer_reg_map[i] == reg[1]) { |
| exar7250_write(sc, i, reg[2]); |
| break; |
| } |
| break; |
| case SBE_2T3E3_CHIP_LIU: |
| for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) |
| if (t3e3_liu_reg_map[i] == reg[1]) { |
| exar7300_write(sc, i, reg[2]); |
| break; |
| } |
| break; |
| } |
| } |
| |
| void t3e3_port_get(struct channel *sc, t3e3_param_t *param) |
| { |
| memcpy(param, &(sc->p), sizeof(t3e3_param_t)); |
| } |
| |
| void t3e3_port_set(struct channel *sc, t3e3_param_t *param) |
| { |
| if (param->frame_mode != 0xff) |
| cpld_set_frame_mode(sc, param->frame_mode); |
| |
| if (param->fractional_mode != 0xff) |
| cpld_set_fractional_mode(sc, param->fractional_mode, |
| param->bandwidth_start, |
| param->bandwidth_stop); |
| |
| if (param->pad_count != 0xff) |
| cpld_set_pad_count(sc, param->pad_count); |
| |
| if (param->crc != 0xff) |
| cpld_set_crc(sc, param->crc); |
| |
| if (param->receiver_on != 0xff) |
| dc_receiver_onoff(sc, param->receiver_on); |
| |
| if (param->transmitter_on != 0xff) |
| dc_transmitter_onoff(sc, param->transmitter_on); |
| |
| if (param->frame_type != 0xff) |
| t3e3_set_frame_type(sc, param->frame_type); |
| |
| if (param->panel != 0xff) |
| cpld_select_panel(sc, param->panel); |
| |
| if (param->line_build_out != 0xff) |
| exar7300_line_build_out_onoff(sc, param->line_build_out); |
| |
| if (param->receive_equalization != 0xff) |
| exar7300_receive_equalization_onoff(sc, param->receive_equalization); |
| |
| if (param->transmit_all_ones != 0xff) |
| exar7300_transmit_all_ones_onoff(sc, param->transmit_all_ones); |
| |
| if (param->loopback != 0xff) |
| t3e3_set_loopback(sc, param->loopback); |
| |
| if (param->clock_source != 0xff) |
| cpld_set_clock(sc, param->clock_source); |
| |
| if (param->scrambler != 0xff) |
| cpld_set_scrambler(sc, param->scrambler); |
| } |
| |
| void t3e3_port_get_stats(struct channel *sc, |
| t3e3_stats_t *stats) |
| { |
| u32 result; |
| |
| sc->s.LOC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL) |
| & SBE_2T3E3_FRAMER_VAL_LOSS_OF_CLOCK_STATUS ? 1 : 0; |
| |
| switch (sc->p.frame_type) { |
| case SBE_2T3E3_FRAME_TYPE_E3_G751: |
| case SBE_2T3E3_FRAME_TYPE_E3_G832: |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); |
| sc->s.LOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_LOF ? 1 : 0; |
| sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; |
| #if 0 |
| sc->s.LOS = result & SBE_2T3E3_FRAMER_VAL_E3_RX_LOS ? 1 : 0; |
| #else |
| cpld_LOS_update(sc); |
| #endif |
| sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_E3_RX_AIS ? 1 : 0; |
| sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_FERF ? 1 : 0; |
| break; |
| |
| case SBE_2T3E3_FRAME_TYPE_T3_CBIT: |
| case SBE_2T3E3_FRAME_TYPE_T3_M13: |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); |
| sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIS ? 1 : 0; |
| #if 0 |
| sc->s.LOS = result & SBE_2T3E3_FRAMER_VAL_T3_RX_LOS ? 1 : 0; |
| #else |
| cpld_LOS_update(sc); |
| #endif |
| sc->s.IDLE = result & SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE ? 1 : 0; |
| sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_STATUS); |
| sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FERF ? 1 : 0; |
| sc->s.AIC = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIC ? 1 : 0; |
| sc->s.FEBE_code = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FEBE; |
| |
| sc->s.FEAC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC); |
| break; |
| |
| default: |
| break; |
| } |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_LCV_EVENT_COUNT_MSB) << 8; |
| result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); |
| sc->s.LCV += result; |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FRAMING_BIT_ERROR_EVENT_COUNT_MSB) << 8; |
| result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); |
| sc->s.FRAMING_BIT += result; |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_PARITY_ERROR_EVENT_COUNT_MSB) << 8; |
| result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); |
| sc->s.PARITY_ERROR += result; |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FEBE_EVENT_COUNT_MSB) << 8; |
| result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); |
| sc->s.FEBE_count += result; |
| |
| result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_CP_BIT_ERROR_EVENT_COUNT_MSB) << 8; |
| result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); |
| sc->s.CP_BIT += result; |
| |
| memcpy(stats, &(sc->s), sizeof(t3e3_stats_t)); |
| } |
| |
| void t3e3_port_del_stats(struct channel *sc) |
| { |
| memset(&(sc->s), 0, sizeof(t3e3_stats_t)); |
| } |
| |
| void t3e3_if_config(struct channel *sc, u32 cmd, char *set, |
| t3e3_resp_t *ret, int *rlen) |
| { |
| t3e3_param_t *param = (t3e3_param_t *)set; |
| u32 *data = (u32 *)set; |
| |
| /* turn off all interrupt */ |
| /* cpld_stop_intr(sc); */ |
| |
| switch (cmd) { |
| case SBE_2T3E3_PORT_GET: |
| t3e3_port_get(sc, &(ret->u.param)); |
| *rlen = sizeof(ret->u.param); |
| break; |
| case SBE_2T3E3_PORT_SET: |
| t3e3_port_set(sc, param); |
| *rlen = 0; |
| break; |
| case SBE_2T3E3_PORT_GET_STATS: |
| t3e3_port_get_stats(sc, &(ret->u.stats)); |
| *rlen = sizeof(ret->u.stats); |
| break; |
| case SBE_2T3E3_PORT_DEL_STATS: |
| t3e3_port_del_stats(sc); |
| *rlen = 0; |
| break; |
| case SBE_2T3E3_PORT_READ_REGS: |
| t3e3_reg_read(sc, data, &(ret->u.data)); |
| *rlen = sizeof(ret->u.data); |
| break; |
| case SBE_2T3E3_PORT_WRITE_REGS: |
| #if 0 |
| printk(KERN_DEBUG "SBE_2T3E3_PORT_WRITE_REGS, 0x%x, 0x%x, 0x%x\n", |
| ((int*)data)[0], ((int*)data)[1], ((int*)data)[2]); |
| #endif |
| t3e3_reg_write(sc, data); |
| *rlen = 0; |
| break; |
| case SBE_2T3E3_LOG_LEVEL: |
| *rlen = 0; |
| break; |
| default: |
| *rlen = 0; |
| break; |
| } |
| |
| /* turn on interrupt */ |
| /* cpld_start_intr(sc); */ |
| } |
| |
| void t3e3_sc_init(struct channel *sc) |
| { |
| memset(sc, 0, sizeof(*sc)); |
| |
| sc->p.frame_mode = SBE_2T3E3_FRAME_MODE_HDLC; |
| sc->p.fractional_mode = SBE_2T3E3_FRACTIONAL_MODE_NONE; |
| sc->p.crc = SBE_2T3E3_CRC_32; |
| sc->p.receiver_on = SBE_2T3E3_OFF; |
| sc->p.transmitter_on = SBE_2T3E3_OFF; |
| sc->p.frame_type = SBE_2T3E3_FRAME_TYPE_T3_CBIT; |
| sc->p.panel = SBE_2T3E3_PANEL_FRONT; |
| sc->p.line_build_out = SBE_2T3E3_OFF; |
| sc->p.receive_equalization = SBE_2T3E3_OFF; |
| sc->p.transmit_all_ones = SBE_2T3E3_OFF; |
| sc->p.loopback = SBE_2T3E3_LOOPBACK_NONE; |
| sc->p.clock_source = SBE_2T3E3_TIMING_LOCAL; |
| sc->p.scrambler = SBE_2T3E3_SCRAMBLER_OFF; |
| sc->p.pad_count = SBE_2T3E3_PAD_COUNT_1; |
| } |