]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/sbe-2t3e3/cpld.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / sbe-2t3e3 / cpld.c
diff --git a/drivers/staging/sbe-2t3e3/cpld.c b/drivers/staging/sbe-2t3e3/cpld.c
new file mode 100644 (file)
index 0000000..b0fc2dd
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * 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/delay.h>
+#include "2t3e3.h"
+#include "ctrl.h"
+
+#define bootrom_set_bit(sc, reg, bit)                          \
+       bootrom_write((sc), (reg),                              \
+                     bootrom_read((sc), (reg)) | (bit))
+
+#define bootrom_clear_bit(sc, reg, bit)                                \
+       bootrom_write((sc), (reg),                              \
+                     bootrom_read((sc), (reg)) & ~(bit))
+
+static inline void cpld_set_bit(struct channel *channel, unsigned reg, u32 bit)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+       bootrom_set_bit(channel, CPLD_MAP_REG(reg, channel), bit);
+       spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+}
+
+static inline void cpld_clear_bit(struct channel *channel, unsigned reg, u32 bit)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&channel->card->bootrom_lock, flags);
+       bootrom_clear_bit(channel, CPLD_MAP_REG(reg, channel), bit);
+       spin_unlock_irqrestore(&channel->card->bootrom_lock, flags);
+}
+
+void cpld_init(struct channel *sc)
+{
+       u32 val;
+#if 0
+       /* reset LIU and Framer */
+       val = cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_FRAMER_RESET][sc->h.slot];
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_STATIC_RESET, val);
+       udelay(10000); /* TODO - how long? */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_STATIC_RESET, val);
+#endif
+
+       /* PCRA */
+       val = SBE_2T3E3_CPLD_VAL_CRC32 |
+               cpld_val_map[SBE_2T3E3_CPLD_VAL_LOOP_TIMING_SOURCE][sc->h.slot];
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRA, val);
+
+       /* PCRB */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRB, val);
+
+       /* PCRC */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, val);
+
+       /* PBWF */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, val);
+
+       /* PBWL */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, val);
+
+       /* PLTR */
+       val = SBE_2T3E3_CPLD_VAL_LCV_COUNTER;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PLTR, val);
+       udelay(1000);
+
+       /* PLCR */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PLCR, val);
+       udelay(1000);
+
+       /* PPFR */
+       val = 0x55;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PPFR, val);
+       /* TODO: this doesn't work!!! */
+
+       /* SERIAL_CHIP_SELECT */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, val);
+
+       /* PICSR */
+       val = SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED |
+               SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED |
+               SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, val);
+
+       cpld_start_intr(sc);
+
+       udelay(1000);
+}
+
+void cpld_start_intr(struct channel *sc)
+{
+       u32 val;
+
+       /* PIER */
+       val = SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ENABLE |
+               SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ENABLE;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val);
+#if 0
+       /*
+         do you want to hang up your computer?
+         ENABLE REST OF INTERRUPTS !!!
+         you have been warned :).
+       */
+#endif
+}
+
+void cpld_stop_intr(struct channel *sc)
+{
+       u32 val;
+
+       /* PIER */
+       val = 0;
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val);
+}
+
+void cpld_set_frame_mode(struct channel *sc, u32 mode)
+{
+       if (sc->p.frame_mode == mode)
+               return;
+
+       switch (mode) {
+       case SBE_2T3E3_FRAME_MODE_HDLC:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE |
+                              SBE_2T3E3_CPLD_VAL_RAW_MODE);
+               exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF);
+               exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF);
+               break;
+       case SBE_2T3E3_FRAME_MODE_TRANSPARENT:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_RAW_MODE);
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE);
+               exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF);
+               exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF);
+               break;
+       case SBE_2T3E3_FRAME_MODE_RAW:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_RAW_MODE);
+               exar7250_unipolar_onoff(sc, SBE_2T3E3_ON);
+               exar7300_unipolar_onoff(sc, SBE_2T3E3_ON);
+               break;
+       default:
+               return;
+       }
+
+       sc->p.frame_mode = mode;
+}
+
+/* set rate of the local clock */
+void cpld_set_frame_type(struct channel *sc, u32 type)
+{
+       switch (type) {
+       case SBE_2T3E3_FRAME_TYPE_E3_G751:
+       case SBE_2T3E3_FRAME_TYPE_E3_G832:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3);
+               break;
+       case SBE_2T3E3_FRAME_TYPE_T3_CBIT:
+       case SBE_2T3E3_FRAME_TYPE_T3_M13:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3);
+               break;
+       default:
+               return;
+       }
+}
+
+void cpld_set_scrambler(struct channel *sc, u32 mode)
+{
+       if (sc->p.scrambler == mode)
+               return;
+
+       switch (mode) {
+       case SBE_2T3E3_SCRAMBLER_OFF:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                              SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE);
+               break;
+       case SBE_2T3E3_SCRAMBLER_LARSCOM:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                              SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE);
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                            SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE);
+               break;
+       case SBE_2T3E3_SCRAMBLER_ADC_KENTROX_DIGITAL:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                            SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE);
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                            SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE);
+               break;
+       default:
+               return;
+       }
+
+       sc->p.scrambler = mode;
+}
+
+
+void cpld_set_crc(struct channel *sc, u32 crc)
+{
+       if (sc->p.crc == crc)
+               return;
+
+       switch (crc) {
+       case SBE_2T3E3_CRC_16:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_CRC32);
+               break;
+       case SBE_2T3E3_CRC_32:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_CRC32);
+               break;
+       default:
+               return;
+       }
+
+       sc->p.crc = crc;
+}
+
+
+void cpld_select_panel(struct channel *sc, u32 panel)
+{
+       if (sc->p.panel == panel)
+               return;
+       switch (panel) {
+       case SBE_2T3E3_PANEL_FRONT:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_REAR_PANEL);
+               break;
+       case SBE_2T3E3_PANEL_REAR:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_REAR_PANEL);
+               break;
+       default:
+               return;
+       }
+
+       udelay(100);
+
+       sc->p.panel = panel;
+}
+
+
+extern void cpld_set_clock(struct channel *sc, u32 mode)
+{
+       if (sc->p.clock_source == mode)
+               return;
+
+       switch (mode) {
+       case SBE_2T3E3_TIMING_LOCAL:
+               cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                            SBE_2T3E3_CPLD_VAL_ALT);
+               break;
+       case SBE_2T3E3_TIMING_LOOP:
+               cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA,
+                              SBE_2T3E3_CPLD_VAL_ALT);
+               break;
+       default:
+               return;
+       }
+
+       sc->p.clock_source = mode;
+}
+
+void cpld_set_pad_count(struct channel *sc, u32 count)
+{
+       u32 val;
+
+       if (sc->p.pad_count == count)
+               return;
+
+       switch (count) {
+       case SBE_2T3E3_PAD_COUNT_1:
+               val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_1;
+               break;
+       case SBE_2T3E3_PAD_COUNT_2:
+               val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_2;
+               break;
+       case SBE_2T3E3_PAD_COUNT_3:
+               val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_3;
+               break;
+       case SBE_2T3E3_PAD_COUNT_4:
+               val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_4;
+               break;
+       default:
+               return;
+       }
+
+       cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB,
+                      SBE_2T3E3_CPLD_VAL_PAD_COUNT);
+       cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, val);
+       sc->p.pad_count = count;
+}
+
+void cpld_LOS_update(struct channel *sc)
+{
+       u_int8_t los;
+
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR,
+                  SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED |
+                  SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED |
+                  SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED);
+       los = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR) &
+               SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED;
+
+       if (los != sc->s.LOS)
+               dev_info(&sc->pdev->dev, "SBE 2T3E3: LOS status: %s\n",
+                        los ? "Loss of signal" : "Signal OK");
+       sc->s.LOS = los;
+}
+
+void cpld_set_fractional_mode(struct channel *sc, u32 mode,
+                             u32 start, u32 stop)
+{
+       if (mode == SBE_2T3E3_FRACTIONAL_MODE_NONE) {
+               start = 0;
+               stop = 0;
+       }
+
+       if (sc->p.fractional_mode == mode && sc->p.bandwidth_start == start &&
+           sc->p.bandwidth_stop == stop)
+               return;
+
+       switch (mode) {
+       case SBE_2T3E3_FRACTIONAL_MODE_NONE:
+               cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC,
+                          SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_NONE);
+               break;
+       case SBE_2T3E3_FRACTIONAL_MODE_0:
+               cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC,
+                          SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_0);
+               break;
+       case SBE_2T3E3_FRACTIONAL_MODE_1:
+               cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC,
+                          SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_1);
+               break;
+       case SBE_2T3E3_FRACTIONAL_MODE_2:
+               cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC,
+                          SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_2);
+               break;
+       default:
+               printk(KERN_ERR "wrong mode in set_fractional_mode\n");
+               return;
+       }
+
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, start);
+       cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, stop);
+
+       sc->p.fractional_mode = mode;
+       sc->p.bandwidth_start = start;
+       sc->p.bandwidth_stop = stop;
+}