diff --git a/drivers/isdn/hardware/mISDN/Kbuild b/drivers/isdn/hardware/mISDN/Kbuild
new file mode 100644
index 000000000..2eb717964
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/Kbuild
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the modular ISDN hardware drivers
+#
+#
+obj-m := xhfc.o
+
+xhfc-y := xhfc_su.o xhfc_spi.o
+xhfc-objs := xhfc_su.o xhfc_spi.o
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index 078eeadf7..1b4e36105 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -24,6 +24,12 @@ config MISDN_HFCMULTI
 	   * HFC-8S (8 S/T interfaces on one chip)
 	   * HFC-E1 (E1 interface for 2Mbit ISDN)
 
+config MISDN_XHFC
+	tristate "Support for Osmocom XHFC-2SU evalboard"
+	depends on SPI
+	help
+	  Enable support for Osmocom Cologne Chips XHFC-2SU evaluation board
+
 config MISDN_HFCMULTI_8xx
 	bool "Support for XHFC embedded board in HFC multiport driver"
 	depends on MISDN
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index 3f50f8c47..6215ee097 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
 obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
 obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
+obj-$(CONFIG_MISDN_XHFC) += xhfc.o
 obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
 obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
 obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
@@ -17,3 +18,5 @@ obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
 obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
 
 obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o
+
+xhfc-objs := xhfc_su.o xhfc_spi.o
diff --git a/drivers/isdn/hardware/mISDN/xhfc24sucd.h b/drivers/isdn/hardware/mISDN/xhfc24sucd.h
new file mode 100644
index 000000000..0d59ad64a
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc24sucd.h
@@ -0,0 +1,2025 @@
+/* xhfc24sucd.h
+ * XHFC-2S4U / XHFC-4SU register definitions
+ * (C) 2007, 2008 Copyright Cologne Chip AG
+ * E-Mail: support@colognechip.com
+ *
+ * Dual-license
+ * ------------
+ * Cologne Chip AG, Eintrachtstr. 113, 50668 Koeln, Germany, provides this
+ * header file (software) under a dual-license.
+ * The licensee can choose from the following two licensing models:
+ *   * For GPL (free) distributions, see the 'License - GPL'
+ *   * For commercial distributions, see the 'License - Commercial'
+ *
+ *
+ * License - GPL
+ * -------------
+ * This software 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, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this software; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * License - Commercial
+ * --------------------
+ * (C) 2007, 2008 Copyright Cologne Chip AG
+ * All rights reserved.
+ * Contact: support@CologneChip.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions of source code must mark all modifications explicitly
+ *       as such, if any are made.
+ *     * For redistributing and use of this software in binary form, none of the
+ *       provisions above applies.
+ *
+ * This software is provided by Cologne Chip AG "as is" and any express or
+ * implied warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose are disclaimed. In no
+ * event shall Cologne Chip AG be liable for any direct, indirect, incidental,
+ * special, exemplary, or consequential damages (including, but not limited to,
+ * procurement of substitute goods or services; loss of use, data, or profits;
+ * or business interruption) however caused and on any theory of liability,
+ * whether in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even if
+ * advised of the possibility of such damage.
+ *
+ * <END OF Dual-license>
+ *
+ * __________________________________________________________________________________
+ *
+ *   File name:     xhfc24sucd.h
+ *   File content:  This file contains the XHFC-2S4U / XHFC-4SU register definitions.
+ *   Creation date: 18.06.2007 15:38
+ *   Creator:       Genero 3.6
+ *   Data base:     HFC XML 1.9 for XHFC-1SU, XHFC-2SU, XHFC-2S4U and XHFC-4SU
+ *   Address range: 0x00 - 0xFF
+ * 
+ *   The information presented can not be considered as assured characteristics.
+ *   Data can change without notice. Please check version numbers in case of doubt.
+ * 
+ *   For further information or questions please contact support@CologneChip.com
+ * __________________________________________________________________________________
+ * 
+ *   WARNING: This file has been generated automatically and should not be
+ *            changed to maintain compatibility with later versions.
+ * __________________________________________________________________________________
+ */
+
+#ifndef _XHFC24SUCD_H_
+#define _XHFC24SUCD_H_
+
+
+/*
+ *  Common chip information:
+ */
+
+	#define CHIP_NAME_2S4U		"XHFC-2S4U"
+	#define CHIP_NAME_4SU		"XHFC-4SU"
+	#define CHIP_TITLE_2S4U		"ISDN HDLC FIFO controller 2 S/T interfaces combined with 4 Up interfaces (Universal ISDN Ports)"
+	#define CHIP_TITLE_4SU		"ISDN HDLC FIFO controller with 4 S/T interfaces combined with 4 Up interfaces (Universal ISDN Ports)"
+	#define CHIP_MANUFACTURER	"Cologne Chip"
+	#define CHIP_ID_2S4U		0x62
+	#define CHIP_ID_4SU		0x63
+	#define CHIP_REGISTER_COUNT	122
+	#define CHIP_DATABASE		"Version HFC-XMLHFC XML 1.9 for XHFC-1SU, XHFC-2SU, XHFC-2S4U and XHFC-4SU - GeneroGenero 3.6 "
+
+// This register file can also be used for XHFC-2SU and XHFC-1SU programming.
+// For this reason these chip names, IDs and titles are defined here as well:
+
+	#define CHIP_NAME_2SU		"XHFC-2SU"
+	#define CHIP_TITLE_2SU		"ISDN HDLC FIFO controller with 2 combined S/T and Up Interfaces"
+	#define CHIP_ID_2SU		0x61
+
+	#define CHIP_NAME_1SU		"XHFC-1SU"
+	#define CHIP_TITLE_1SU		"ISDN HDLC FIFO controller with a combined S/T and Up Interface"
+	#define CHIP_ID_1SU		0x60
+
+/*
+ *  Begin of XHFC-2S4U / XHFC-4SU register definitions.
+ */
+
+#define R_CIRM 0x00 // register address, write only
+	#define M_CLK_OFF  0x01  // mask bit 0
+	#define SET_V_CLK_OFF(R,V)  (R = (__u8)((R & (__u8)(M_CLK_OFF ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_CLK_OFF(R)    (__u8)(R & M_CLK_OFF)
+
+	#define M_WAIT_PROC  0x02  // mask bit 1
+	#define SET_V_WAIT_PROC(R,V)  (R = (__u8)((R & (__u8)(M_WAIT_PROC ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_WAIT_PROC(R)    (__u8)((R & M_WAIT_PROC) >> 1)
+
+	#define M_WAIT_REG  0x04  // mask bit 2
+	#define SET_V_WAIT_REG(R,V)  (R = (__u8)((R & (__u8)(M_WAIT_REG ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_WAIT_REG(R)    (__u8)((R & M_WAIT_REG) >> 2)
+
+	#define M_SRES  0x08  // mask bit 3
+	#define SET_V_SRES(R,V)  (R = (__u8)((R & (__u8)(M_SRES ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_SRES(R)    (__u8)((R & M_SRES) >> 3)
+
+	#define M_HFC_RES  0x10  // mask bit 4
+	#define SET_V_HFC_RES(R,V)  (R = (__u8)((R & (__u8)(M_HFC_RES ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_HFC_RES(R)    (__u8)((R & M_HFC_RES) >> 4)
+
+	#define M_PCM_RES  0x20  // mask bit 5
+	#define SET_V_PCM_RES(R,V)  (R = (__u8)((R & (__u8)(M_PCM_RES ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_PCM_RES(R)    (__u8)((R & M_PCM_RES) >> 5)
+
+	#define M_SU_RES  0x40  // mask bit 6
+	#define SET_V_SU_RES(R,V)  (R = (__u8)((R & (__u8)(M_SU_RES ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_SU_RES(R)    (__u8)((R & M_SU_RES) >> 6)
+
+
+#define R_CTRL 0x01 // register address, write only
+	#define M_FIFO_LPRIO  0x02  // mask bit 1
+	#define SET_V_FIFO_LPRIO(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_LPRIO ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_FIFO_LPRIO(R)    (__u8)((R & M_FIFO_LPRIO) >> 1)
+
+	#define M_NT_SYNC  0x08  // mask bit 3
+	#define SET_V_NT_SYNC(R,V)  (R = (__u8)((R & (__u8)(M_NT_SYNC ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_NT_SYNC(R)    (__u8)((R & M_NT_SYNC) >> 3)
+
+	#define M_OSC_OFF  0x20  // mask bit 5
+	#define SET_V_OSC_OFF(R,V)  (R = (__u8)((R & (__u8)(M_OSC_OFF ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_OSC_OFF(R)    (__u8)((R & M_OSC_OFF) >> 5)
+
+	#define M_SU_CLK  0xC0  // mask bits 6..7
+	#define SET_V_SU_CLK(R,V)  (R = (__u8)((R & (__u8)(M_SU_CLK ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_SU_CLK(R)    (__u8)((R & M_SU_CLK) >> 6)
+
+
+#define R_CLK_CFG 0x02 // register address, write only
+	#define M_CLK_PLL  0x01  // mask bit 0
+	#define SET_V_CLK_PLL(R,V)  (R = (__u8)((R & (__u8)(M_CLK_PLL ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_CLK_PLL(R)    (__u8)(R & M_CLK_PLL)
+
+	#define M_CLKO_HI  0x02  // mask bit 1
+	#define SET_V_CLKO_HI(R,V)  (R = (__u8)((R & (__u8)(M_CLKO_HI ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_CLKO_HI(R)    (__u8)((R & M_CLKO_HI) >> 1)
+
+	#define M_CLKO_PLL  0x04  // mask bit 2
+	#define SET_V_CLKO_PLL(R,V)  (R = (__u8)((R & (__u8)(M_CLKO_PLL ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_CLKO_PLL(R)    (__u8)((R & M_CLKO_PLL) >> 2)
+
+	#define M_PCM_CLK  0x20  // mask bit 5
+	#define SET_V_PCM_CLK(R,V)  (R = (__u8)((R & (__u8)(M_PCM_CLK ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_PCM_CLK(R)    (__u8)((R & M_PCM_CLK) >> 5)
+
+	#define M_CLKO_OFF  0x40  // mask bit 6
+	#define SET_V_CLKO_OFF(R,V)  (R = (__u8)((R & (__u8)(M_CLKO_OFF ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_CLKO_OFF(R)    (__u8)((R & M_CLKO_OFF) >> 6)
+
+	#define M_CLK_F1  0x80  // mask bit 7
+	#define SET_V_CLK_F1(R,V)  (R = (__u8)((R & (__u8)(M_CLK_F1 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_CLK_F1(R)    (__u8)((R & M_CLK_F1) >> 7)
+
+
+#define A_Z1 0x04 // register address, read only
+	#define M_Z1  0xFF  // mask bits 0..7
+	#define GET_V_Z1(R)    (__u8)(R & M_Z1)
+
+
+#define A_Z2 0x06 // register address, read only
+	#define M_Z2  0xFF  // mask bits 0..7
+	#define GET_V_Z2(R)    (__u8)(R & M_Z2)
+
+
+#define R_RAM_ADDR 0x08 // register address, write only
+	#define M_RAM_ADDR0  0xFF  // mask bits 0..7
+	#define SET_V_RAM_ADDR0(R,V)  (R = (__u8)((R & (__u8)(M_RAM_ADDR0 ^ 0xFF)) | (__u8)V))
+	#define GET_V_RAM_ADDR0(R)    (__u8)(R & M_RAM_ADDR0)
+
+
+#define R_RAM_CTRL 0x09 // register address, write only
+	#define M_RAM_ADDR1  0x0F  // mask bits 0..3
+	#define SET_V_RAM_ADDR1(R,V)  (R = (__u8)((R & (__u8)(M_RAM_ADDR1 ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_RAM_ADDR1(R)    (__u8)(R & M_RAM_ADDR1)
+
+	#define M_ADDR_RES  0x40  // mask bit 6
+	#define SET_V_ADDR_RES(R,V)  (R = (__u8)((R & (__u8)(M_ADDR_RES ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_ADDR_RES(R)    (__u8)((R & M_ADDR_RES) >> 6)
+
+	#define M_ADDR_INC  0x80  // mask bit 7
+	#define SET_V_ADDR_INC(R,V)  (R = (__u8)((R & (__u8)(M_ADDR_INC ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_ADDR_INC(R)    (__u8)((R & M_ADDR_INC) >> 7)
+
+
+#define R_FIRST_FIFO 0x0B // register address, write only
+	#define M_FIRST_FIFO_DIR  0x01  // mask bit 0
+	#define SET_V_FIRST_FIFO_DIR(R,V)  (R = (__u8)((R & (__u8)(M_FIRST_FIFO_DIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_FIRST_FIFO_DIR(R)    (__u8)(R & M_FIRST_FIFO_DIR)
+
+	#define M_FIRST_FIFO_NUM  0x1E  // mask bits 1..4
+	#define SET_V_FIRST_FIFO_NUM(R,V)  (R = (__u8)((R & (__u8)(M_FIRST_FIFO_NUM ^ 0xFF)) | (__u8)((V & 0x0F) << 1)))
+	#define GET_V_FIRST_FIFO_NUM(R)    (__u8)((R & M_FIRST_FIFO_NUM) >> 1)
+
+
+#define R_FIFO_THRES 0x0C // register address, write only
+	#define M_THRES_TX  0x0F  // mask bits 0..3
+	#define SET_V_THRES_TX(R,V)  (R = (__u8)((R & (__u8)(M_THRES_TX ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_THRES_TX(R)    (__u8)(R & M_THRES_TX)
+
+	#define M_THRES_RX  0xF0  // mask bits 4..7
+	#define SET_V_THRES_RX(R,V)  (R = (__u8)((R & (__u8)(M_THRES_RX ^ 0xFF)) | (__u8)((V & 0x0F) << 4)))
+	#define GET_V_THRES_RX(R)    (__u8)((R & M_THRES_RX) >> 4)
+
+
+#define A_F1 0x0C // register address, read only
+	#define M_F1  0xFF  // mask bits 0..7
+	#define GET_V_F1(R)    (__u8)(R & M_F1)
+
+
+#define R_FIFO_MD 0x0D // register address, write only
+	#define M_FIFO_MD  0x03  // mask bits 0..1
+	#define SET_V_FIFO_MD(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_MD ^ 0xFF)) | (__u8)(V & 0x03)))
+	#define GET_V_FIFO_MD(R)    (__u8)(R & M_FIFO_MD)
+
+	#define M_DF_MD  0x0C  // mask bits 2..3
+	#define SET_V_DF_MD(R,V)  (R = (__u8)((R & (__u8)(M_DF_MD ^ 0xFF)) | (__u8)((V & 0x03) << 2)))
+	#define GET_V_DF_MD(R)    (__u8)((R & M_DF_MD) >> 2)
+
+	#define M_UNIDIR_MD  0x10  // mask bit 4
+	#define SET_V_UNIDIR_MD(R,V)  (R = (__u8)((R & (__u8)(M_UNIDIR_MD ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_UNIDIR_MD(R)    (__u8)((R & M_UNIDIR_MD) >> 4)
+
+	#define M_UNIDIR_RX  0x20  // mask bit 5
+	#define SET_V_UNIDIR_RX(R,V)  (R = (__u8)((R & (__u8)(M_UNIDIR_RX ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_UNIDIR_RX(R)    (__u8)((R & M_UNIDIR_RX) >> 5)
+
+
+#define A_F2 0x0D // register address, read only
+	#define M_F2  0xFF  // mask bits 0..7
+	#define GET_V_F2(R)    (__u8)(R & M_F2)
+
+
+#define A_INC_RES_FIFO 0x0E // register address, write only
+	#define M_INC_F  0x01  // mask bit 0
+	#define SET_V_INC_F(R,V)  (R = (__u8)((R & (__u8)(M_INC_F ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_INC_F(R)    (__u8)(R & M_INC_F)
+
+	#define M_RES_FIFO  0x02  // mask bit 1
+	#define SET_V_RES_FIFO(R,V)  (R = (__u8)((R & (__u8)(M_RES_FIFO ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_RES_FIFO(R)    (__u8)((R & M_RES_FIFO) >> 1)
+
+	#define M_RES_LOST  0x04  // mask bit 2
+	#define SET_V_RES_LOST(R,V)  (R = (__u8)((R & (__u8)(M_RES_LOST ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_RES_LOST(R)    (__u8)((R & M_RES_LOST) >> 2)
+
+	#define M_RES_FIFO_ERR  0x08  // mask bit 3
+	#define SET_V_RES_FIFO_ERR(R,V)  (R = (__u8)((R & (__u8)(M_RES_FIFO_ERR ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_RES_FIFO_ERR(R)    (__u8)((R & M_RES_FIFO_ERR) >> 3)
+
+
+#define A_FIFO_STA 0x0E // register address, read only
+	#define M_FIFO_ERR  0x01  // mask bit 0
+	#define GET_V_FIFO_ERR(R)    (__u8)(R & M_FIFO_ERR)
+
+	#define M_ABO_DONE  0x10  // mask bit 4
+	#define GET_V_ABO_DONE(R)    (__u8)((R & M_ABO_DONE) >> 4)
+
+
+#define R_FSM_IDX 0x0F // register address, write only
+	#define M_IDX  0x1F  // mask bits 0..4
+	#define SET_V_IDX(R,V)  (R = (__u8)((R & (__u8)(M_IDX ^ 0xFF)) | (__u8)(V & 0x1F)))
+	#define GET_V_IDX(R)    (__u8)(R & M_IDX)
+
+
+#define R_FIFO 0x0F // register address, write only
+	#define M_FIFO_DIR  0x01  // mask bit 0
+	#define SET_V_FIFO_DIR(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_DIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_FIFO_DIR(R)    (__u8)(R & M_FIFO_DIR)
+
+	#define M_FIFO_NUM  0x1E  // mask bits 1..4
+	#define SET_V_FIFO_NUM(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_NUM ^ 0xFF)) | (__u8)((V & 0x0F) << 1)))
+	#define GET_V_FIFO_NUM(R)    (__u8)((R & M_FIFO_NUM) >> 1)
+
+	#define M_REV  0x80  // mask bit 7
+	#define SET_V_REV(R,V)  (R = (__u8)((R & (__u8)(M_REV ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_REV(R)    (__u8)((R & M_REV) >> 7)
+
+
+#define R_SLOT 0x10 // register address, write only
+	#define M_SL_DIR  0x01  // mask bit 0
+	#define SET_V_SL_DIR(R,V)  (R = (__u8)((R & (__u8)(M_SL_DIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_SL_DIR(R)    (__u8)(R & M_SL_DIR)
+
+	#define M_SL_NUM  0xFE  // mask bits 1..7
+	#define SET_V_SL_NUM(R,V)  (R = (__u8)((R & (__u8)(M_SL_NUM ^ 0xFF)) | (__u8)((V & 0x7F) << 1)))
+	#define GET_V_SL_NUM(R)    (__u8)((R & M_SL_NUM) >> 1)
+
+
+#define R_IRQ_OVIEW 0x10 // register address, read only
+	#define M_FIFO_BL0_IRQ  0x01  // mask bit 0
+	#define GET_V_FIFO_BL0_IRQ(R)    (__u8)(R & M_FIFO_BL0_IRQ)
+
+	#define M_FIFO_BL1_IRQ  0x02  // mask bit 1
+	#define GET_V_FIFO_BL1_IRQ(R)    (__u8)((R & M_FIFO_BL1_IRQ) >> 1)
+
+	#define M_FIFO_BL2_IRQ  0x04  // mask bit 2
+	#define GET_V_FIFO_BL2_IRQ(R)    (__u8)((R & M_FIFO_BL2_IRQ) >> 2)
+
+	#define M_FIFO_BL3_IRQ  0x08  // mask bit 3
+	#define GET_V_FIFO_BL3_IRQ(R)    (__u8)((R & M_FIFO_BL3_IRQ) >> 3)
+
+	#define M_MISC_IRQ  0x10  // mask bit 4
+	#define GET_V_MISC_IRQ(R)    (__u8)((R & M_MISC_IRQ) >> 4)
+
+	#define M_STUP_IRQ  0x20  // mask bit 5
+	#define GET_V_STUP_IRQ(R)    (__u8)((R & M_STUP_IRQ) >> 5)
+
+
+#define R_MISC_IRQMSK 0x11 // register address, write only
+	#define M_SLIP_IRQMSK  0x01  // mask bit 0
+	#define SET_V_SLIP_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_SLIP_IRQMSK ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_SLIP_IRQMSK(R)    (__u8)(R & M_SLIP_IRQMSK)
+
+	#define M_TI_IRQMSK  0x02  // mask bit 1
+	#define SET_V_TI_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_TI_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_TI_IRQMSK(R)    (__u8)((R & M_TI_IRQMSK) >> 1)
+
+	#define M_PROC_IRQMSK  0x04  // mask bit 2
+	#define SET_V_PROC_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_PROC_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_PROC_IRQMSK(R)    (__u8)((R & M_PROC_IRQMSK) >> 2)
+
+	#define M_CI_IRQMSK  0x10  // mask bit 4
+	#define SET_V_CI_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_CI_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_CI_IRQMSK(R)    (__u8)((R & M_CI_IRQMSK) >> 4)
+
+	#define M_WAK_IRQMSK  0x20  // mask bit 5
+	#define SET_V_WAK_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_WAK_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_WAK_IRQMSK(R)    (__u8)((R & M_WAK_IRQMSK) >> 5)
+
+	#define M_MON_TX_IRQMSK  0x40  // mask bit 6
+	#define SET_V_MON_TX_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_MON_TX_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_MON_TX_IRQMSK(R)    (__u8)((R & M_MON_TX_IRQMSK) >> 6)
+
+	#define M_MON_RX_IRQMSK  0x80  // mask bit 7
+	#define SET_V_MON_RX_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_MON_RX_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_MON_RX_IRQMSK(R)    (__u8)((R & M_MON_RX_IRQMSK) >> 7)
+
+
+#define R_MISC_IRQ 0x11 // register address, read only
+	#define M_SLIP_IRQ  0x01  // mask bit 0
+	#define GET_V_SLIP_IRQ(R)    (__u8)(R & M_SLIP_IRQ)
+
+	#define M_TI_IRQ  0x02  // mask bit 1
+	#define GET_V_TI_IRQ(R)    (__u8)((R & M_TI_IRQ) >> 1)
+
+	#define M_PROC_IRQ  0x04  // mask bit 2
+	#define GET_V_PROC_IRQ(R)    (__u8)((R & M_PROC_IRQ) >> 2)
+
+	#define M_CI_IRQ  0x10  // mask bit 4
+	#define GET_V_CI_IRQ(R)    (__u8)((R & M_CI_IRQ) >> 4)
+
+	#define M_WAK_IRQ  0x20  // mask bit 5
+	#define GET_V_WAK_IRQ(R)    (__u8)((R & M_WAK_IRQ) >> 5)
+
+	#define M_MON_TX_IRQ  0x40  // mask bit 6
+	#define GET_V_MON_TX_IRQ(R)    (__u8)((R & M_MON_TX_IRQ) >> 6)
+
+	#define M_MON_RX_IRQ  0x80  // mask bit 7
+	#define GET_V_MON_RX_IRQ(R)    (__u8)((R & M_MON_RX_IRQ) >> 7)
+
+
+#define R_SU_IRQ 0x12 // register address, read only
+	#define M_SU0_IRQ  0x01  // mask bit 0
+	#define GET_V_SU0_IRQ(R)    (__u8)(R & M_SU0_IRQ)
+
+	#define M_SU1_IRQ  0x02  // mask bit 1
+	#define GET_V_SU1_IRQ(R)    (__u8)((R & M_SU1_IRQ) >> 1)
+
+	#define M_SU2_IRQ  0x04  // mask bit 2
+	#define GET_V_SU2_IRQ(R)    (__u8)((R & M_SU2_IRQ) >> 2)
+
+	#define M_SU3_IRQ  0x08  // mask bit 3
+	#define GET_V_SU3_IRQ(R)    (__u8)((R & M_SU3_IRQ) >> 3)
+
+
+#define R_SU_IRQMSK 0x12 // register address, write only
+	#define M_SU0_IRQMSK  0x01  // mask bit 0
+	#define SET_V_SU0_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_SU0_IRQMSK ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_SU0_IRQMSK(R)    (__u8)(R & M_SU0_IRQMSK)
+
+	#define M_SU1_IRQMSK  0x02  // mask bit 1
+	#define SET_V_SU1_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_SU1_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_SU1_IRQMSK(R)    (__u8)((R & M_SU1_IRQMSK) >> 1)
+
+	#define M_SU2_IRQMSK  0x04  // mask bit 2
+	#define SET_V_SU2_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_SU2_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_SU2_IRQMSK(R)    (__u8)((R & M_SU2_IRQMSK) >> 2)
+
+	#define M_SU3_IRQMSK  0x08  // mask bit 3
+	#define SET_V_SU3_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_SU3_IRQMSK ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_SU3_IRQMSK(R)    (__u8)((R & M_SU3_IRQMSK) >> 3)
+
+
+#define R_AF0_OVIEW 0x13 // register address, read only
+	#define M_SU0_AF0  0x01  // mask bit 0
+	#define GET_V_SU0_AF0(R)    (__u8)(R & M_SU0_AF0)
+
+	#define M_SU1_AF0  0x02  // mask bit 1
+	#define GET_V_SU1_AF0(R)    (__u8)((R & M_SU1_AF0) >> 1)
+
+	#define M_SU2_AF0  0x04  // mask bit 2
+	#define GET_V_SU2_AF0(R)    (__u8)((R & M_SU2_AF0) >> 2)
+
+	#define M_SU3_AF0  0x08  // mask bit 3
+	#define GET_V_SU3_AF0(R)    (__u8)((R & M_SU3_AF0) >> 3)
+
+
+#define R_IRQ_CTRL 0x13 // register address, write only
+	#define M_FIFO_IRQ_EN  0x01  // mask bit 0
+	#define SET_V_FIFO_IRQ_EN(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_IRQ_EN ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_FIFO_IRQ_EN(R)    (__u8)(R & M_FIFO_IRQ_EN)
+
+	#define M_GLOB_IRQ_EN  0x08  // mask bit 3
+	#define SET_V_GLOB_IRQ_EN(R,V)  (R = (__u8)((R & (__u8)(M_GLOB_IRQ_EN ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GLOB_IRQ_EN(R)    (__u8)((R & M_GLOB_IRQ_EN) >> 3)
+
+	#define M_IRQ_POL  0x10  // mask bit 4
+	#define SET_V_IRQ_POL(R,V)  (R = (__u8)((R & (__u8)(M_IRQ_POL ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_IRQ_POL(R)    (__u8)((R & M_IRQ_POL) >> 4)
+
+
+#define A_USAGE 0x14 // register address, read only
+	#define M_USAGE  0xFF  // mask bits 0..7
+	#define GET_V_USAGE(R)    (__u8)(R & M_USAGE)
+
+
+#define R_PCM_MD0 0x14 // register address, write only
+	#define M_PCM_MD  0x01  // mask bit 0
+	#define SET_V_PCM_MD(R,V)  (R = (__u8)((R & (__u8)(M_PCM_MD ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_PCM_MD(R)    (__u8)(R & M_PCM_MD)
+
+	#define M_C4_POL  0x02  // mask bit 1
+	#define SET_V_C4_POL(R,V)  (R = (__u8)((R & (__u8)(M_C4_POL ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_C4_POL(R)    (__u8)((R & M_C4_POL) >> 1)
+
+	#define M_F0_NEG  0x04  // mask bit 2
+	#define SET_V_F0_NEG(R,V)  (R = (__u8)((R & (__u8)(M_F0_NEG ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_F0_NEG(R)    (__u8)((R & M_F0_NEG) >> 2)
+
+	#define M_F0_LEN  0x08  // mask bit 3
+	#define SET_V_F0_LEN(R,V)  (R = (__u8)((R & (__u8)(M_F0_LEN ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_F0_LEN(R)    (__u8)((R & M_F0_LEN) >> 3)
+
+	#define M_PCM_IDX  0xF0  // mask bits 4..7
+	#define SET_V_PCM_IDX(R,V)  (R = (__u8)((R & (__u8)(M_PCM_IDX ^ 0xFF)) | (__u8)((V & 0x0F) << 4)))
+	#define GET_V_PCM_IDX(R)    (__u8)((R & M_PCM_IDX) >> 4)
+
+
+#define R_SL_SEL0 0x15 // register address, write only
+	#define M_SL_SEL0  0x7F  // mask bits 0..6
+	#define SET_V_SL_SEL0(R,V)  (R = (__u8)((R & (__u8)(M_SL_SEL0 ^ 0xFF)) | (__u8)(V & 0x7F)))
+	#define GET_V_SL_SEL0(R)    (__u8)(R & M_SL_SEL0)
+
+	#define M_SH_SEL0  0x80  // mask bit 7
+	#define SET_V_SH_SEL0(R,V)  (R = (__u8)((R & (__u8)(M_SH_SEL0 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_SH_SEL0(R)    (__u8)((R & M_SH_SEL0) >> 7)
+
+
+#define R_SL_SEL1 0x15 // register address, write only
+	#define M_SL_SEL1  0x7F  // mask bits 0..6
+	#define SET_V_SL_SEL1(R,V)  (R = (__u8)((R & (__u8)(M_SL_SEL1 ^ 0xFF)) | (__u8)(V & 0x7F)))
+	#define GET_V_SL_SEL1(R)    (__u8)(R & M_SL_SEL1)
+
+	#define M_SH_SEL1  0x80  // mask bit 7
+	#define SET_V_SH_SEL1(R,V)  (R = (__u8)((R & (__u8)(M_SH_SEL1 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_SH_SEL1(R)    (__u8)((R & M_SH_SEL1) >> 7)
+
+
+#define R_SL_SEL7 0x15 // register address, write only
+	#define M_SL_SEL7  0x7F  // mask bits 0..6
+	#define SET_V_SL_SEL7(R,V)  (R = (__u8)((R & (__u8)(M_SL_SEL7 ^ 0xFF)) | (__u8)(V & 0x7F)))
+	#define GET_V_SL_SEL7(R)    (__u8)(R & M_SL_SEL7)
+
+
+#define R_MSS0 0x15 // register address, write only
+	#define M_MSS_MOD  0x01  // mask bit 0
+	#define SET_V_MSS_MOD(R,V)  (R = (__u8)((R & (__u8)(M_MSS_MOD ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_MSS_MOD(R)    (__u8)(R & M_MSS_MOD)
+
+	#define M_MSS_MOD_REP  0x02  // mask bit 1
+	#define SET_V_MSS_MOD_REP(R,V)  (R = (__u8)((R & (__u8)(M_MSS_MOD_REP ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_MSS_MOD_REP(R)    (__u8)((R & M_MSS_MOD_REP) >> 1)
+
+	#define M_MSS_SRC_EN  0x04  // mask bit 2
+	#define SET_V_MSS_SRC_EN(R,V)  (R = (__u8)((R & (__u8)(M_MSS_SRC_EN ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_MSS_SRC_EN(R)    (__u8)((R & M_MSS_SRC_EN) >> 2)
+
+	#define M_MSS_SRC_GRD  0x08  // mask bit 3
+	#define SET_V_MSS_SRC_GRD(R,V)  (R = (__u8)((R & (__u8)(M_MSS_SRC_GRD ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_MSS_SRC_GRD(R)    (__u8)((R & M_MSS_SRC_GRD) >> 3)
+
+	#define M_MSS_OUT_EN  0x10  // mask bit 4
+	#define SET_V_MSS_OUT_EN(R,V)  (R = (__u8)((R & (__u8)(M_MSS_OUT_EN ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_MSS_OUT_EN(R)    (__u8)((R & M_MSS_OUT_EN) >> 4)
+
+	#define M_MSS_OUT_REP  0x20  // mask bit 5
+	#define SET_V_MSS_OUT_REP(R,V)  (R = (__u8)((R & (__u8)(M_MSS_OUT_REP ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_MSS_OUT_REP(R)    (__u8)((R & M_MSS_OUT_REP) >> 5)
+
+	#define M_MSS_SRC  0xC0  // mask bits 6..7
+	#define SET_V_MSS_SRC(R,V)  (R = (__u8)((R & (__u8)(M_MSS_SRC ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_MSS_SRC(R)    (__u8)((R & M_MSS_SRC) >> 6)
+
+
+#define R_PCM_MD1 0x15 // register address, write only
+	#define M_PCM_OD  0x02  // mask bit 1
+	#define SET_V_PCM_OD(R,V)  (R = (__u8)((R & (__u8)(M_PCM_OD ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_PCM_OD(R)    (__u8)((R & M_PCM_OD) >> 1)
+
+	#define M_PLL_ADJ  0x0C  // mask bits 2..3
+	#define SET_V_PLL_ADJ(R,V)  (R = (__u8)((R & (__u8)(M_PLL_ADJ ^ 0xFF)) | (__u8)((V & 0x03) << 2)))
+	#define GET_V_PLL_ADJ(R)    (__u8)((R & M_PLL_ADJ) >> 2)
+
+	#define M_PCM_DR  0x30  // mask bits 4..5
+	#define SET_V_PCM_DR(R,V)  (R = (__u8)((R & (__u8)(M_PCM_DR ^ 0xFF)) | (__u8)((V & 0x03) << 4)))
+	#define GET_V_PCM_DR(R)    (__u8)((R & M_PCM_DR) >> 4)
+
+	#define M_PCM_LOOP  0x40  // mask bit 6
+	#define SET_V_PCM_LOOP(R,V)  (R = (__u8)((R & (__u8)(M_PCM_LOOP ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_PCM_LOOP(R)    (__u8)((R & M_PCM_LOOP) >> 6)
+
+	#define M_PCM_SMPL  0x80  // mask bit 7
+	#define SET_V_PCM_SMPL(R,V)  (R = (__u8)((R & (__u8)(M_PCM_SMPL ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_PCM_SMPL(R)    (__u8)((R & M_PCM_SMPL) >> 7)
+
+
+#define R_PCM_MD2 0x15 // register address, write only
+	#define M_SYNC_OUT1  0x02  // mask bit 1
+	#define SET_V_SYNC_OUT1(R,V)  (R = (__u8)((R & (__u8)(M_SYNC_OUT1 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_SYNC_OUT1(R)    (__u8)((R & M_SYNC_OUT1) >> 1)
+
+	#define M_SYNC_SRC  0x04  // mask bit 2
+	#define SET_V_SYNC_SRC(R,V)  (R = (__u8)((R & (__u8)(M_SYNC_SRC ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_SYNC_SRC(R)    (__u8)((R & M_SYNC_SRC) >> 2)
+
+	#define M_SYNC_OUT2  0x08  // mask bit 3
+	#define SET_V_SYNC_OUT2(R,V)  (R = (__u8)((R & (__u8)(M_SYNC_OUT2 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_SYNC_OUT2(R)    (__u8)((R & M_SYNC_OUT2) >> 3)
+
+	#define M_C2O_EN  0x10  // mask bit 4
+	#define SET_V_C2O_EN(R,V)  (R = (__u8)((R & (__u8)(M_C2O_EN ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_C2O_EN(R)    (__u8)((R & M_C2O_EN) >> 4)
+
+	#define M_C2I_EN  0x20  // mask bit 5
+	#define SET_V_C2I_EN(R,V)  (R = (__u8)((R & (__u8)(M_C2I_EN ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_C2I_EN(R)    (__u8)((R & M_C2I_EN) >> 5)
+
+	#define M_PLL_ICR  0x40  // mask bit 6
+	#define SET_V_PLL_ICR(R,V)  (R = (__u8)((R & (__u8)(M_PLL_ICR ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_PLL_ICR(R)    (__u8)((R & M_PLL_ICR) >> 6)
+
+	#define M_PLL_MAN  0x80  // mask bit 7
+	#define SET_V_PLL_MAN(R,V)  (R = (__u8)((R & (__u8)(M_PLL_MAN ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_PLL_MAN(R)    (__u8)((R & M_PLL_MAN) >> 7)
+
+
+#define R_MSS1 0x15 // register address, write only
+	#define M_MSS_OFFS  0x07  // mask bits 0..2
+	#define SET_V_MSS_OFFS(R,V)  (R = (__u8)((R & (__u8)(M_MSS_OFFS ^ 0xFF)) | (__u8)(V & 0x07)))
+	#define GET_V_MSS_OFFS(R)    (__u8)(R & M_MSS_OFFS)
+
+	#define M_MS_SSYNC1  0x08  // mask bit 3
+	#define SET_V_MS_SSYNC1(R,V)  (R = (__u8)((R & (__u8)(M_MS_SSYNC1 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_MS_SSYNC1(R)    (__u8)((R & M_MS_SSYNC1) >> 3)
+
+	#define M_MSS_DLY  0xF0  // mask bits 4..7
+	#define SET_V_MSS_DLY(R,V)  (R = (__u8)((R & (__u8)(M_MSS_DLY ^ 0xFF)) | (__u8)((V & 0x0F) << 4)))
+	#define GET_V_MSS_DLY(R)    (__u8)((R & M_MSS_DLY) >> 4)
+
+
+#define R_SH0L 0x15 // register address, write only
+	#define M_SH0L  0xFF  // mask bits 0..7
+	#define SET_V_SH0L(R,V)  (R = (__u8)((R & (__u8)(M_SH0L ^ 0xFF)) | (__u8)V))
+	#define GET_V_SH0L(R)    (__u8)(R & M_SH0L)
+
+
+#define R_SH0H 0x15 // register address, write only
+	#define M_SH0H  0xFF  // mask bits 0..7
+	#define SET_V_SH0H(R,V)  (R = (__u8)((R & (__u8)(M_SH0H ^ 0xFF)) | (__u8)V))
+	#define GET_V_SH0H(R)    (__u8)(R & M_SH0H)
+
+
+#define R_SH1L 0x15 // register address, write only
+	#define M_SH1L  0xFF  // mask bits 0..7
+	#define SET_V_SH1L(R,V)  (R = (__u8)((R & (__u8)(M_SH1L ^ 0xFF)) | (__u8)V))
+	#define GET_V_SH1L(R)    (__u8)(R & M_SH1L)
+
+
+#define R_SH1H 0x15 // register address, write only
+	#define M_SH1H  0xFF  // mask bits 0..7
+	#define SET_V_SH1H(R,V)  (R = (__u8)((R & (__u8)(M_SH1H ^ 0xFF)) | (__u8)V))
+	#define GET_V_SH1H(R)    (__u8)(R & M_SH1H)
+
+
+#define R_RAM_USE 0x15 // register address, read only
+	#define M_SRAM_USE  0xFF  // mask bits 0..7
+	#define GET_V_SRAM_USE(R)    (__u8)(R & M_SRAM_USE)
+
+
+#define R_SU_SEL 0x16 // register address, write only
+	#define M_SU_SEL  0x03  // mask bits 0..1
+	#define SET_V_SU_SEL(R,V)  (R = (__u8)((R & (__u8)(M_SU_SEL ^ 0xFF)) | (__u8)(V & 0x03)))
+	#define GET_V_SU_SEL(R)    (__u8)(R & M_SU_SEL)
+
+	#define M_MULT_SU  0x08  // mask bit 3
+	#define SET_V_MULT_SU(R,V)  (R = (__u8)((R & (__u8)(M_MULT_SU ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_MULT_SU(R)    (__u8)((R & M_MULT_SU) >> 3)
+
+
+#define R_CHIP_ID 0x16 // register address, read only
+	#define M_CHIP_ID  0xFF  // mask bits 0..7
+	#define GET_V_CHIP_ID(R)    (__u8)(R & M_CHIP_ID)
+
+
+#define R_BERT_STA 0x17 // register address, read only
+	#define M_RD_SYNC_SRC  0x07  // mask bits 0..2
+	#define GET_V_RD_SYNC_SRC(R)    (__u8)(R & M_RD_SYNC_SRC)
+
+	#define M_BERT_SYNC  0x10  // mask bit 4
+	#define GET_V_BERT_SYNC(R)    (__u8)((R & M_BERT_SYNC) >> 4)
+
+	#define M_BERT_INV_DATA  0x20  // mask bit 5
+	#define GET_V_BERT_INV_DATA(R)    (__u8)((R & M_BERT_INV_DATA) >> 5)
+
+
+#define R_SU_SYNC 0x17 // register address, write only
+	#define M_SYNC_SEL  0x07  // mask bits 0..2
+	#define SET_V_SYNC_SEL(R,V)  (R = (__u8)((R & (__u8)(M_SYNC_SEL ^ 0xFF)) | (__u8)(V & 0x07)))
+	#define GET_V_SYNC_SEL(R)    (__u8)(R & M_SYNC_SEL)
+
+	#define M_MAN_SYNC  0x08  // mask bit 3
+	#define SET_V_MAN_SYNC(R,V)  (R = (__u8)((R & (__u8)(M_MAN_SYNC ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_MAN_SYNC(R)    (__u8)((R & M_MAN_SYNC) >> 3)
+
+	#define M_AUTO_SYNCI  0x10  // mask bit 4
+	#define SET_V_AUTO_SYNCI(R,V)  (R = (__u8)((R & (__u8)(M_AUTO_SYNCI ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_AUTO_SYNCI(R)    (__u8)((R & M_AUTO_SYNCI) >> 4)
+
+	#define M_D_MERGE_TX  0x20  // mask bit 5
+	#define SET_V_D_MERGE_TX(R,V)  (R = (__u8)((R & (__u8)(M_D_MERGE_TX ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_D_MERGE_TX(R)    (__u8)((R & M_D_MERGE_TX) >> 5)
+
+	#define M_E_MERGE_RX  0x40  // mask bit 6
+	#define SET_V_E_MERGE_RX(R,V)  (R = (__u8)((R & (__u8)(M_E_MERGE_RX ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_E_MERGE_RX(R)    (__u8)((R & M_E_MERGE_RX) >> 6)
+
+	#define M_D_MERGE_RX  0x80  // mask bit 7
+	#define SET_V_D_MERGE_RX(R,V)  (R = (__u8)((R & (__u8)(M_D_MERGE_RX ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_D_MERGE_RX(R)    (__u8)((R & M_D_MERGE_RX) >> 7)
+
+
+#define R_F0_CNTL 0x18 // register address, read only
+	#define M_F0_CNTL  0xFF  // mask bits 0..7
+	#define GET_V_F0_CNTL(R)    (__u8)(R & M_F0_CNTL)
+
+
+#define R_F0_CNTH 0x19 // register address, read only
+	#define M_F0_CNTH  0xFF  // mask bits 0..7
+	#define GET_V_F0_CNTH(R)    (__u8)(R & M_F0_CNTH)
+
+
+#define R_BERT_ECL 0x1A // register address, read only
+	#define M_BERT_ECL  0xFF  // mask bits 0..7
+	#define GET_V_BERT_ECL(R)    (__u8)(R & M_BERT_ECL)
+
+
+#define R_TI_WD 0x1A // register address, write only
+	#define M_EV_TS  0x0F  // mask bits 0..3
+	#define SET_V_EV_TS(R,V)  (R = (__u8)((R & (__u8)(M_EV_TS ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_EV_TS(R)    (__u8)(R & M_EV_TS)
+
+	#define M_WD_TS  0xF0  // mask bits 4..7
+	#define SET_V_WD_TS(R,V)  (R = (__u8)((R & (__u8)(M_WD_TS ^ 0xFF)) | (__u8)((V & 0x0F) << 4)))
+	#define GET_V_WD_TS(R)    (__u8)((R & M_WD_TS) >> 4)
+
+
+#define R_BERT_ECH 0x1B // register address, read only
+	#define M_BERT_ECH  0xFF  // mask bits 0..7
+	#define GET_V_BERT_ECH(R)    (__u8)(R & M_BERT_ECH)
+
+
+#define R_BERT_WD_MD 0x1B // register address, write only
+	#define M_PAT_SEQ  0x07  // mask bits 0..2
+	#define SET_V_PAT_SEQ(R,V)  (R = (__u8)((R & (__u8)(M_PAT_SEQ ^ 0xFF)) | (__u8)(V & 0x07)))
+	#define GET_V_PAT_SEQ(R)    (__u8)(R & M_PAT_SEQ)
+
+	#define M_BERT_ERR  0x08  // mask bit 3
+	#define SET_V_BERT_ERR(R,V)  (R = (__u8)((R & (__u8)(M_BERT_ERR ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_BERT_ERR(R)    (__u8)((R & M_BERT_ERR) >> 3)
+
+	#define M_AUTO_WD_RES  0x20  // mask bit 5
+	#define SET_V_AUTO_WD_RES(R,V)  (R = (__u8)((R & (__u8)(M_AUTO_WD_RES ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_AUTO_WD_RES(R)    (__u8)((R & M_AUTO_WD_RES) >> 5)
+
+	#define M_WD_RES  0x80  // mask bit 7
+	#define SET_V_WD_RES(R,V)  (R = (__u8)((R & (__u8)(M_WD_RES ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_WD_RES(R)    (__u8)((R & M_WD_RES) >> 7)
+
+
+#define R_STATUS 0x1C // register address, read only
+	#define M_BUSY  0x01  // mask bit 0
+	#define GET_V_BUSY(R)    (__u8)(R & M_BUSY)
+
+	#define M_PROC  0x02  // mask bit 1
+	#define GET_V_PROC(R)    (__u8)((R & M_PROC) >> 1)
+
+	#define M_LOST_STA  0x08  // mask bit 3
+	#define GET_V_LOST_STA(R)    (__u8)((R & M_LOST_STA) >> 3)
+
+	#define M_PCM_INIT  0x10  // mask bit 4
+	#define GET_V_PCM_INIT(R)    (__u8)((R & M_PCM_INIT) >> 4)
+
+	#define M_WAK_STA  0x20  // mask bit 5
+	#define GET_V_WAK_STA(R)    (__u8)((R & M_WAK_STA) >> 5)
+
+	#define M_MISC_IRQSTA  0x40  // mask bit 6
+	#define GET_V_MISC_IRQSTA(R)    (__u8)((R & M_MISC_IRQSTA) >> 6)
+
+	#define M_FIFO_IRQSTA  0x80  // mask bit 7
+	#define GET_V_FIFO_IRQSTA(R)    (__u8)((R & M_FIFO_IRQSTA) >> 7)
+
+
+#define R_SL_MAX 0x1D // register address, read only
+	#define M_SL_MAX  0xFF  // mask bits 0..7
+	#define GET_V_SL_MAX(R)    (__u8)(R & M_SL_MAX)
+
+
+#define R_PWM_CFG 0x1E // register address, write only
+	#define M_PWM0_16KHZ  0x10  // mask bit 4
+	#define SET_V_PWM0_16KHZ(R,V)  (R = (__u8)((R & (__u8)(M_PWM0_16KHZ ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_PWM0_16KHZ(R)    (__u8)((R & M_PWM0_16KHZ) >> 4)
+
+	#define M_PWM1_16KHZ  0x20  // mask bit 5
+	#define SET_V_PWM1_16KHZ(R,V)  (R = (__u8)((R & (__u8)(M_PWM1_16KHZ ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_PWM1_16KHZ(R)    (__u8)((R & M_PWM1_16KHZ) >> 5)
+
+	#define M_PWM_FRQ  0xC0  // mask bits 6..7
+	#define SET_V_PWM_FRQ(R,V)  (R = (__u8)((R & (__u8)(M_PWM_FRQ ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_PWM_FRQ(R)    (__u8)((R & M_PWM_FRQ) >> 6)
+
+
+#define R_CHIP_RV 0x1F // register address, read only
+	#define M_CHIP_RV  0x0F  // mask bits 0..3
+	#define GET_V_CHIP_RV(R)    (__u8)(R & M_CHIP_RV)
+
+
+#define R_FIFO_BL0_IRQ 0x20 // register address, read only
+	#define M_FIFO0_TX_IRQ  0x01  // mask bit 0
+	#define GET_V_FIFO0_TX_IRQ(R)    (__u8)(R & M_FIFO0_TX_IRQ)
+
+	#define M_FIFO0_RX_IRQ  0x02  // mask bit 1
+	#define GET_V_FIFO0_RX_IRQ(R)    (__u8)((R & M_FIFO0_RX_IRQ) >> 1)
+
+	#define M_FIFO1_TX_IRQ  0x04  // mask bit 2
+	#define GET_V_FIFO1_TX_IRQ(R)    (__u8)((R & M_FIFO1_TX_IRQ) >> 2)
+
+	#define M_FIFO1_RX_IRQ  0x08  // mask bit 3
+	#define GET_V_FIFO1_RX_IRQ(R)    (__u8)((R & M_FIFO1_RX_IRQ) >> 3)
+
+	#define M_FIFO2_TX_IRQ  0x10  // mask bit 4
+	#define GET_V_FIFO2_TX_IRQ(R)    (__u8)((R & M_FIFO2_TX_IRQ) >> 4)
+
+	#define M_FIFO2_RX_IRQ  0x20  // mask bit 5
+	#define GET_V_FIFO2_RX_IRQ(R)    (__u8)((R & M_FIFO2_RX_IRQ) >> 5)
+
+	#define M_FIFO3_TX_IRQ  0x40  // mask bit 6
+	#define GET_V_FIFO3_TX_IRQ(R)    (__u8)((R & M_FIFO3_TX_IRQ) >> 6)
+
+	#define M_FIFO3_RX_IRQ  0x80  // mask bit 7
+	#define GET_V_FIFO3_RX_IRQ(R)    (__u8)((R & M_FIFO3_RX_IRQ) >> 7)
+
+
+#define R_FIFO_BL1_IRQ 0x21 // register address, read only
+	#define M_FIFO4_TX_IRQ  0x01  // mask bit 0
+	#define GET_V_FIFO4_TX_IRQ(R)    (__u8)(R & M_FIFO4_TX_IRQ)
+
+	#define M_FIFO4_RX_IRQ  0x02  // mask bit 1
+	#define GET_V_FIFO4_RX_IRQ(R)    (__u8)((R & M_FIFO4_RX_IRQ) >> 1)
+
+	#define M_FIFO5_TX_IRQ  0x04  // mask bit 2
+	#define GET_V_FIFO5_TX_IRQ(R)    (__u8)((R & M_FIFO5_TX_IRQ) >> 2)
+
+	#define M_FIFO5_RX_IRQ  0x08  // mask bit 3
+	#define GET_V_FIFO5_RX_IRQ(R)    (__u8)((R & M_FIFO5_RX_IRQ) >> 3)
+
+	#define M_FIFO6_TX_IRQ  0x10  // mask bit 4
+	#define GET_V_FIFO6_TX_IRQ(R)    (__u8)((R & M_FIFO6_TX_IRQ) >> 4)
+
+	#define M_FIFO6_RX_IRQ  0x20  // mask bit 5
+	#define GET_V_FIFO6_RX_IRQ(R)    (__u8)((R & M_FIFO6_RX_IRQ) >> 5)
+
+	#define M_FIFO7_TX_IRQ  0x40  // mask bit 6
+	#define GET_V_FIFO7_TX_IRQ(R)    (__u8)((R & M_FIFO7_TX_IRQ) >> 6)
+
+	#define M_FIFO7_RX_IRQ  0x80  // mask bit 7
+	#define GET_V_FIFO7_RX_IRQ(R)    (__u8)((R & M_FIFO7_RX_IRQ) >> 7)
+
+
+#define R_FIFO_BL2_IRQ 0x22 // register address, read only
+	#define M_FIFO8_TX_IRQ  0x01  // mask bit 0
+	#define GET_V_FIFO8_TX_IRQ(R)    (__u8)(R & M_FIFO8_TX_IRQ)
+
+	#define M_FIFO8_RX_IRQ  0x02  // mask bit 1
+	#define GET_V_FIFO8_RX_IRQ(R)    (__u8)((R & M_FIFO8_RX_IRQ) >> 1)
+
+	#define M_FIFO9_TX_IRQ  0x04  // mask bit 2
+	#define GET_V_FIFO9_TX_IRQ(R)    (__u8)((R & M_FIFO9_TX_IRQ) >> 2)
+
+	#define M_FIFO9_RX_IRQ  0x08  // mask bit 3
+	#define GET_V_FIFO9_RX_IRQ(R)    (__u8)((R & M_FIFO9_RX_IRQ) >> 3)
+
+	#define M_FIFO10_TX_IRQ  0x10  // mask bit 4
+	#define GET_V_FIFO10_TX_IRQ(R)    (__u8)((R & M_FIFO10_TX_IRQ) >> 4)
+
+	#define M_FIFO10_RX_IRQ  0x20  // mask bit 5
+	#define GET_V_FIFO10_RX_IRQ(R)    (__u8)((R & M_FIFO10_RX_IRQ) >> 5)
+
+	#define M_FIFO11_TX_IRQ  0x40  // mask bit 6
+	#define GET_V_FIFO11_TX_IRQ(R)    (__u8)((R & M_FIFO11_TX_IRQ) >> 6)
+
+	#define M_FIFO11_RX_IRQ  0x80  // mask bit 7
+	#define GET_V_FIFO11_RX_IRQ(R)    (__u8)((R & M_FIFO11_RX_IRQ) >> 7)
+
+
+#define R_FIFO_BL3_IRQ 0x23 // register address, read only
+	#define M_FIFO12_TX_IRQ  0x01  // mask bit 0
+	#define GET_V_FIFO12_TX_IRQ(R)    (__u8)(R & M_FIFO12_TX_IRQ)
+
+	#define M_FIFO12_RX_IRQ  0x02  // mask bit 1
+	#define GET_V_FIFO12_RX_IRQ(R)    (__u8)((R & M_FIFO12_RX_IRQ) >> 1)
+
+	#define M_FIFO13_TX_IRQ  0x04  // mask bit 2
+	#define GET_V_FIFO13_TX_IRQ(R)    (__u8)((R & M_FIFO13_TX_IRQ) >> 2)
+
+	#define M_FIFO13_RX_IRQ  0x08  // mask bit 3
+	#define GET_V_FIFO13_RX_IRQ(R)    (__u8)((R & M_FIFO13_RX_IRQ) >> 3)
+
+	#define M_FIFO14_TX_IRQ  0x10  // mask bit 4
+	#define GET_V_FIFO14_TX_IRQ(R)    (__u8)((R & M_FIFO14_TX_IRQ) >> 4)
+
+	#define M_FIFO14_RX_IRQ  0x20  // mask bit 5
+	#define GET_V_FIFO14_RX_IRQ(R)    (__u8)((R & M_FIFO14_RX_IRQ) >> 5)
+
+	#define M_FIFO15_TX_IRQ  0x40  // mask bit 6
+	#define GET_V_FIFO15_TX_IRQ(R)    (__u8)((R & M_FIFO15_TX_IRQ) >> 6)
+
+	#define M_FIFO15_RX_IRQ  0x80  // mask bit 7
+	#define GET_V_FIFO15_RX_IRQ(R)    (__u8)((R & M_FIFO15_RX_IRQ) >> 7)
+
+
+#define R_FILL_BL0 0x24 // register address, read only
+	#define M_FILL_FIFO0_TX  0x01  // mask bit 0
+	#define GET_V_FILL_FIFO0_TX(R)    (__u8)(R & M_FILL_FIFO0_TX)
+
+	#define M_FILL_FIFO0_RX  0x02  // mask bit 1
+	#define GET_V_FILL_FIFO0_RX(R)    (__u8)((R & M_FILL_FIFO0_RX) >> 1)
+
+	#define M_FILL_FIFO1_TX  0x04  // mask bit 2
+	#define GET_V_FILL_FIFO1_TX(R)    (__u8)((R & M_FILL_FIFO1_TX) >> 2)
+
+	#define M_FILL_FIFO1_RX  0x08  // mask bit 3
+	#define GET_V_FILL_FIFO1_RX(R)    (__u8)((R & M_FILL_FIFO1_RX) >> 3)
+
+	#define M_FILL_FIFO2_TX  0x10  // mask bit 4
+	#define GET_V_FILL_FIFO2_TX(R)    (__u8)((R & M_FILL_FIFO2_TX) >> 4)
+
+	#define M_FILL_FIFO2_RX  0x20  // mask bit 5
+	#define GET_V_FILL_FIFO2_RX(R)    (__u8)((R & M_FILL_FIFO2_RX) >> 5)
+
+	#define M_FILL_FIFO3_TX  0x40  // mask bit 6
+	#define GET_V_FILL_FIFO3_TX(R)    (__u8)((R & M_FILL_FIFO3_TX) >> 6)
+
+	#define M_FILL_FIFO3_RX  0x80  // mask bit 7
+	#define GET_V_FILL_FIFO3_RX(R)    (__u8)((R & M_FILL_FIFO3_RX) >> 7)
+
+
+#define R_FILL_BL1 0x25 // register address, read only
+	#define M_FILL_FIFO4_TX  0x01  // mask bit 0
+	#define GET_V_FILL_FIFO4_TX(R)    (__u8)(R & M_FILL_FIFO4_TX)
+
+	#define M_FILL_FIFO4_RX  0x02  // mask bit 1
+	#define GET_V_FILL_FIFO4_RX(R)    (__u8)((R & M_FILL_FIFO4_RX) >> 1)
+
+	#define M_FILL_FIFO5_TX  0x04  // mask bit 2
+	#define GET_V_FILL_FIFO5_TX(R)    (__u8)((R & M_FILL_FIFO5_TX) >> 2)
+
+	#define M_FILL_FIFO5_RX  0x08  // mask bit 3
+	#define GET_V_FILL_FIFO5_RX(R)    (__u8)((R & M_FILL_FIFO5_RX) >> 3)
+
+	#define M_FILL_FIFO6_TX  0x10  // mask bit 4
+	#define GET_V_FILL_FIFO6_TX(R)    (__u8)((R & M_FILL_FIFO6_TX) >> 4)
+
+	#define M_FILL_FIFO6_RX  0x20  // mask bit 5
+	#define GET_V_FILL_FIFO6_RX(R)    (__u8)((R & M_FILL_FIFO6_RX) >> 5)
+
+	#define M_FILL_FIFO7_TX  0x40  // mask bit 6
+	#define GET_V_FILL_FIFO7_TX(R)    (__u8)((R & M_FILL_FIFO7_TX) >> 6)
+
+	#define M_FILL_FIFO7_RX  0x80  // mask bit 7
+	#define GET_V_FILL_FIFO7_RX(R)    (__u8)((R & M_FILL_FIFO7_RX) >> 7)
+
+
+#define R_FILL_BL2 0x26 // register address, read only
+	#define M_FILL_FIFO8_TX  0x01  // mask bit 0
+	#define GET_V_FILL_FIFO8_TX(R)    (__u8)(R & M_FILL_FIFO8_TX)
+
+	#define M_FILL_FIFO8_RX  0x02  // mask bit 1
+	#define GET_V_FILL_FIFO8_RX(R)    (__u8)((R & M_FILL_FIFO8_RX) >> 1)
+
+	#define M_FILL_FIFO9_TX  0x04  // mask bit 2
+	#define GET_V_FILL_FIFO9_TX(R)    (__u8)((R & M_FILL_FIFO9_TX) >> 2)
+
+	#define M_FILL_FIFO9_RX  0x08  // mask bit 3
+	#define GET_V_FILL_FIFO9_RX(R)    (__u8)((R & M_FILL_FIFO9_RX) >> 3)
+
+	#define M_FILL_FIFO10_TX  0x10  // mask bit 4
+	#define GET_V_FILL_FIFO10_TX(R)    (__u8)((R & M_FILL_FIFO10_TX) >> 4)
+
+	#define M_FILL_FIFO10_RX  0x20  // mask bit 5
+	#define GET_V_FILL_FIFO10_RX(R)    (__u8)((R & M_FILL_FIFO10_RX) >> 5)
+
+	#define M_FILL_FIFO11_TX  0x40  // mask bit 6
+	#define GET_V_FILL_FIFO11_TX(R)    (__u8)((R & M_FILL_FIFO11_TX) >> 6)
+
+	#define M_FILL_FIFO11_RX  0x80  // mask bit 7
+	#define GET_V_FILL_FIFO11_RX(R)    (__u8)((R & M_FILL_FIFO11_RX) >> 7)
+
+
+#define R_FILL_BL3 0x27 // register address, read only
+	#define M_FILL_FIFO12_TX  0x01  // mask bit 0
+	#define GET_V_FILL_FIFO12_TX(R)    (__u8)(R & M_FILL_FIFO12_TX)
+
+	#define M_FILL_FIFO12_RX  0x02  // mask bit 1
+	#define GET_V_FILL_FIFO12_RX(R)    (__u8)((R & M_FILL_FIFO12_RX) >> 1)
+
+	#define M_FILL_FIFO13_TX  0x04  // mask bit 2
+	#define GET_V_FILL_FIFO13_TX(R)    (__u8)((R & M_FILL_FIFO13_TX) >> 2)
+
+	#define M_FILL_FIFO13_RX  0x08  // mask bit 3
+	#define GET_V_FILL_FIFO13_RX(R)    (__u8)((R & M_FILL_FIFO13_RX) >> 3)
+
+	#define M_FILL_FIFO14_TX  0x10  // mask bit 4
+	#define GET_V_FILL_FIFO14_TX(R)    (__u8)((R & M_FILL_FIFO14_TX) >> 4)
+
+	#define M_FILL_FIFO14_RX  0x20  // mask bit 5
+	#define GET_V_FILL_FIFO14_RX(R)    (__u8)((R & M_FILL_FIFO14_RX) >> 5)
+
+	#define M_FILL_FIFO15_TX  0x40  // mask bit 6
+	#define GET_V_FILL_FIFO15_TX(R)    (__u8)((R & M_FILL_FIFO15_TX) >> 6)
+
+	#define M_FILL_FIFO15_RX  0x80  // mask bit 7
+	#define GET_V_FILL_FIFO15_RX(R)    (__u8)((R & M_FILL_FIFO15_RX) >> 7)
+
+
+#define R_CI_TX 0x28 // register address, write only
+	#define M_GCI_C  0x3F  // mask bits 0..5
+	#define SET_V_GCI_C(R,V)  (R = (__u8)((R & (__u8)(M_GCI_C ^ 0xFF)) | (__u8)(V & 0x3F)))
+	#define GET_V_GCI_C(R)    (__u8)(R & M_GCI_C)
+
+
+#define R_CI_RX 0x28 // register address, read only
+	#define M_GCI_I  0x3F  // mask bits 0..5
+	#define GET_V_GCI_I(R)    (__u8)(R & M_GCI_I)
+
+
+#define R_GCI_CFG0 0x29 // register address, write only
+	#define M_MON_END  0x01  // mask bit 0
+	#define SET_V_MON_END(R,V)  (R = (__u8)((R & (__u8)(M_MON_END ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_MON_END(R)    (__u8)(R & M_MON_END)
+
+	#define M_MON_SLOW  0x02  // mask bit 1
+	#define SET_V_MON_SLOW(R,V)  (R = (__u8)((R & (__u8)(M_MON_SLOW ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_MON_SLOW(R)    (__u8)((R & M_MON_SLOW) >> 1)
+
+	#define M_MON_DLL  0x04  // mask bit 2
+	#define SET_V_MON_DLL(R,V)  (R = (__u8)((R & (__u8)(M_MON_DLL ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_MON_DLL(R)    (__u8)((R & M_MON_DLL) >> 2)
+
+	#define M_MON_CI6  0x08  // mask bit 3
+	#define SET_V_MON_CI6(R,V)  (R = (__u8)((R & (__u8)(M_MON_CI6 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_MON_CI6(R)    (__u8)((R & M_MON_CI6) >> 3)
+
+	#define M_GCI_SWAP_TXHS  0x10  // mask bit 4
+	#define SET_V_GCI_SWAP_TXHS(R,V)  (R = (__u8)((R & (__u8)(M_GCI_SWAP_TXHS ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GCI_SWAP_TXHS(R)    (__u8)((R & M_GCI_SWAP_TXHS) >> 4)
+
+	#define M_GCI_SWAP_RXHS  0x20  // mask bit 5
+	#define SET_V_GCI_SWAP_RXHS(R,V)  (R = (__u8)((R & (__u8)(M_GCI_SWAP_RXHS ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GCI_SWAP_RXHS(R)    (__u8)((R & M_GCI_SWAP_RXHS) >> 5)
+
+	#define M_GCI_SWAP_STIO  0x40  // mask bit 6
+	#define SET_V_GCI_SWAP_STIO(R,V)  (R = (__u8)((R & (__u8)(M_GCI_SWAP_STIO ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GCI_SWAP_STIO(R)    (__u8)((R & M_GCI_SWAP_STIO) >> 6)
+
+	#define M_GCI_EN  0x80  // mask bit 7
+	#define SET_V_GCI_EN(R,V)  (R = (__u8)((R & (__u8)(M_GCI_EN ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GCI_EN(R)    (__u8)((R & M_GCI_EN) >> 7)
+
+
+#define R_GCI_STA 0x29 // register address, read only
+	#define M_MON_RXR  0x01  // mask bit 0
+	#define GET_V_MON_RXR(R)    (__u8)(R & M_MON_RXR)
+
+	#define M_MON_TXR  0x02  // mask bit 1
+	#define GET_V_MON_TXR(R)    (__u8)((R & M_MON_TXR) >> 1)
+
+	#define M_GCI_MX  0x04  // mask bit 2
+	#define GET_V_GCI_MX(R)    (__u8)((R & M_GCI_MX) >> 2)
+
+	#define M_GCI_MR  0x08  // mask bit 3
+	#define GET_V_GCI_MR(R)    (__u8)((R & M_GCI_MR) >> 3)
+
+	#define M_GCI_RX  0x10  // mask bit 4
+	#define GET_V_GCI_RX(R)    (__u8)((R & M_GCI_RX) >> 4)
+
+	#define M_GCI_ABO  0x20  // mask bit 5
+	#define GET_V_GCI_ABO(R)    (__u8)((R & M_GCI_ABO) >> 5)
+
+
+#define R_GCI_CFG1 0x2A // register address, write only
+	#define M_GCI_SL  0x1F  // mask bits 0..4
+	#define SET_V_GCI_SL(R,V)  (R = (__u8)((R & (__u8)(M_GCI_SL ^ 0xFF)) | (__u8)(V & 0x1F)))
+	#define GET_V_GCI_SL(R)    (__u8)(R & M_GCI_SL)
+
+
+#define R_MON_RX 0x2A // register address, read only
+	#define M_MON_RX  0xFF  // mask bits 0..7
+	#define GET_V_MON_RX(R)    (__u8)(R & M_MON_RX)
+
+
+#define R_MON_TX 0x2B // register address, write only
+	#define M_MON_TX  0xFF  // mask bits 0..7
+	#define SET_V_MON_TX(R,V)  (R = (__u8)((R & (__u8)(M_MON_TX ^ 0xFF)) | (__u8)V))
+	#define GET_V_MON_TX(R)    (__u8)(R & M_MON_TX)
+
+
+#define A_SU_WR_STA 0x30 // register address, write only
+	#define M_SU_SET_STA  0x0F  // mask bits 0..3
+	#define SET_V_SU_SET_STA(R,V)  (R = (__u8)((R & (__u8)(M_SU_SET_STA ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_SU_SET_STA(R)    (__u8)(R & M_SU_SET_STA)
+
+	#define M_SU_LD_STA  0x10  // mask bit 4
+	#define SET_V_SU_LD_STA(R,V)  (R = (__u8)((R & (__u8)(M_SU_LD_STA ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_SU_LD_STA(R)    (__u8)((R & M_SU_LD_STA) >> 4)
+
+	#define M_SU_ACT  0x60  // mask bits 5..6
+	#define SET_V_SU_ACT(R,V)  (R = (__u8)((R & (__u8)(M_SU_ACT ^ 0xFF)) | (__u8)((V & 0x03) << 5)))
+	#define GET_V_SU_ACT(R)    (__u8)((R & M_SU_ACT) >> 5)
+
+	#define M_SU_SET_G2_G3  0x80  // mask bit 7
+	#define SET_V_SU_SET_G2_G3(R,V)  (R = (__u8)((R & (__u8)(M_SU_SET_G2_G3 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_SU_SET_G2_G3(R)    (__u8)((R & M_SU_SET_G2_G3) >> 7)
+
+
+#define A_SU_RD_STA 0x30 // register address, read only
+	#define M_SU_STA  0x0F  // mask bits 0..3
+	#define GET_V_SU_STA(R)    (__u8)(R & M_SU_STA)
+
+	#define M_SU_FR_SYNC  0x10  // mask bit 4
+	#define GET_V_SU_FR_SYNC(R)    (__u8)((R & M_SU_FR_SYNC) >> 4)
+
+	#define M_SU_T2_EXP  0x20  // mask bit 5
+	#define GET_V_SU_T2_EXP(R)    (__u8)((R & M_SU_T2_EXP) >> 5)
+
+	#define M_SU_INFO0  0x40  // mask bit 6
+	#define GET_V_SU_INFO0(R)    (__u8)((R & M_SU_INFO0) >> 6)
+
+	#define M_G2_G3  0x80  // mask bit 7
+	#define GET_V_G2_G3(R)    (__u8)((R & M_G2_G3) >> 7)
+
+
+#define A_SU_CTRL0 0x31 // register address, write only
+	#define M_B1_TX_EN  0x01  // mask bit 0
+	#define SET_V_B1_TX_EN(R,V)  (R = (__u8)((R & (__u8)(M_B1_TX_EN ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_B1_TX_EN(R)    (__u8)(R & M_B1_TX_EN)
+
+	#define M_B2_TX_EN  0x02  // mask bit 1
+	#define SET_V_B2_TX_EN(R,V)  (R = (__u8)((R & (__u8)(M_B2_TX_EN ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_B2_TX_EN(R)    (__u8)((R & M_B2_TX_EN) >> 1)
+
+	#define M_SU_MD  0x04  // mask bit 2
+	#define SET_V_SU_MD(R,V)  (R = (__u8)((R & (__u8)(M_SU_MD ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_SU_MD(R)    (__u8)((R & M_SU_MD) >> 2)
+
+	#define M_ST_D_LPRIO  0x08  // mask bit 3
+	#define SET_V_ST_D_LPRIO(R,V)  (R = (__u8)((R & (__u8)(M_ST_D_LPRIO ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_ST_D_LPRIO(R)    (__u8)((R & M_ST_D_LPRIO) >> 3)
+
+	#define M_ST_SQ_EN  0x10  // mask bit 4
+	#define SET_V_ST_SQ_EN(R,V)  (R = (__u8)((R & (__u8)(M_ST_SQ_EN ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_ST_SQ_EN(R)    (__u8)((R & M_ST_SQ_EN) >> 4)
+
+	#define M_SU_TST_SIG  0x20  // mask bit 5
+	#define SET_V_SU_TST_SIG(R,V)  (R = (__u8)((R & (__u8)(M_SU_TST_SIG ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_SU_TST_SIG(R)    (__u8)((R & M_SU_TST_SIG) >> 5)
+
+	#define M_ST_PU_CTRL  0x40  // mask bit 6
+	#define SET_V_ST_PU_CTRL(R,V)  (R = (__u8)((R & (__u8)(M_ST_PU_CTRL ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_ST_PU_CTRL(R)    (__u8)((R & M_ST_PU_CTRL) >> 6)
+
+	#define M_SU_STOP  0x80  // mask bit 7
+	#define SET_V_SU_STOP(R,V)  (R = (__u8)((R & (__u8)(M_SU_STOP ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_SU_STOP(R)    (__u8)((R & M_SU_STOP) >> 7)
+
+
+#define A_SU_DLYL 0x31 // register address, read only
+	#define M_SU_DLYL  0x1F  // mask bits 0..4
+	#define GET_V_SU_DLYL(R)    (__u8)(R & M_SU_DLYL)
+
+
+#define A_SU_CTRL1 0x32 // register address, write only
+	#define M_G2_G3_EN  0x01  // mask bit 0
+	#define SET_V_G2_G3_EN(R,V)  (R = (__u8)((R & (__u8)(M_G2_G3_EN ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_G2_G3_EN(R)    (__u8)(R & M_G2_G3_EN)
+
+	#define M_D_RES  0x04  // mask bit 2
+	#define SET_V_D_RES(R,V)  (R = (__u8)((R & (__u8)(M_D_RES ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_D_RES(R)    (__u8)((R & M_D_RES) >> 2)
+
+	#define M_ST_E_IGNO  0x08  // mask bit 3
+	#define SET_V_ST_E_IGNO(R,V)  (R = (__u8)((R & (__u8)(M_ST_E_IGNO ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_ST_E_IGNO(R)    (__u8)((R & M_ST_E_IGNO) >> 3)
+
+	#define M_ST_E_LO  0x10  // mask bit 4
+	#define SET_V_ST_E_LO(R,V)  (R = (__u8)((R & (__u8)(M_ST_E_LO ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_ST_E_LO(R)    (__u8)((R & M_ST_E_LO) >> 4)
+
+	#define M_BAC_D  0x40  // mask bit 6
+	#define SET_V_BAC_D(R,V)  (R = (__u8)((R & (__u8)(M_BAC_D ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_BAC_D(R)    (__u8)((R & M_BAC_D) >> 6)
+
+	#define M_B12_SWAP  0x80  // mask bit 7
+	#define SET_V_B12_SWAP(R,V)  (R = (__u8)((R & (__u8)(M_B12_SWAP ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_B12_SWAP(R)    (__u8)((R & M_B12_SWAP) >> 7)
+
+
+#define A_SU_DLYH 0x32 // register address, read only
+	#define M_SU_DLYH  0x1F  // mask bits 0..4
+	#define GET_V_SU_DLYH(R)    (__u8)(R & M_SU_DLYH)
+
+
+#define A_SU_CTRL2 0x33 // register address, write only
+	#define M_B1_RX_EN  0x01  // mask bit 0
+	#define SET_V_B1_RX_EN(R,V)  (R = (__u8)((R & (__u8)(M_B1_RX_EN ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_B1_RX_EN(R)    (__u8)(R & M_B1_RX_EN)
+
+	#define M_B2_RX_EN  0x02  // mask bit 1
+	#define SET_V_B2_RX_EN(R,V)  (R = (__u8)((R & (__u8)(M_B2_RX_EN ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_B2_RX_EN(R)    (__u8)((R & M_B2_RX_EN) >> 1)
+
+	#define M_MS_SSYNC2  0x04  // mask bit 2
+	#define SET_V_MS_SSYNC2(R,V)  (R = (__u8)((R & (__u8)(M_MS_SSYNC2 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_MS_SSYNC2(R)    (__u8)((R & M_MS_SSYNC2) >> 2)
+
+	#define M_BAC_S_SEL  0x08  // mask bit 3
+	#define SET_V_BAC_S_SEL(R,V)  (R = (__u8)((R & (__u8)(M_BAC_S_SEL ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_BAC_S_SEL(R)    (__u8)((R & M_BAC_S_SEL) >> 3)
+
+	#define M_SU_SYNC_NT  0x10  // mask bit 4
+	#define SET_V_SU_SYNC_NT(R,V)  (R = (__u8)((R & (__u8)(M_SU_SYNC_NT ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_SU_SYNC_NT(R)    (__u8)((R & M_SU_SYNC_NT) >> 4)
+
+	#define M_SU_2KHZ  0x20  // mask bit 5
+	#define SET_V_SU_2KHZ(R,V)  (R = (__u8)((R & (__u8)(M_SU_2KHZ ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_SU_2KHZ(R)    (__u8)((R & M_SU_2KHZ) >> 5)
+
+	#define M_SU_TRI  0x40  // mask bit 6
+	#define SET_V_SU_TRI(R,V)  (R = (__u8)((R & (__u8)(M_SU_TRI ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_SU_TRI(R)    (__u8)((R & M_SU_TRI) >> 6)
+
+	#define M_SU_EXCHG  0x80  // mask bit 7
+	#define SET_V_SU_EXCHG(R,V)  (R = (__u8)((R & (__u8)(M_SU_EXCHG ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_SU_EXCHG(R)    (__u8)((R & M_SU_EXCHG) >> 7)
+
+
+#define A_MS_TX 0x34 // register address, write only
+	#define M_MS_TX  0x0F  // mask bits 0..3
+	#define SET_V_MS_TX(R,V)  (R = (__u8)((R & (__u8)(M_MS_TX ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_MS_TX(R)    (__u8)(R & M_MS_TX)
+
+	#define M_UP_S_TX  0x40  // mask bit 6
+	#define SET_V_UP_S_TX(R,V)  (R = (__u8)((R & (__u8)(M_UP_S_TX ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_UP_S_TX(R)    (__u8)((R & M_UP_S_TX) >> 6)
+
+
+#define A_MS_RX 0x34 // register address, read only
+	#define M_MS_RX  0x0F  // mask bits 0..3
+	#define GET_V_MS_RX(R)    (__u8)(R & M_MS_RX)
+
+	#define M_MS_RX_RDY  0x10  // mask bit 4
+	#define GET_V_MS_RX_RDY(R)    (__u8)((R & M_MS_RX_RDY) >> 4)
+
+	#define M_UP_S_RX  0x40  // mask bit 6
+	#define GET_V_UP_S_RX(R)    (__u8)((R & M_UP_S_RX) >> 6)
+
+	#define M_MS_TX_RDY  0x80  // mask bit 7
+	#define GET_V_MS_TX_RDY(R)    (__u8)((R & M_MS_TX_RDY) >> 7)
+
+
+#define A_ST_CTRL3 0x35 // register address, write only
+	#define M_ST_SEL  0x01  // mask bit 0
+	#define SET_V_ST_SEL(R,V)  (R = (__u8)((R & (__u8)(M_ST_SEL ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_ST_SEL(R)    (__u8)(R & M_ST_SEL)
+
+	#define M_ST_PULSE  0xFE  // mask bits 1..7
+	#define SET_V_ST_PULSE(R,V)  (R = (__u8)((R & (__u8)(M_ST_PULSE ^ 0xFF)) | (__u8)((V & 0x7F) << 1)))
+	#define GET_V_ST_PULSE(R)    (__u8)((R & M_ST_PULSE) >> 1)
+
+
+#define A_UP_CTRL3 0x35 // register address, write only
+	#define M_UP_SEL  0x01  // mask bit 0
+	#define SET_V_UP_SEL(R,V)  (R = (__u8)((R & (__u8)(M_UP_SEL ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_UP_SEL(R)    (__u8)(R & M_UP_SEL)
+
+	#define M_UP_VIO  0x02  // mask bit 1
+	#define SET_V_UP_VIO(R,V)  (R = (__u8)((R & (__u8)(M_UP_VIO ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_UP_VIO(R)    (__u8)((R & M_UP_VIO) >> 1)
+
+	#define M_UP_DC_STR  0x04  // mask bit 2
+	#define SET_V_UP_DC_STR(R,V)  (R = (__u8)((R & (__u8)(M_UP_DC_STR ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_UP_DC_STR(R)    (__u8)((R & M_UP_DC_STR) >> 2)
+
+	#define M_UP_DC_OFF  0x08  // mask bit 3
+	#define SET_V_UP_DC_OFF(R,V)  (R = (__u8)((R & (__u8)(M_UP_DC_OFF ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_UP_DC_OFF(R)    (__u8)((R & M_UP_DC_OFF) >> 3)
+
+	#define M_UP_RPT_PAT  0x10  // mask bit 4
+	#define SET_V_UP_RPT_PAT(R,V)  (R = (__u8)((R & (__u8)(M_UP_RPT_PAT ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_UP_RPT_PAT(R)    (__u8)((R & M_UP_RPT_PAT) >> 4)
+
+	#define M_UP_SCRM_MD  0x20  // mask bit 5
+	#define SET_V_UP_SCRM_MD(R,V)  (R = (__u8)((R & (__u8)(M_UP_SCRM_MD ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_UP_SCRM_MD(R)    (__u8)((R & M_UP_SCRM_MD) >> 5)
+
+	#define M_UP_SCRM_TX_OFF  0x40  // mask bit 6
+	#define SET_V_UP_SCRM_TX_OFF(R,V)  (R = (__u8)((R & (__u8)(M_UP_SCRM_TX_OFF ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_UP_SCRM_TX_OFF(R)    (__u8)((R & M_UP_SCRM_TX_OFF) >> 6)
+
+	#define M_UP_SCRM_RX_OFF  0x80  // mask bit 7
+	#define SET_V_UP_SCRM_RX_OFF(R,V)  (R = (__u8)((R & (__u8)(M_UP_SCRM_RX_OFF ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_UP_SCRM_RX_OFF(R)    (__u8)((R & M_UP_SCRM_RX_OFF) >> 7)
+
+
+#define A_SU_STA 0x35 // register address, read only
+	#define M_ST_D_HPRIO9  0x01  // mask bit 0
+	#define GET_V_ST_D_HPRIO9(R)    (__u8)(R & M_ST_D_HPRIO9)
+
+	#define M_ST_D_LPRIO11  0x02  // mask bit 1
+	#define GET_V_ST_D_LPRIO11(R)    (__u8)((R & M_ST_D_LPRIO11) >> 1)
+
+	#define M_ST_D_CONT  0x04  // mask bit 2
+	#define GET_V_ST_D_CONT(R)    (__u8)((R & M_ST_D_CONT) >> 2)
+
+	#define M_ST_D_ACT  0x08  // mask bit 3
+	#define GET_V_ST_D_ACT(R)    (__u8)((R & M_ST_D_ACT) >> 3)
+
+	#define M_SU_AF0  0x80  // mask bit 7
+	#define GET_V_SU_AF0(R)    (__u8)((R & M_SU_AF0) >> 7)
+
+
+#define A_MS_DF 0x36 // register address, write only
+	#define M_BAC_NINV  0x01  // mask bit 0
+	#define SET_V_BAC_NINV(R,V)  (R = (__u8)((R & (__u8)(M_BAC_NINV ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_BAC_NINV(R)    (__u8)(R & M_BAC_NINV)
+
+	#define M_SG_AB_INV  0x02  // mask bit 1
+	#define SET_V_SG_AB_INV(R,V)  (R = (__u8)((R & (__u8)(M_SG_AB_INV ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_SG_AB_INV(R)    (__u8)((R & M_SG_AB_INV) >> 1)
+
+	#define M_SQ_T_SRC  0x04  // mask bit 2
+	#define SET_V_SQ_T_SRC(R,V)  (R = (__u8)((R & (__u8)(M_SQ_T_SRC ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_SQ_T_SRC(R)    (__u8)((R & M_SQ_T_SRC) >> 2)
+
+	#define M_M_S_SRC  0x08  // mask bit 3
+	#define SET_V_M_S_SRC(R,V)  (R = (__u8)((R & (__u8)(M_M_S_SRC ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_M_S_SRC(R)    (__u8)((R & M_M_S_SRC) >> 3)
+
+	#define M_SQ_T_DST  0x10  // mask bit 4
+	#define SET_V_SQ_T_DST(R,V)  (R = (__u8)((R & (__u8)(M_SQ_T_DST ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_SQ_T_DST(R)    (__u8)((R & M_SQ_T_DST) >> 4)
+
+	#define M_SU_RX_VAL  0x20  // mask bit 5
+	#define SET_V_SU_RX_VAL(R,V)  (R = (__u8)((R & (__u8)(M_SU_RX_VAL ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_SU_RX_VAL(R)    (__u8)((R & M_SU_RX_VAL) >> 5)
+
+
+#define A_SU_CLK_DLY 0x37 // register address, write only
+	#define M_SU_CLK_DLY  0x0F  // mask bits 0..3
+	#define SET_V_SU_CLK_DLY(R,V)  (R = (__u8)((R & (__u8)(M_SU_CLK_DLY ^ 0xFF)) | (__u8)(V & 0x0F)))
+	#define GET_V_SU_CLK_DLY(R)    (__u8)(R & M_SU_CLK_DLY)
+
+	#define M_ST_SMPL  0x70  // mask bits 4..6
+	#define SET_V_ST_SMPL(R,V)  (R = (__u8)((R & (__u8)(M_ST_SMPL ^ 0xFF)) | (__u8)((V & 0x07) << 4)))
+	#define GET_V_ST_SMPL(R)    (__u8)((R & M_ST_SMPL) >> 4)
+
+
+#define R_PWM0 0x38 // register address, write only
+	#define M_PWM0  0xFF  // mask bits 0..7
+	#define SET_V_PWM0(R,V)  (R = (__u8)((R & (__u8)(M_PWM0 ^ 0xFF)) | (__u8)V))
+	#define GET_V_PWM0(R)    (__u8)(R & M_PWM0)
+
+
+#define R_PWM1 0x39 // register address, write only
+	#define M_PWM1  0xFF  // mask bits 0..7
+	#define SET_V_PWM1(R,V)  (R = (__u8)((R & (__u8)(M_PWM1 ^ 0xFF)) | (__u8)V))
+	#define GET_V_PWM1(R)    (__u8)(R & M_PWM1)
+
+
+#define A_B1_TX 0x3C // register address, write only
+	#define M_B1_TX  0xFF  // mask bits 0..7
+	#define SET_V_B1_TX(R,V)  (R = (__u8)((R & (__u8)(M_B1_TX ^ 0xFF)) | (__u8)V))
+	#define GET_V_B1_TX(R)    (__u8)(R & M_B1_TX)
+
+
+#define A_B1_RX 0x3C // register address, read only
+	#define M_B1_RX  0xFF  // mask bits 0..7
+	#define GET_V_B1_RX(R)    (__u8)(R & M_B1_RX)
+
+
+#define A_B2_TX 0x3D // register address, write only
+	#define M_B2_TX  0xFF  // mask bits 0..7
+	#define SET_V_B2_TX(R,V)  (R = (__u8)((R & (__u8)(M_B2_TX ^ 0xFF)) | (__u8)V))
+	#define GET_V_B2_TX(R)    (__u8)(R & M_B2_TX)
+
+
+#define A_B2_RX 0x3D // register address, read only
+	#define M_B2_RX  0xFF  // mask bits 0..7
+	#define GET_V_B2_RX(R)    (__u8)(R & M_B2_RX)
+
+
+#define A_D_TX 0x3E // register address, write only
+	#define M_D_TX_S  0x01  // mask bit 0
+	#define SET_V_D_TX_S(R,V)  (R = (__u8)((R & (__u8)(M_D_TX_S ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_D_TX_S(R)    (__u8)(R & M_D_TX_S)
+
+	#define M_D_TX_BAC  0x20  // mask bit 5
+	#define SET_V_D_TX_BAC(R,V)  (R = (__u8)((R & (__u8)(M_D_TX_BAC ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_D_TX_BAC(R)    (__u8)((R & M_D_TX_BAC) >> 5)
+
+	#define M_D_TX  0xC0  // mask bits 6..7
+	#define SET_V_D_TX(R,V)  (R = (__u8)((R & (__u8)(M_D_TX ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_D_TX(R)    (__u8)((R & M_D_TX) >> 6)
+
+
+#define A_D_RX 0x3E // register address, read only
+	#define M_D_RX_S  0x01  // mask bit 0
+	#define GET_V_D_RX_S(R)    (__u8)(R & M_D_RX_S)
+
+	#define M_D_RX_AB  0x10  // mask bit 4
+	#define GET_V_D_RX_AB(R)    (__u8)((R & M_D_RX_AB) >> 4)
+
+	#define M_D_RX_SG  0x20  // mask bit 5
+	#define GET_V_D_RX_SG(R)    (__u8)((R & M_D_RX_SG) >> 5)
+
+	#define M_D_RX  0xC0  // mask bits 6..7
+	#define GET_V_D_RX(R)    (__u8)((R & M_D_RX) >> 6)
+
+
+#define A_E_RX 0x3F // register address, read only
+	#define M_E_RX_S  0x01  // mask bit 0
+	#define GET_V_E_RX_S(R)    (__u8)(R & M_E_RX_S)
+
+	#define M_E_RX_AB  0x10  // mask bit 4
+	#define GET_V_E_RX_AB(R)    (__u8)((R & M_E_RX_AB) >> 4)
+
+	#define M_E_RX_SG  0x20  // mask bit 5
+	#define GET_V_E_RX_SG(R)    (__u8)((R & M_E_RX_SG) >> 5)
+
+	#define M_E_RX  0xC0  // mask bits 6..7
+	#define GET_V_E_RX(R)    (__u8)((R & M_E_RX) >> 6)
+
+
+#define A_BAC_S_TX 0x3F // register address, write only
+	#define M_S_TX  0x01  // mask bit 0
+	#define SET_V_S_TX(R,V)  (R = (__u8)((R & (__u8)(M_S_TX ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_S_TX(R)    (__u8)(R & M_S_TX)
+
+	#define M_BAC_TX  0x20  // mask bit 5
+	#define SET_V_BAC_TX(R,V)  (R = (__u8)((R & (__u8)(M_BAC_TX ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_BAC_TX(R)    (__u8)((R & M_BAC_TX) >> 5)
+
+
+#define R_GPIO_OUT1 0x40 // register address, write only
+	#define M_GPIO_OUT8  0x01  // mask bit 0
+	#define SET_V_GPIO_OUT8(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT8 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_OUT8(R)    (__u8)(R & M_GPIO_OUT8)
+
+	#define M_GPIO_OUT9  0x02  // mask bit 1
+	#define SET_V_GPIO_OUT9(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT9 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_OUT9(R)    (__u8)((R & M_GPIO_OUT9) >> 1)
+
+	#define M_GPIO_OUT10  0x04  // mask bit 2
+	#define SET_V_GPIO_OUT10(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT10 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_OUT10(R)    (__u8)((R & M_GPIO_OUT10) >> 2)
+
+	#define M_GPIO_OUT11  0x08  // mask bit 3
+	#define SET_V_GPIO_OUT11(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT11 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_OUT11(R)    (__u8)((R & M_GPIO_OUT11) >> 3)
+
+	#define M_GPIO_OUT12  0x10  // mask bit 4
+	#define SET_V_GPIO_OUT12(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT12 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_OUT12(R)    (__u8)((R & M_GPIO_OUT12) >> 4)
+
+	#define M_GPIO_OUT13  0x20  // mask bit 5
+	#define SET_V_GPIO_OUT13(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT13 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_OUT13(R)    (__u8)((R & M_GPIO_OUT13) >> 5)
+
+	#define M_GPIO_OUT14  0x40  // mask bit 6
+	#define SET_V_GPIO_OUT14(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT14 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_OUT14(R)    (__u8)((R & M_GPIO_OUT14) >> 6)
+
+	#define M_GPIO_OUT15  0x80  // mask bit 7
+	#define SET_V_GPIO_OUT15(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT15 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_OUT15(R)    (__u8)((R & M_GPIO_OUT15) >> 7)
+
+
+#define R_GPIO_IN1 0x40 // register address, read only
+	#define M_GPIO_IN8  0x01  // mask bit 0
+	#define GET_V_GPIO_IN8(R)    (__u8)(R & M_GPIO_IN8)
+
+	#define M_GPIO_IN9  0x02  // mask bit 1
+	#define GET_V_GPIO_IN9(R)    (__u8)((R & M_GPIO_IN9) >> 1)
+
+	#define M_GPIO_IN10  0x04  // mask bit 2
+	#define GET_V_GPIO_IN10(R)    (__u8)((R & M_GPIO_IN10) >> 2)
+
+	#define M_GPIO_IN11  0x08  // mask bit 3
+	#define GET_V_GPIO_IN11(R)    (__u8)((R & M_GPIO_IN11) >> 3)
+
+	#define M_GPIO_IN12  0x10  // mask bit 4
+	#define GET_V_GPIO_IN12(R)    (__u8)((R & M_GPIO_IN12) >> 4)
+
+	#define M_GPIO_IN13  0x20  // mask bit 5
+	#define GET_V_GPIO_IN13(R)    (__u8)((R & M_GPIO_IN13) >> 5)
+
+	#define M_GPIO_IN14  0x40  // mask bit 6
+	#define GET_V_GPIO_IN14(R)    (__u8)((R & M_GPIO_IN14) >> 6)
+
+	#define M_GPIO_IN15  0x80  // mask bit 7
+	#define GET_V_GPIO_IN15(R)    (__u8)((R & M_GPIO_IN15) >> 7)
+
+
+#define R_GPIO_OUT3 0x41 // register address, write only
+	#define M_GPIO_OUT24  0x01  // mask bit 0
+	#define SET_V_GPIO_OUT24(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT24 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_OUT24(R)    (__u8)(R & M_GPIO_OUT24)
+
+	#define M_GPIO_OUT25  0x02  // mask bit 1
+	#define SET_V_GPIO_OUT25(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT25 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_OUT25(R)    (__u8)((R & M_GPIO_OUT25) >> 1)
+
+	#define M_GPIO_OUT26  0x04  // mask bit 2
+	#define SET_V_GPIO_OUT26(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT26 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_OUT26(R)    (__u8)((R & M_GPIO_OUT26) >> 2)
+
+	#define M_GPIO_OUT27  0x08  // mask bit 3
+	#define SET_V_GPIO_OUT27(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT27 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_OUT27(R)    (__u8)((R & M_GPIO_OUT27) >> 3)
+
+	#define M_GPIO_OUT28  0x10  // mask bit 4
+	#define SET_V_GPIO_OUT28(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT28 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_OUT28(R)    (__u8)((R & M_GPIO_OUT28) >> 4)
+
+	#define M_GPIO_OUT29  0x20  // mask bit 5
+	#define SET_V_GPIO_OUT29(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT29 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_OUT29(R)    (__u8)((R & M_GPIO_OUT29) >> 5)
+
+	#define M_GPIO_OUT30  0x40  // mask bit 6
+	#define SET_V_GPIO_OUT30(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT30 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_OUT30(R)    (__u8)((R & M_GPIO_OUT30) >> 6)
+
+	#define M_GPIO_OUT31  0x80  // mask bit 7
+	#define SET_V_GPIO_OUT31(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT31 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_OUT31(R)    (__u8)((R & M_GPIO_OUT31) >> 7)
+
+
+#define R_GPIO_IN3 0x41 // register address, read only
+	#define M_GPIO_IN24  0x01  // mask bit 0
+	#define GET_V_GPIO_IN24(R)    (__u8)(R & M_GPIO_IN24)
+
+	#define M_GPIO_IN25  0x02  // mask bit 1
+	#define GET_V_GPIO_IN25(R)    (__u8)((R & M_GPIO_IN25) >> 1)
+
+	#define M_GPIO_IN26  0x04  // mask bit 2
+	#define GET_V_GPIO_IN26(R)    (__u8)((R & M_GPIO_IN26) >> 2)
+
+	#define M_GPIO_IN27  0x08  // mask bit 3
+	#define GET_V_GPIO_IN27(R)    (__u8)((R & M_GPIO_IN27) >> 3)
+
+	#define M_GPIO_IN28  0x10  // mask bit 4
+	#define GET_V_GPIO_IN28(R)    (__u8)((R & M_GPIO_IN28) >> 4)
+
+	#define M_GPIO_IN29  0x20  // mask bit 5
+	#define GET_V_GPIO_IN29(R)    (__u8)((R & M_GPIO_IN29) >> 5)
+
+	#define M_GPIO_IN30  0x40  // mask bit 6
+	#define GET_V_GPIO_IN30(R)    (__u8)((R & M_GPIO_IN30) >> 6)
+
+	#define M_GPIO_IN31  0x80  // mask bit 7
+	#define GET_V_GPIO_IN31(R)    (__u8)((R & M_GPIO_IN31) >> 7)
+
+
+#define R_GPIO_EN1 0x42 // register address, write only
+	#define M_GPIO_EN8  0x01  // mask bit 0
+	#define SET_V_GPIO_EN8(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN8 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_EN8(R)    (__u8)(R & M_GPIO_EN8)
+
+	#define M_GPIO_EN9  0x02  // mask bit 1
+	#define SET_V_GPIO_EN9(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN9 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_EN9(R)    (__u8)((R & M_GPIO_EN9) >> 1)
+
+	#define M_GPIO_EN10  0x04  // mask bit 2
+	#define SET_V_GPIO_EN10(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN10 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_EN10(R)    (__u8)((R & M_GPIO_EN10) >> 2)
+
+	#define M_GPIO_EN11  0x08  // mask bit 3
+	#define SET_V_GPIO_EN11(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN11 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_EN11(R)    (__u8)((R & M_GPIO_EN11) >> 3)
+
+	#define M_GPIO_EN12  0x10  // mask bit 4
+	#define SET_V_GPIO_EN12(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN12 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_EN12(R)    (__u8)((R & M_GPIO_EN12) >> 4)
+
+	#define M_GPIO_EN13  0x20  // mask bit 5
+	#define SET_V_GPIO_EN13(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN13 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_EN13(R)    (__u8)((R & M_GPIO_EN13) >> 5)
+
+	#define M_GPIO_EN14  0x40  // mask bit 6
+	#define SET_V_GPIO_EN14(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN14 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_EN14(R)    (__u8)((R & M_GPIO_EN14) >> 6)
+
+	#define M_GPIO_EN15  0x80  // mask bit 7
+	#define SET_V_GPIO_EN15(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN15 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_EN15(R)    (__u8)((R & M_GPIO_EN15) >> 7)
+
+
+#define R_GPIO_EN3 0x43 // register address, write only
+	#define M_GPIO_EN24  0x01  // mask bit 0
+	#define SET_V_GPIO_EN24(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN24 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_EN24(R)    (__u8)(R & M_GPIO_EN24)
+
+	#define M_GPIO_EN25  0x02  // mask bit 1
+	#define SET_V_GPIO_EN25(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN25 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_EN25(R)    (__u8)((R & M_GPIO_EN25) >> 1)
+
+	#define M_GPIO_EN26  0x04  // mask bit 2
+	#define SET_V_GPIO_EN26(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN26 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_EN26(R)    (__u8)((R & M_GPIO_EN26) >> 2)
+
+	#define M_GPIO_EN27  0x08  // mask bit 3
+	#define SET_V_GPIO_EN27(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN27 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_EN27(R)    (__u8)((R & M_GPIO_EN27) >> 3)
+
+	#define M_GPIO_EN28  0x10  // mask bit 4
+	#define SET_V_GPIO_EN28(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN28 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_EN28(R)    (__u8)((R & M_GPIO_EN28) >> 4)
+
+	#define M_GPIO_EN29  0x20  // mask bit 5
+	#define SET_V_GPIO_EN29(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN29 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_EN29(R)    (__u8)((R & M_GPIO_EN29) >> 5)
+
+	#define M_GPIO_EN30  0x40  // mask bit 6
+	#define SET_V_GPIO_EN30(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN30 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_EN30(R)    (__u8)((R & M_GPIO_EN30) >> 6)
+
+	#define M_GPIO_EN31  0x80  // mask bit 7
+	#define SET_V_GPIO_EN31(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN31 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_EN31(R)    (__u8)((R & M_GPIO_EN31) >> 7)
+
+
+#define R_GPIO_SEL_BL 0x44 // register address, write only
+	#define M_GPIO_BL0  0x01  // mask bit 0
+	#define SET_V_GPIO_BL0(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_BL0 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_BL0(R)    (__u8)(R & M_GPIO_BL0)
+
+	#define M_GPIO_BL1  0x02  // mask bit 1
+	#define SET_V_GPIO_BL1(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_BL1 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_BL1(R)    (__u8)((R & M_GPIO_BL1) >> 1)
+
+	#define M_GPIO_BL2  0x04  // mask bit 2
+	#define SET_V_GPIO_BL2(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_BL2 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_BL2(R)    (__u8)((R & M_GPIO_BL2) >> 2)
+
+	#define M_GPIO_BL3  0x08  // mask bit 3
+	#define SET_V_GPIO_BL3(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_BL3 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_BL3(R)    (__u8)((R & M_GPIO_BL3) >> 3)
+
+
+#define R_GPIO_OUT2 0x45 // register address, write only
+	#define M_GPIO_OUT16  0x01  // mask bit 0
+	#define SET_V_GPIO_OUT16(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT16 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_OUT16(R)    (__u8)(R & M_GPIO_OUT16)
+
+	#define M_GPIO_OUT17  0x02  // mask bit 1
+	#define SET_V_GPIO_OUT17(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT17 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_OUT17(R)    (__u8)((R & M_GPIO_OUT17) >> 1)
+
+	#define M_GPIO_OUT18  0x04  // mask bit 2
+	#define SET_V_GPIO_OUT18(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT18 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_OUT18(R)    (__u8)((R & M_GPIO_OUT18) >> 2)
+
+	#define M_GPIO_OUT19  0x08  // mask bit 3
+	#define SET_V_GPIO_OUT19(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT19 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_OUT19(R)    (__u8)((R & M_GPIO_OUT19) >> 3)
+
+	#define M_GPIO_OUT20  0x10  // mask bit 4
+	#define SET_V_GPIO_OUT20(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT20 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_OUT20(R)    (__u8)((R & M_GPIO_OUT20) >> 4)
+
+	#define M_GPIO_OUT21  0x20  // mask bit 5
+	#define SET_V_GPIO_OUT21(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT21 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_OUT21(R)    (__u8)((R & M_GPIO_OUT21) >> 5)
+
+	#define M_GPIO_OUT22  0x40  // mask bit 6
+	#define SET_V_GPIO_OUT22(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT22 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_OUT22(R)    (__u8)((R & M_GPIO_OUT22) >> 6)
+
+	#define M_GPIO_OUT23  0x80  // mask bit 7
+	#define SET_V_GPIO_OUT23(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT23 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_OUT23(R)    (__u8)((R & M_GPIO_OUT23) >> 7)
+
+
+#define R_GPIO_IN2 0x45 // register address, read only
+	#define M_GPIO_IN16  0x01  // mask bit 0
+	#define GET_V_GPIO_IN16(R)    (__u8)(R & M_GPIO_IN16)
+
+	#define M_GPIO_IN17  0x02  // mask bit 1
+	#define GET_V_GPIO_IN17(R)    (__u8)((R & M_GPIO_IN17) >> 1)
+
+	#define M_GPIO_IN18  0x04  // mask bit 2
+	#define GET_V_GPIO_IN18(R)    (__u8)((R & M_GPIO_IN18) >> 2)
+
+	#define M_GPIO_IN19  0x08  // mask bit 3
+	#define GET_V_GPIO_IN19(R)    (__u8)((R & M_GPIO_IN19) >> 3)
+
+	#define M_GPIO_IN20  0x10  // mask bit 4
+	#define GET_V_GPIO_IN20(R)    (__u8)((R & M_GPIO_IN20) >> 4)
+
+	#define M_GPIO_IN21  0x20  // mask bit 5
+	#define GET_V_GPIO_IN21(R)    (__u8)((R & M_GPIO_IN21) >> 5)
+
+	#define M_GPIO_IN22  0x40  // mask bit 6
+	#define GET_V_GPIO_IN22(R)    (__u8)((R & M_GPIO_IN22) >> 6)
+
+	#define M_GPIO_IN23  0x80  // mask bit 7
+	#define GET_V_GPIO_IN23(R)    (__u8)((R & M_GPIO_IN23) >> 7)
+
+
+#define R_PWM_MD 0x46 // register address, write only
+	#define M_WAK_EN  0x02  // mask bit 1
+	#define SET_V_WAK_EN(R,V)  (R = (__u8)((R & (__u8)(M_WAK_EN ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_WAK_EN(R)    (__u8)((R & M_WAK_EN) >> 1)
+
+	#define M_PWM0_MD  0x30  // mask bits 4..5
+	#define SET_V_PWM0_MD(R,V)  (R = (__u8)((R & (__u8)(M_PWM0_MD ^ 0xFF)) | (__u8)((V & 0x03) << 4)))
+	#define GET_V_PWM0_MD(R)    (__u8)((R & M_PWM0_MD) >> 4)
+
+	#define M_PWM1_MD  0xC0  // mask bits 6..7
+	#define SET_V_PWM1_MD(R,V)  (R = (__u8)((R & (__u8)(M_PWM1_MD ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_PWM1_MD(R)    (__u8)((R & M_PWM1_MD) >> 6)
+
+
+#define R_GPIO_EN2 0x47 // register address, write only
+	#define M_GPIO_EN16  0x01  // mask bit 0
+	#define SET_V_GPIO_EN16(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN16 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_EN16(R)    (__u8)(R & M_GPIO_EN16)
+
+	#define M_GPIO_EN17  0x02  // mask bit 1
+	#define SET_V_GPIO_EN17(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN17 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_EN17(R)    (__u8)((R & M_GPIO_EN17) >> 1)
+
+	#define M_GPIO_EN18  0x04  // mask bit 2
+	#define SET_V_GPIO_EN18(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN18 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_EN18(R)    (__u8)((R & M_GPIO_EN18) >> 2)
+
+	#define M_GPIO_EN19  0x08  // mask bit 3
+	#define SET_V_GPIO_EN19(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN19 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_EN19(R)    (__u8)((R & M_GPIO_EN19) >> 3)
+
+	#define M_GPIO_EN20  0x10  // mask bit 4
+	#define SET_V_GPIO_EN20(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN20 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_EN20(R)    (__u8)((R & M_GPIO_EN20) >> 4)
+
+	#define M_GPIO_EN21  0x20  // mask bit 5
+	#define SET_V_GPIO_EN21(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN21 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_EN21(R)    (__u8)((R & M_GPIO_EN21) >> 5)
+
+	#define M_GPIO_EN22  0x40  // mask bit 6
+	#define SET_V_GPIO_EN22(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN22 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_EN22(R)    (__u8)((R & M_GPIO_EN22) >> 6)
+
+	#define M_GPIO_EN23  0x80  // mask bit 7
+	#define SET_V_GPIO_EN23(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN23 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_EN23(R)    (__u8)((R & M_GPIO_EN23) >> 7)
+
+
+#define R_GPIO_IN0 0x48 // register address, read only
+	#define M_GPIO_IN0  0x01  // mask bit 0
+	#define GET_V_GPIO_IN0(R)    (__u8)(R & M_GPIO_IN0)
+
+	#define M_GPIO_IN1  0x02  // mask bit 1
+	#define GET_V_GPIO_IN1(R)    (__u8)((R & M_GPIO_IN1) >> 1)
+
+	#define M_GPIO_IN2  0x04  // mask bit 2
+	#define GET_V_GPIO_IN2(R)    (__u8)((R & M_GPIO_IN2) >> 2)
+
+	#define M_GPIO_IN3  0x08  // mask bit 3
+	#define GET_V_GPIO_IN3(R)    (__u8)((R & M_GPIO_IN3) >> 3)
+
+	#define M_GPIO_IN4  0x10  // mask bit 4
+	#define GET_V_GPIO_IN4(R)    (__u8)((R & M_GPIO_IN4) >> 4)
+
+	#define M_GPIO_IN5  0x20  // mask bit 5
+	#define GET_V_GPIO_IN5(R)    (__u8)((R & M_GPIO_IN5) >> 5)
+
+	#define M_GPIO_IN6  0x40  // mask bit 6
+	#define GET_V_GPIO_IN6(R)    (__u8)((R & M_GPIO_IN6) >> 6)
+
+	#define M_GPIO_IN7  0x80  // mask bit 7
+	#define GET_V_GPIO_IN7(R)    (__u8)((R & M_GPIO_IN7) >> 7)
+
+
+#define R_GPIO_OUT0 0x48 // register address, write only
+	#define M_GPIO_OUT0  0x01  // mask bit 0
+	#define SET_V_GPIO_OUT0(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT0 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_OUT0(R)    (__u8)(R & M_GPIO_OUT0)
+
+	#define M_GPIO_OUT1  0x02  // mask bit 1
+	#define SET_V_GPIO_OUT1(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT1 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_OUT1(R)    (__u8)((R & M_GPIO_OUT1) >> 1)
+
+	#define M_GPIO_OUT2  0x04  // mask bit 2
+	#define SET_V_GPIO_OUT2(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT2 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_OUT2(R)    (__u8)((R & M_GPIO_OUT2) >> 2)
+
+	#define M_GPIO_OUT3  0x08  // mask bit 3
+	#define SET_V_GPIO_OUT3(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT3 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_OUT3(R)    (__u8)((R & M_GPIO_OUT3) >> 3)
+
+	#define M_GPIO_OUT4  0x10  // mask bit 4
+	#define SET_V_GPIO_OUT4(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT4 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_OUT4(R)    (__u8)((R & M_GPIO_OUT4) >> 4)
+
+	#define M_GPIO_OUT5  0x20  // mask bit 5
+	#define SET_V_GPIO_OUT5(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT5 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_OUT5(R)    (__u8)((R & M_GPIO_OUT5) >> 5)
+
+	#define M_GPIO_OUT6  0x40  // mask bit 6
+	#define SET_V_GPIO_OUT6(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT6 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_OUT6(R)    (__u8)((R & M_GPIO_OUT6) >> 6)
+
+	#define M_GPIO_OUT7  0x80  // mask bit 7
+	#define SET_V_GPIO_OUT7(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_OUT7 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_OUT7(R)    (__u8)((R & M_GPIO_OUT7) >> 7)
+
+
+#define R_GPIO_EN0 0x4A // register address, write only
+	#define M_GPIO_EN0  0x01  // mask bit 0
+	#define SET_V_GPIO_EN0(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN0 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_EN0(R)    (__u8)(R & M_GPIO_EN0)
+
+	#define M_GPIO_EN1  0x02  // mask bit 1
+	#define SET_V_GPIO_EN1(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN1 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_EN1(R)    (__u8)((R & M_GPIO_EN1) >> 1)
+
+	#define M_GPIO_EN2  0x04  // mask bit 2
+	#define SET_V_GPIO_EN2(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN2 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_EN2(R)    (__u8)((R & M_GPIO_EN2) >> 2)
+
+	#define M_GPIO_EN3  0x08  // mask bit 3
+	#define SET_V_GPIO_EN3(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN3 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_EN3(R)    (__u8)((R & M_GPIO_EN3) >> 3)
+
+	#define M_GPIO_EN4  0x10  // mask bit 4
+	#define SET_V_GPIO_EN4(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN4 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_EN4(R)    (__u8)((R & M_GPIO_EN4) >> 4)
+
+	#define M_GPIO_EN5  0x20  // mask bit 5
+	#define SET_V_GPIO_EN5(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN5 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_EN5(R)    (__u8)((R & M_GPIO_EN5) >> 5)
+
+	#define M_GPIO_EN6  0x40  // mask bit 6
+	#define SET_V_GPIO_EN6(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN6 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_EN6(R)    (__u8)((R & M_GPIO_EN6) >> 6)
+
+	#define M_GPIO_EN7  0x80  // mask bit 7
+	#define SET_V_GPIO_EN7(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_EN7 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_EN7(R)    (__u8)((R & M_GPIO_EN7) >> 7)
+
+
+#define R_GPIO_SEL 0x4C // register address, write only
+	#define M_GPIO_SEL0  0x01  // mask bit 0
+	#define SET_V_GPIO_SEL0(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL0 ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_GPIO_SEL0(R)    (__u8)(R & M_GPIO_SEL0)
+
+	#define M_GPIO_SEL1  0x02  // mask bit 1
+	#define SET_V_GPIO_SEL1(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL1 ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_GPIO_SEL1(R)    (__u8)((R & M_GPIO_SEL1) >> 1)
+
+	#define M_GPIO_SEL2  0x04  // mask bit 2
+	#define SET_V_GPIO_SEL2(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL2 ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_GPIO_SEL2(R)    (__u8)((R & M_GPIO_SEL2) >> 2)
+
+	#define M_GPIO_SEL3  0x08  // mask bit 3
+	#define SET_V_GPIO_SEL3(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL3 ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_GPIO_SEL3(R)    (__u8)((R & M_GPIO_SEL3) >> 3)
+
+	#define M_GPIO_SEL4  0x10  // mask bit 4
+	#define SET_V_GPIO_SEL4(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL4 ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_GPIO_SEL4(R)    (__u8)((R & M_GPIO_SEL4) >> 4)
+
+	#define M_GPIO_SEL5  0x20  // mask bit 5
+	#define SET_V_GPIO_SEL5(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL5 ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_GPIO_SEL5(R)    (__u8)((R & M_GPIO_SEL5) >> 5)
+
+	#define M_GPIO_SEL6  0x40  // mask bit 6
+	#define SET_V_GPIO_SEL6(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL6 ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_GPIO_SEL6(R)    (__u8)((R & M_GPIO_SEL6) >> 6)
+
+	#define M_GPIO_SEL7  0x80  // mask bit 7
+	#define SET_V_GPIO_SEL7(R,V)  (R = (__u8)((R & (__u8)(M_GPIO_SEL7 ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_GPIO_SEL7(R)    (__u8)((R & M_GPIO_SEL7) >> 7)
+
+
+#define R_PLL_STA 0x50 // register address, read only
+	#define M_PLL_LOCK  0x80  // mask bit 7
+	#define GET_V_PLL_LOCK(R)    (__u8)((R & M_PLL_LOCK) >> 7)
+
+
+#define R_PLL_CTRL 0x50 // register address, write only
+	#define M_PLL_NRES  0x01  // mask bit 0
+	#define SET_V_PLL_NRES(R,V)  (R = (__u8)((R & (__u8)(M_PLL_NRES ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_PLL_NRES(R)    (__u8)(R & M_PLL_NRES)
+
+	#define M_PLL_TST  0x02  // mask bit 1
+	#define SET_V_PLL_TST(R,V)  (R = (__u8)((R & (__u8)(M_PLL_TST ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_PLL_TST(R)    (__u8)((R & M_PLL_TST) >> 1)
+
+	#define M_PLL_FREEZE  0x20  // mask bit 5
+	#define SET_V_PLL_FREEZE(R,V)  (R = (__u8)((R & (__u8)(M_PLL_FREEZE ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_PLL_FREEZE(R)    (__u8)((R & M_PLL_FREEZE) >> 5)
+
+	#define M_PLL_M  0xC0  // mask bits 6..7
+	#define SET_V_PLL_M(R,V)  (R = (__u8)((R & (__u8)(M_PLL_M ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_PLL_M(R)    (__u8)((R & M_PLL_M) >> 6)
+
+
+#define R_PLL_P 0x51 // register address, read/write
+	#define M_PLL_P  0xFF  // mask bits 0..7
+	#define SET_V_PLL_P(R,V)  (R = (__u8)((R & (__u8)(M_PLL_P ^ 0xFF)) | (__u8)V))
+	#define GET_V_PLL_P(R)    (__u8)(R & M_PLL_P)
+
+
+#define R_PLL_N 0x52 // register address, read/write
+	#define M_PLL_N  0xFF  // mask bits 0..7
+	#define SET_V_PLL_N(R,V)  (R = (__u8)((R & (__u8)(M_PLL_N ^ 0xFF)) | (__u8)V))
+	#define GET_V_PLL_N(R)    (__u8)(R & M_PLL_N)
+
+
+#define R_PLL_S 0x53 // register address, read/write
+	#define M_PLL_S  0xFF  // mask bits 0..7
+	#define SET_V_PLL_S(R,V)  (R = (__u8)((R & (__u8)(M_PLL_S ^ 0xFF)) | (__u8)V))
+	#define GET_V_PLL_S(R)    (__u8)(R & M_PLL_S)
+
+
+#define A_FIFO_DATA 0x80 // register address, read/write
+	#define M_FIFO_DATA  0xFF  // mask bits 0..7
+	#define SET_V_FIFO_DATA(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_DATA ^ 0xFF)) | (__u8)V))
+	#define GET_V_FIFO_DATA(R)    (__u8)(R & M_FIFO_DATA)
+
+
+#define A_FIFO_DATA_NOINC 0x84 // register address, read/write
+	#define M_FIFO_DATA_NOINC  0xFF  // mask bits 0..7
+	#define SET_V_FIFO_DATA_NOINC(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_DATA_NOINC ^ 0xFF)) | (__u8)V))
+	#define GET_V_FIFO_DATA_NOINC(R)    (__u8)(R & M_FIFO_DATA_NOINC)
+
+
+#define R_INT_DATA 0x88 // register address, read only
+	#define M_INT_DATA  0xFF  // mask bits 0..7
+	#define GET_V_INT_DATA(R)    (__u8)(R & M_INT_DATA)
+
+
+#define R_RAM_DATA 0xC0 // register address, r*/w
+	#define M_RAM_DATA  0xFF  // mask bits 0..7
+	#define SET_V_RAM_DATA(R,V)  (R = (__u8)((R & (__u8)(M_RAM_DATA ^ 0xFF)) | (__u8)V))
+	#define GET_V_RAM_DATA(R)    (__u8)(R & M_RAM_DATA)
+
+
+#define A_SL_CFG 0xD0 // register address, r*/w
+	#define M_CH_SDIR  0x01  // mask bit 0
+	#define SET_V_CH_SDIR(R,V)  (R = (__u8)((R & (__u8)(M_CH_SDIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_CH_SDIR(R)    (__u8)(R & M_CH_SDIR)
+
+	#define M_CH_SNUM  0x3E  // mask bits 1..5
+	#define SET_V_CH_SNUM(R,V)  (R = (__u8)((R & (__u8)(M_CH_SNUM ^ 0xFF)) | (__u8)((V & 0x1F) << 1)))
+	#define GET_V_CH_SNUM(R)    (__u8)((R & M_CH_SNUM) >> 1)
+
+	#define M_ROUT  0xC0  // mask bits 6..7
+	#define SET_V_ROUT(R,V)  (R = (__u8)((R & (__u8)(M_ROUT ^ 0xFF)) | (__u8)((V & 0x03) << 6)))
+	#define GET_V_ROUT(R)    (__u8)((R & M_ROUT) >> 6)
+
+
+#define A_CH_MSK 0xF4 // register address, r*/w
+	#define M_CH_MSK  0xFF  // mask bits 0..7
+	#define SET_V_CH_MSK(R,V)  (R = (__u8)((R & (__u8)(M_CH_MSK ^ 0xFF)) | (__u8)V))
+	#define GET_V_CH_MSK(R)    (__u8)(R & M_CH_MSK)
+
+
+#define A_CON_HDLC 0xFA // register address, r*/w
+	#define M_IFF  0x01  // mask bit 0
+	#define SET_V_IFF(R,V)  (R = (__u8)((R & (__u8)(M_IFF ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_IFF(R)    (__u8)(R & M_IFF)
+
+	#define M_HDLC_TRP  0x02  // mask bit 1
+	#define SET_V_HDLC_TRP(R,V)  (R = (__u8)((R & (__u8)(M_HDLC_TRP ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_HDLC_TRP(R)    (__u8)((R & M_HDLC_TRP) >> 1)
+
+	#define M_FIFO_IRQ  0x1C  // mask bits 2..4
+	#define SET_V_FIFO_IRQ(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_IRQ ^ 0xFF)) | (__u8)((V & 0x07) << 2)))
+	#define GET_V_FIFO_IRQ(R)    (__u8)((R & M_FIFO_IRQ) >> 2)
+
+	#define M_DATA_FLOW  0xE0  // mask bits 5..7
+	#define SET_V_DATA_FLOW(R,V)  (R = (__u8)((R & (__u8)(M_DATA_FLOW ^ 0xFF)) | (__u8)((V & 0x07) << 5)))
+	#define GET_V_DATA_FLOW(R)    (__u8)((R & M_DATA_FLOW) >> 5)
+
+
+#define A_SUBCH_CFG 0xFB // register address, r*/w
+	#define M_BIT_CNT  0x07  // mask bits 0..2
+	#define SET_V_BIT_CNT(R,V)  (R = (__u8)((R & (__u8)(M_BIT_CNT ^ 0xFF)) | (__u8)(V & 0x07)))
+	#define GET_V_BIT_CNT(R)    (__u8)(R & M_BIT_CNT)
+
+	#define M_START_BIT  0x38  // mask bits 3..5
+	#define SET_V_START_BIT(R,V)  (R = (__u8)((R & (__u8)(M_START_BIT ^ 0xFF)) | (__u8)((V & 0x07) << 3)))
+	#define GET_V_START_BIT(R)    (__u8)((R & M_START_BIT) >> 3)
+
+	#define M_LOOP_FIFO  0x40  // mask bit 6
+	#define SET_V_LOOP_FIFO(R,V)  (R = (__u8)((R & (__u8)(M_LOOP_FIFO ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_LOOP_FIFO(R)    (__u8)((R & M_LOOP_FIFO) >> 6)
+
+	#define M_INV_DATA  0x80  // mask bit 7
+	#define SET_V_INV_DATA(R,V)  (R = (__u8)((R & (__u8)(M_INV_DATA ^ 0xFF)) | (__u8)((V & 0x01) << 7)))
+	#define GET_V_INV_DATA(R)    (__u8)((R & M_INV_DATA) >> 7)
+
+
+#define A_CHANNEL 0xFC // register address, r*/w
+	#define M_CH_FDIR  0x01  // mask bit 0
+	#define SET_V_CH_FDIR(R,V)  (R = (__u8)((R & (__u8)(M_CH_FDIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_CH_FDIR(R)    (__u8)(R & M_CH_FDIR)
+
+	#define M_CH_FNUM  0x1E  // mask bits 1..4
+	#define SET_V_CH_FNUM(R,V)  (R = (__u8)((R & (__u8)(M_CH_FNUM ^ 0xFF)) | (__u8)((V & 0x0F) << 1)))
+	#define GET_V_CH_FNUM(R)    (__u8)((R & M_CH_FNUM) >> 1)
+
+
+#define A_FIFO_SEQ 0xFD // register address, r*/w
+	#define M_NEXT_FIFO_DIR  0x01  // mask bit 0
+	#define SET_V_NEXT_FIFO_DIR(R,V)  (R = (__u8)((R & (__u8)(M_NEXT_FIFO_DIR ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_NEXT_FIFO_DIR(R)    (__u8)(R & M_NEXT_FIFO_DIR)
+
+	#define M_NEXT_FIFO_NUM  0x1E  // mask bits 1..4
+	#define SET_V_NEXT_FIFO_NUM(R,V)  (R = (__u8)((R & (__u8)(M_NEXT_FIFO_NUM ^ 0xFF)) | (__u8)((V & 0x0F) << 1)))
+	#define GET_V_NEXT_FIFO_NUM(R)    (__u8)((R & M_NEXT_FIFO_NUM) >> 1)
+
+	#define M_SEQ_END  0x40  // mask bit 6
+	#define SET_V_SEQ_END(R,V)  (R = (__u8)((R & (__u8)(M_SEQ_END ^ 0xFF)) | (__u8)((V & 0x01) << 6)))
+	#define GET_V_SEQ_END(R)    (__u8)((R & M_SEQ_END) >> 6)
+
+
+#define A_FIFO_CTRL 0xFF // register address, r*/w
+	#define M_FIFO_IRQMSK  0x01  // mask bit 0
+	#define SET_V_FIFO_IRQMSK(R,V)  (R = (__u8)((R & (__u8)(M_FIFO_IRQMSK ^ 0xFF)) | (__u8)(V & 0x01)))
+	#define GET_V_FIFO_IRQMSK(R)    (__u8)(R & M_FIFO_IRQMSK)
+
+	#define M_BERT_EN  0x02  // mask bit 1
+	#define SET_V_BERT_EN(R,V)  (R = (__u8)((R & (__u8)(M_BERT_EN ^ 0xFF)) | (__u8)((V & 0x01) << 1)))
+	#define GET_V_BERT_EN(R)    (__u8)((R & M_BERT_EN) >> 1)
+
+	#define M_MIX_IRQ  0x04  // mask bit 2
+	#define SET_V_MIX_IRQ(R,V)  (R = (__u8)((R & (__u8)(M_MIX_IRQ ^ 0xFF)) | (__u8)((V & 0x01) << 2)))
+	#define GET_V_MIX_IRQ(R)    (__u8)((R & M_MIX_IRQ) >> 2)
+
+	#define M_FR_ABO  0x08  // mask bit 3
+	#define SET_V_FR_ABO(R,V)  (R = (__u8)((R & (__u8)(M_FR_ABO ^ 0xFF)) | (__u8)((V & 0x01) << 3)))
+	#define GET_V_FR_ABO(R)    (__u8)((R & M_FR_ABO) >> 3)
+
+	#define M_NO_CRC  0x10  // mask bit 4
+	#define SET_V_NO_CRC(R,V)  (R = (__u8)((R & (__u8)(M_NO_CRC ^ 0xFF)) | (__u8)((V & 0x01) << 4)))
+	#define GET_V_NO_CRC(R)    (__u8)((R & M_NO_CRC) >> 4)
+
+	#define M_NO_REP  0x20  // mask bit 5
+	#define SET_V_NO_REP(R,V)  (R = (__u8)((R & (__u8)(M_NO_REP ^ 0xFF)) | (__u8)((V & 0x01) << 5)))
+	#define GET_V_NO_REP(R)    (__u8)((R & M_NO_REP) >> 5)
+
+
+#endif /* _XHFC24SUCD_H_ */
diff --git a/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c b/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c
new file mode 100644
index 000000000..1a5b0dc4f
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c
@@ -0,0 +1,810 @@
+/* xhfc_pci2pi.c
+ * PCI2PI Pci Bridge support for xhfc_su.c
+ *
+ * (C) 2007 Copyright Cologne Chip AG
+ * Authors : Joerg Ciesielski, Martin Bachem
+ * Contact : info@colognechip.com
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "xhfc_su.h"
+#include "xhfc_pci2pi.h"
+
+static int card_cnt = 0;
+static LIST_HEAD(card_list);
+static DEFINE_RWLOCK(card_lock);
+
+
+static struct pci_device_id xhfc_ids[] = {
+	{
+	 .vendor = PCI_VENDOR_ID_CCD,
+	 .device = 0xA003,
+	 .subvendor = 0x1397,
+	 .subdevice = 0xA003,
+	 /* CCAG XHFC Eval Board with using 1 XHFC */
+	 .driver_data = (unsigned long)
+	 &((struct pi_params) {
+			       "XHFC Evaluation Board",
+			       1})
+	 },
+	{}
+};
+
+static struct pci_driver xhfc_driver = {
+      name:DRIVER_NAME,
+      probe:xhfc_pci_probe,
+      remove:xhfc_pci_remove,
+      id_table:xhfc_ids,
+};
+
+/*
+ * PCI hotplug interface: probe new card
+ *  every PCI card will alloc mem for one 'struct xhfc_pi'
+ *  and alloc 'struct xhfc' at pi->xhfc for every XHFC expected
+ *  on that PCI card
+ */
+int
+xhfc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct pi_params *driver_data =
+	    (struct pi_params *) ent->driver_data;
+	struct xhfc_pi *pi = NULL;
+	__u8 i;
+	u_long flags;
+
+	int err = -ENOMEM;
+
+	/* alloc mem for ProcessorInterface xhfc_pi */
+	if (!(pi = kzalloc(sizeof(struct xhfc_pi), GFP_KERNEL))) {
+		printk(KERN_ERR "%s: No kmem for XHFC card\n",
+		       __FUNCTION__);
+		goto out;
+	}
+
+	pi->cardnum = card_cnt;
+
+	sprintf(pi->name, "%s_PI%d", DRIVER_NAME, pi->cardnum);
+	printk(KERN_INFO
+	       "%s %s: adapter '%s' found on PCI bus %02x dev %02x"
+	       ", using %i XHFC controllers\n", pi->name, __FUNCTION__,
+	       driver_data->device_name, pdev->bus->number, pdev->devfn,
+	       driver_data->num_xhfcs);
+
+	/* alloc mem for all XHFCs (xhfc_t) */
+	if (!
+	    (pi->xhfc =
+	     kzalloc(sizeof(struct xhfc) * driver_data->num_xhfcs,
+		     GFP_KERNEL))) {
+		printk(KERN_ERR "%s %s: No kmem for sizeof(xhfc_t)*%i \n",
+		       pi->name, __FUNCTION__, driver_data->num_xhfcs);
+		goto out;
+	}
+
+	pi->pdev = pdev;
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s %s: error with pci_enable_device\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	if (driver_data->num_xhfcs > PCI2PI_MAX_XHFC) {
+		printk(KERN_ERR
+		       "%s %s: max no of addressable XHFCs reached\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	pi->driver_data = *driver_data;
+	pi->irq = pdev->irq;
+	pi->hw_membase = (u_char *) pci_resource_start(pdev, 1);
+	pi->membase = ioremap((ulong) pi->hw_membase, 4096);
+	pci_set_drvdata(pdev, pi);
+
+	err = init_pci_bridge(pi);
+	if (err) {
+		printk(KERN_ERR "%s %s: init_pci_bridge failed!\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	/* init interrupt engine */
+	if (request_irq(pi->irq, xhfc_interrupt, IRQF_SHARED, "XHFC", pi)) {
+		printk(KERN_WARNING "%s %s: couldn't get interrupt %d\n",
+		       pi->name, __FUNCTION__, pi->irq);
+		pi->irq = 0;
+		err = -EIO;
+		goto out;
+	}
+
+	err = 0;
+	pi->num_xhfcs = pi->driver_data.num_xhfcs;
+	for (i = 0; i < pi->num_xhfcs; i++) {
+		pi->xhfc[i].pi = pi;
+		pi->xhfc[i].chipidx = i;
+		err |= setup_instance(&pi->xhfc[i], pdev->dev.parent);
+	}
+
+	if (!err) {
+		card_cnt++;
+		write_lock_irqsave(&card_lock, flags);
+		list_add_tail(&pi->list, &card_list);
+		write_unlock_irqrestore(&card_lock, flags);
+		return (0);
+	} else {
+		goto out;
+	}
+
+      out:
+	if (pi->xhfc)
+		kfree(pi->xhfc);
+	if (pi)
+		kfree(pi);
+	return (err);
+}
+
+/*
+ * PCI hotplug interface: remove card
+ */
+void
+xhfc_pci_remove(struct pci_dev *pdev)
+{
+	int i;
+
+	struct xhfc_pi *pi = pci_get_drvdata(pdev);
+	printk(KERN_INFO "%s %s: removing card\n", pi->name, __FUNCTION__);
+
+	for (i = 0; i < pi->num_xhfcs; i++)
+		disable_interrupts(&pi->xhfc[i]);
+	free_irq(pi->irq, pi);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 10);
+	for (i = 0; i < pi->driver_data.num_xhfcs; i++)
+		release_instance(&pi->xhfc[i]);
+	kfree(pi);
+	card_cnt--;
+	pci_disable_device(pdev);
+	return;
+}
+
+int
+xhfc_register_pi(void)
+{
+	return pci_register_driver(&xhfc_driver);
+}
+
+int
+xhfc_unregister_pi(void)
+{
+	pci_unregister_driver(&xhfc_driver);
+	return 0;
+}
+
+
+/******************************************************************************/
+
+
+static struct PCI2PI_cfg PCI2PI_config = {
+	0,			// .del_cs
+	0,			// .del_rd
+	0,			// .del_wr
+	0,			// .del_ale
+	0,			// .del_adr
+	0,			// .del_dout
+	0x00,			// .default_adr
+	0x00,			// .default_dout
+	PI_MODE,		// .pi_mode
+	1,			// .setup
+	1,			// .hold
+	1,			// .cycle
+	0,			// .ale_adr_first
+	0,			// .ale_adr_setup
+	1,			// .ale_adr_hold
+	0,			// .ale_adr_wait
+	1,			// .pause_seq
+	0,			// .pause_end
+	0,			// .gpio_out
+	1,			// .status_int_enable
+	0,			// .pi_int_pol
+	0,			// .pi_wait_enable
+	0,			// .spi_cfg0
+	2,			// .spi_cfg1
+	0,			// .spi_cfg2
+	0,			// .spi_cfg3
+	4,			// .eep_recover
+};
+
+/* base addr to address several XHFCs on one PCI2PI bridge */
+__u32 PCI2PI_XHFC_OFFSETS[PCI2PI_MAX_XHFC] = { 0, 0x400 };
+
+
+/* read and write functions to access registers of the PCI bridge */
+
+static inline __u8
+ReadPCI2PI_u8(struct xhfc_pi *pi, __u16 reg_addr)
+{
+	return (*(volatile __u8 *) (pi->membase + reg_addr));
+}
+
+static inline __u16
+ReadPCI2PI_u16(struct xhfc_pi *pi, __u16 reg_addr)
+{
+	return (*(volatile __u16 *) (pi->membase + reg_addr));
+}
+
+static inline __u32
+ReadPCI2PI_u32(struct xhfc_pi *pi, __u16 reg_addr)
+{
+	return (*(volatile __u32 *) (pi->membase + reg_addr));
+}
+
+static inline void
+WritePCI2PI_u8(struct xhfc_pi *pi, __u16 reg_addr, __u8 value)
+{
+	*((volatile __u8 *) (pi->membase + reg_addr)) = value;
+}
+
+static inline void
+WritePCI2PI_u16(struct xhfc_pi *pi, __u16 reg_addr, __u16 value)
+{
+	*((volatile __u16 *) (pi->membase + reg_addr)) = value;
+}
+
+static inline void
+WritePCI2PI_u32(struct xhfc_pi *pi, __u16 reg_addr, __u32 value)
+{
+	*((volatile __u32 *) (pi->membase + reg_addr)) = value;
+}
+
+/*
+ * initialise the XHFC PCI Bridge
+ * return 0 on success.
+ */
+int
+init_pci_bridge(struct xhfc_pi *pi)
+{
+	int err = -ENODEV;
+
+	printk(KERN_INFO
+	       "%s %s: using PCI2PI Bridge at 0x%p, PI-Mode(0x%x)\n",
+	       pi->name, __FUNCTION__, pi->hw_membase,
+	       PCI2PI_config.pi_mode);
+
+	spin_lock_init(&pi->lock);
+
+	/* test if Bridge regsiter accessable */
+	WritePCI2PI_u32(pi, PCI2PI_DEL_CS, 0x0);
+	if (ReadPCI2PI_u32(pi, PCI2PI_DEL_CS) == 0x00) {
+		WritePCI2PI_u32(pi, PCI2PI_DEL_CS, 0xFFFFFFFF);
+		if (ReadPCI2PI_u32(pi, PCI2PI_DEL_CS) == 0xF) {
+			err = 0;
+		}
+	}
+	if (err)
+		return (err);
+
+	/* enable hardware reset XHFC */
+	WritePCI2PI_u32(pi, PCI2PI_GPIO_OUT, GPIO_OUT_VAL);
+
+	WritePCI2PI_u32(pi, PCI2PI_PI_MODE, PCI2PI_config.pi_mode);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_CS, PCI2PI_config.del_cs);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_RD, PCI2PI_config.del_rd);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_WR, PCI2PI_config.del_wr);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_ALE, PCI2PI_config.del_ale);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_ADR, PCI2PI_config.del_adr);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_DOUT, PCI2PI_config.del_dout);
+	WritePCI2PI_u32(pi, PCI2PI_DEFAULT_ADR, PCI2PI_config.default_adr);
+	WritePCI2PI_u32(pi, PCI2PI_DEFAULT_DOUT,
+			PCI2PI_config.default_dout);
+
+	WritePCI2PI_u32(pi, PCI2PI_CYCLE_SHD, 0x80 * PCI2PI_config.setup
+			+ 0x40 * PCI2PI_config.hold + PCI2PI_config.cycle);
+
+	WritePCI2PI_u32(pi, PCI2PI_ALE_ADR_WHSF,
+			PCI2PI_config.ale_adr_first +
+			PCI2PI_config.ale_adr_setup * 2 +
+			PCI2PI_config.ale_adr_hold * 4 +
+			PCI2PI_config.ale_adr_wait * 8);
+
+	WritePCI2PI_u32(pi, PCI2PI_CYCLE_PAUSE,
+			0x10 * PCI2PI_config.pause_seq +
+			PCI2PI_config.pause_end);
+	WritePCI2PI_u32(pi, PCI2PI_STATUS_INT_ENABLE,
+			PCI2PI_config.status_int_enable);
+
+	WritePCI2PI_u32(pi, PCI2PI_PI_INT_POL,
+			2 * PCI2PI_config.pi_wait_enable +
+			PCI2PI_config.pi_int_pol);
+
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG0, PCI2PI_config.spi_cfg0);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG1, PCI2PI_config.spi_cfg1);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG2, PCI2PI_config.spi_cfg2);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG3, PCI2PI_config.spi_cfg3);
+	WritePCI2PI_u32(pi, PCI2PI_EEP_RECOVER, PCI2PI_config.eep_recover);
+	ReadPCI2PI_u32(pi, PCI2PI_STATUS);
+
+	/* release hardware reset XHFC */
+	WritePCI2PI_u32(pi, PCI2PI_GPIO_OUT,
+			GPIO_OUT_VAL | PCI2PI_GPIO7_NRST);
+	udelay(10);
+
+	return (err);
+}
+
+
+/*
+ * read and write functions to access a XHFC at the local bus interface
+ * of the PCI bridge there are two sets of functions to access the XHFC
+ * in the following different interface modes:
+ *
+ * multiplexed bus interface modes PI_INTELMX and PI_MOTMX
+ *  - these modes use a single (atomic) PCI cycle to read or write
+ *    a XHFC register
+ *  - non multiplexed bus interface modes PI_INTELNOMX, PI_MOTMX
+ *    and PI_SPI
+ *
+ * these modes use a separate PCI cycles to select the XHFC register and to read
+ * or write data. That means these register accesses are non atomic and could be
+ * interrupted by an interrupt. The driver must take care that a register access
+ * in these modes is not interrupted by its own interrupt handler.
+ */
+
+
+/*****************************************************************************/
+
+#if ((PI_MODE==PI_INTELMX) || (PI_MODE==PI_MOTMX))
+
+/* functions for multiplexed access */
+inline __u8
+read_xhfc(struct xhfc * xhfc, __u8 reg_addr)
+{
+	return (*(volatile __u8 *) (xhfc->pi->membase +
+				    PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				    (reg_addr << 2)));
+}
+
+/*
+ * read four bytes from the same register address
+ * e.g. A_FIFO_DATA
+ * this function is only defined for software compatibility here
+ */
+inline __u32
+read32_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	__u32 value;
+
+	value = (*(volatile __u8 *) (xhfc->pi->membase +
+				     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				     (reg_addr << 2)));
+	value |= (*(volatile __u8 *) (xhfc->pi->membase +
+				      PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				      (reg_addr << 2))) << 8;
+	value |= (*(volatile __u8 *) (xhfc->pi->membase +
+				      PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				      (reg_addr << 2))) << 16;
+	value |= (*(volatile __u8 *) (xhfc->pi->membase +
+				      PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				      (reg_addr << 2))) << 24;
+
+	return (value);
+}
+
+inline void
+write_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u8 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2))) = value;
+}
+
+/*
+ * writes four bytes to the same register address
+ * e.g. A_FIFO_DATA
+ * this function is only defined for software compatibility here
+ */
+inline void
+write32_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u32 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2))) = value & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2))) = (value >> 8) & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2))) = (value >> 16) & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2))) = (value >> 24) & 0xff;
+}
+
+/*
+ * always reads a single byte with short read method
+ * this allows to read ram based registers
+ * that normally requires long read access times
+ */
+inline __u8
+sread_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	(*(volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+			     (reg_addr << 2)));
+	return (*(volatile __u8 *)
+		(xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+		 (R_INT_DATA << 2)));
+}
+
+/*
+ * this function reads the currently selected regsiter from XHFC and is only
+ * required for non multiplexed access modes. For multiplexed access modes this
+ * function is only defined for for software compatibility.
+ */
+inline __u8
+read_xhfcregptr(struct xhfc *xhfc)
+{
+	return 0;
+}
+
+/*
+ * this function writes the XHFC register address pointer and is only
+ * required for non multiplexed access modes. For multiplexed access modes this
+ * function is only defined for for software compatibility. */
+inline void
+write_xhfcregptr(struct xhfc *xhfc, __u8 reg_addr)
+{
+}
+
+#endif /* PI_MODE==PI_INTELMX || PI_MODE==PI_MOTMX */
+
+/*****************************************************************************/
+
+#if PI_MODE==PI_INTELNOMX || PI_MODE==PI_MOT
+/*
+ * functions for non multiplexed access:
+ * XHFC register address pointer is accessed with PCI address A2=1 and XHFC data
+ * port is accessed with PCI address A2=0
+ */
+
+inline __u8
+read_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u8 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+	data =
+	    *(volatile __u8 *) (xhfc->pi->membase +
+				PCI2PI_XHFC_OFFSETS[xhfc->chipidx]);
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return (data);
+}
+
+/*
+ * read four bytes from the same register address by using a 32bit PCI access.
+ * The PCI bridge generates for 8 bit data read cycles at the local bus
+ * interface.
+ */
+inline __u32
+read32_xhfc(struct xhfc * xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u32 data;
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+	data =
+	    *(volatile __u32 *) xhfc->pi->membase +
+	        PCI2PI_XHFC_OFFSETS[xhfc->chipidx];
+	    spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return (data);
+}
+
+inline void
+write_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u8 value)
+{
+	u_long flags;
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx])) = value;
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+}
+
+/*
+ * writes four bytes to the same register address (e.g. A_FIFO_DATA) by using a
+ * 32bit PCI access. The PCI bridge generates for 8 bit data write cycles at the
+ * local bus interface.
+ */
+inline void
+write32_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u32 value)
+{
+	u_long flags;
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+	*((volatile __u32 *) (xhfc->pi->membase +
+			      PCI2PI_XHFC_OFFSETS[xhfc->chipidx])) = value;
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+}
+
+/*
+ * reads a single byte with short read method (r*). This allows to read ram
+ * based registers that normally requires long read access times
+ */
+inline __u8
+sread_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u8 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+
+	/* dummy read to get R_INT_DATA */
+	(*(volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx]));
+
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    R_INT_DATA;
+	data =
+	    *(volatile __u8 *) (xhfc->pi->membase +
+				PCI2PI_XHFC_OFFSETS[xhfc->chipidx]);
+	    spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return (data);
+}
+
+/*
+ * this function reads the currently selected regsiter from XHFC
+ */
+inline __u8
+read_xhfcregptr(struct xhfc * xhfc)
+{
+	return (*(volatile __u8 *) (xhfc->pi->membase +
+				    PCI2PI_XHFC_OFFSETS[xhfc->chipidx] +
+				    4));
+}
+
+/*
+ * this function writes the XHFC register address pointer
+ */
+inline void
+write_xhfcregptr(struct xhfc *xhfc, __u8 reg_addr)
+{
+	*((volatile __u8 *) (xhfc->pi->membase +
+			     PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) =
+	    reg_addr;
+}
+
+#endif /* PI_MODE==PI_INTELNOMX || PI_MODE==PI_MOT */
+
+
+/*****************************************************************************/
+
+#if PI_MODE == PI_SPI
+
+/* SPI mode transaction bit definitions */
+#define SPI_ADDR	0x40
+#define SPI_DATA	0x00
+#define SPI_RD		0x80
+#define SPI_WR		0x00
+#define SPI_BROAD	0x20
+#define SPI_MULTI	0x20
+
+inline __u8
+read_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u8 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+			(reg_addr << 16) | ((SPI_DATA | SPI_RD) << 8));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+
+	// read data from the SPI data receive register and return one byte
+	data = ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF;
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return data;
+}
+
+/*
+ * read four bytes from the same register address by using a
+ * SPI multiple read access
+ */
+inline __u32
+read32_xhfc(struct xhfc * xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u32 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->
+			  chipidx) << 8) | reg_addr);
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 8 clock SPI master transfer
+	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA,
+		       (SPI_DATA | SPI_RD | SPI_MULTI));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	// output data is arbitrary
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, 0);
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+
+	// read data from the SPI data receive register and return four bytes
+	data = be32_to_cpu(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA));
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return data;
+}
+
+inline void
+write_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u8 value)
+{
+	u_long flags;
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+			(reg_addr << 16) |
+			((SPI_DATA | SPI_WR) << 8) | value);
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+}
+
+/*
+ * writes four bytes to the same register address (e.g. A_FIFO_DATA) by using a
+ * SPI multiple write access
+ */
+inline void
+write32_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u32 value)
+{
+	u_long flags;
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->
+			  chipidx) << 8) | reg_addr);
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 8 clock SPI master transfer
+	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA,
+		       (SPI_DATA | SPI_WR | SPI_MULTI));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, cpu_to_be32(value));
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+}
+
+/*
+ * reads a single byte with short read method (r*). This allows to read ram
+ * based registers that normally requires long read access times
+ */
+inline __u8
+sread_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	u_long flags;
+	__u8 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+			(reg_addr << 16) | ((SPI_DATA | SPI_RD) << 8));
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer to read R_INT_DATA register
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+			(R_INT_DATA << 16) | ((SPI_DATA | SPI_RD) << 8));
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+
+	// read data from the SPI data receive register and return one byte
+	data = ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF;
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return data;
+}
+
+/*
+ * this function reads the currently selected regsiter from XHFC
+ */
+inline __u8
+read_xhfcregptr(struct xhfc * xhfc)
+{
+	u_long flags;
+	__u8 data;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_RD | xhfc->chipidx) << 8));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+
+	// read data from the SPI data receive register and return one byte
+	data = ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF;
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return data;
+}
+
+/*
+ * this function writes the XHFC register address pointer
+ */
+inline void
+write_xhfcregptr(struct xhfc *xhfc, __u8 reg_addr)
+{
+	u_long flags;
+
+	spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+			((SPI_ADDR | SPI_WR | xhfc->
+			  chipidx) << 8) | reg_addr);
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+}
+
+#endif /* PI_MODE == PI_SPI */
diff --git a/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h b/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h
new file mode 100644
index 000000000..312f449bd
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h
@@ -0,0 +1,329 @@
+/* xhfc_pci2pi.h
+ * PCI2PI Pci Bridge support for xhfc_su.c
+ *
+ * (C) 2007 Copyright Cologne Chip AG
+ * Authors : Joerg Ciesielski
+ * Contact : info@colognechip.com
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _XHFC_PCI2PI_H_
+#define _XHFC_PCI2PI_H_
+
+/* differnt PCI modes supported by PCI2PI */
+#define PI_INTELNOMX	0
+#define PI_INTELMX	1
+#define PI_MOT		2
+#define PI_MOTMX	3
+#define PI_SPI		4
+#define PI_EEPPRG	6
+#define PI_AUTOEEP	7
+
+/* PI_MODE to GPIO mapping */
+#define PI_INTELMX_GPIO		PCI2PI_GPIO3_MODE1	/* ALE pulse switches to MULTIPLEXED */
+#define PI_INTELNOMX_GPIO	PCI2PI_GPIO3_MODE1
+#define PI_MOT_GPIO		PCI2PI_GPIO2_MODE0
+#define PI_MOTMX_GPIO		PCI2PI_GPIO2_MODE0
+#define PI_SPI_GPIO		0
+#define PI_AUTOEEP_GPIO		PCI2PI_GPIO2_MODE0 | PCI2PI_GPIO3_MODE1
+
+
+/* PCI2PI GPIO to XHFC signal mapping */
+#define PCI2PI_GPIO7_NRST	0x80
+#define PCI2PI_GPIO6_TLA3	0x40
+#define PCI2PI_GPIO5_TLA2	0x20
+#define PCI2PI_GPIO4_TLA1	0x10
+#define PCI2PI_GPIO3_MODE1	0x08
+#define PCI2PI_GPIO2_MODE0	0x04
+#define PCI2PI_GPIO1_BOND1	0x02
+#define PCI2PI_GPIO0_BOND0	0x01
+
+/* PCI2PI GPIO XHFC Bond out selection */
+#define XHFC_1SU_BOND	0
+#define XHFC_2SU_BOND	PCI2PI_GPIO0_BOND0
+#define XHFC_2S4U_BOND	PCI2PI_GPIO1_BOND1
+#define XHFC_4SU_BOND	PCI2PI_GPIO1_BOND1 | PCI2PI_GPIO0_BOND0
+
+/* membase offset to address XHFC controllers */
+#define PCI2PI_MAX_XHFC 2
+extern __u32 PCI2PI_XHFC_OFFSETS[PCI2PI_MAX_XHFC];
+
+
+/*******************************************************/
+/*******************************************************/
+
+/* Select processor interface mode and Bond option     */
+/* of PCI2PI bridge */
+#define PI_MODE		PI_SPI
+#define XHFC_BOND	XHFC_4SU_BOND
+
+/*******************************************************/
+/*******************************************************/
+
+#if (PI_MODE == PI_INTELNOMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_INTELNOMX_GPIO
+
+#elif (PI_MODE == PI_INTELMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_INTELMX_GPIO
+
+#elif (PI_MODE == PI_MOT)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_MOT_GPIO
+
+#elif (PI_MODE == PI_MOTMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_MOTMX_GPIO
+
+#elif (PI_MODE == PI_SPI)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_SPI_GPIO
+
+#elif (PI_MODE == PI_AUTOEEP)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_AUTOEEP_GPIO
+#endif
+
+/*******************************************************/
+
+
+#define PCI2PI_VENDORID		0x1397
+
+#define PCI2PI_DEVICEID		0xA003
+#define MAX_PCI2PI		2
+
+#define RV_PCI2PI_OK		0
+#define RV_PCI2PI_ERROR		1
+
+/* PCI2PI register definitions */
+#define PCI2PI_OFFSET		0x00000800
+#define PCI2PI_DEL_CS		4*0x00 + PCI2PI_OFFSET
+#define PCI2PI_DEL_RD		4*0x01 + PCI2PI_OFFSET
+#define PCI2PI_DEL_WR		4*0x02 + PCI2PI_OFFSET
+#define PCI2PI_DEL_ALE		4*0x03 + PCI2PI_OFFSET
+#define PCI2PI_DEL_ADR		4*0x04 + PCI2PI_OFFSET
+#define PCI2PI_DEL_DOUT		4*0x05 + PCI2PI_OFFSET
+#define PCI2PI_DEFAULT_ADR	4*0x06 + PCI2PI_OFFSET
+#define PCI2PI_DEFAULT_DOUT	4*0x07 + PCI2PI_OFFSET
+
+
+/*
+ * PCI2PI_PI_MODE bit 2..0:
+ * 000: Intel non multiplexed
+ * 001: Intel multiplexed
+ * 010: Motorola
+ * 100: SPI Motorola
+ * 110: EEPROM programming mode throug PCIIF00 Target
+ * 111: XHFC AutoEEPROM mode
+ */
+#define PCI2PI_PI_MODE		4*0x08 + PCI2PI_OFFSET
+
+#define PCI2PI_CYCLE_SHD	4*0x09 + PCI2PI_OFFSET
+#define PCI2PI_ALE_ADR_WHSF	4*0x0a + PCI2PI_OFFSET
+#define PCI2PI_CYCLE_PAUSE	4*0x0b + PCI2PI_OFFSET
+#define PCI2PI_GPIO_OUT		4*0x0c + PCI2PI_OFFSET
+#define PCI2PI_G1		4*0x0e + PCI2PI_OFFSET
+#define PCI2PI_G0		4*0x0f + PCI2PI_OFFSET
+
+/*
+ * bit0: is set by PI_INT active, is reseted by reading this register
+ * bit1: is set by PI_WAIT active, is reseted by reading this register
+ */
+#define PCI2PI_STATUS		4*0x10 + PCI2PI_OFFSET
+
+
+/* bit0: enable PCI interrupt output */
+#define PCI2PI_STATUS_INT_ENABLE	4*0x11 + PCI2PI_OFFSET
+
+/*
+ * bit0: 0 = low active interrupt is detected at PI_INT
+ * bit0: 1 = high active interrupt is detected at PI_INT
+ */
+#define PCI2PI_PI_INT_POL	4*0x12 + PCI2PI_OFFSET
+
+/* SPI registers */
+/* 32 bit SPI master data output register */
+#define PCI2PI_SPI_MO_DATA	4*0x20 + PCI2PI_OFFSET
+
+/* 32 bit SPI master data input register */
+#define PCI2PI_SPI_MI_DATA	4*0x21 + PCI2PI_OFFSET
+
+/*
+ * bit 0: 0 SPI bits are processing on the serial input/output
+ * bit 0: 1 SPI bits are processed, new data can be written or read
+ * bit 1..31: unused
+ */
+#define PCI2PI_SPI_STATUS	4*0x22 + PCI2PI_OFFSET
+
+/*
+ * bit 0: spi clock polarity, defines level for SPISEL1
+ * bit 1: spi clock phase, defines sampling edge, 0?, 1?
+ * bit 2: 0MSB first (default) , 1LSB first
+ * bit 3: 1SPI clock permanent during SPISEL1
+ */
+#define PCI2PI_SPI_CFG0		4*0x28 + PCI2PI_OFFSET
+
+/*
+ * bit 0..3: spi clock frequency, SPI clock period  (value+1) x 2 x PCIperiod
+ * 0: 2 PCIperiods
+ * 1:
+ */
+#define PCI2PI_SPI_CFG1		4*0x29 + PCI2PI_OFFSET
+
+/* bit 0..3: SPI Device SEL: defines level of D0..D3, XHFC SPI address */
+#define PCI2PI_SPI_CFG2		4*0x2A + PCI2PI_OFFSET
+
+/*
+ * bit 0: 1spi master out permanent driven
+ * bit 1: 1SPISEL remains low between bytes of a sequence
+ * bit 2: 1SPISEL remains low permanent
+ */
+#define PCI2PI_SPI_CFG3		4*0x2B + PCI2PI_OFFSET
+
+/* bit 0..3: default 0100 */
+#define PCI2PI_EEP_RECOVER	4*0x30 + PCI2PI_OFFSET
+
+struct PCI2PI_cfg {
+	__u32 del_cs;		/* Bit 3..0, bit 3: 0.5 PCI clk,
+				 * bits 2..0: gate delay
+				 */
+	__u32 del_rd;
+	__u32 del_wr;
+	__u32 del_ale;
+
+	__u32 del_adr;		/* delay between default address
+				 * value and selected address
+				 */
+
+	__u32 del_dout;		/* delay between default data
+				 * value and written data
+				 */
+
+	__u32 default_adr;	/* default address value bit 0..7 */
+
+	__u32 default_dout;	/* default data value bit 0..7 */
+
+	__u32 pi_mode;		/* pi_mode bit 2..0:
+				 *   000: Intel non multiplexed
+				 *   001: Intel multiplexed
+				 *   010: Motorola
+				 *   100: SPI Motorola
+				 *   110: EEPROM programming mode throug
+				 *        PCIIF00 Target
+				 *   111: XHFC AutoEEPROM mode
+				 */
+
+	__u32 setup;		/* address/data setup berfore rd/wr/cs,
+				 * 0 or 1 PCI clk
+				 */
+
+	__u32 hold;		/* address/data hold after rd/wr/cs,
+				 * 0 or 1 PCI clk
+				 */
+
+	__u32 cycle;		/* bit 0 only
+				 * address/data adds 0 or 1 PCI clk to /rd/wr/cs
+				 * access time (cycle+1) PCI clk
+				 */
+
+	__u32 ale_adr_first;	/* bit 0 = 0: address valid before ALE=1
+				 * bit 0 = 1: ALE=1  before adress valid
+				 */
+
+	__u32 ale_adr_setup;	/* bit 0 = 0 setup for ALE/addr = 0s
+				 * bit 0 = 1:setup for ALE/addr = 1 PCI clk
+				 * ALE/addr depends on ale_adr_first setting
+				 */
+
+	__u32 ale_adr_hold;	/* bit 0 = 0 hold for address after ALE: 0s
+				 * bit 0 = 1:hold for address after ALE: 1 PCI
+				 * clk
+				 */
+
+	__u32 ale_adr_wait;	/* bit 0 = 0: 0 PCI clk delay between address
+				 *              and data phase
+				 * bit 0 = 1: 1 PCI clk delay between address
+				 *              and data phase
+				 */
+
+	__u32 pause_seq;	/* bit 0..3: number of PCI clocks between
+				 * read/write acceses due to DWORD/WORD
+				 * burst access
+				 */
+
+	__u32 pause_end;	/* bit 0..3: number of PCI clocks after
+				 * DWORD/WORD burst access /delays
+				 * PCI_TRDY signal
+				 */
+
+	__u32 gpio_out;		/* bit 0..7: GPIO output value */
+
+	__u32 status_int_enable;	/* bit 0: enables PCI interrupt for
+					 *        PI_INT signal
+					 * bit 1: enables PCI interrupt for
+					 *        PI_NWAIT signal
+					 */
+
+	__u32 pi_int_pol;	/* bit 0: polarity of PI_INT signal */
+
+	__u32 pi_wait_enable;	/* access length can be controled by /wait
+				 * signal:  0 wait disabled, 1 wait enabled
+				 */
+	__u32 spi_cfg0;
+	__u32 spi_cfg1;
+	__u32 spi_cfg2;
+	__u32 spi_cfg3;
+	__u32 eep_recover;
+};
+
+/* private driver_data */
+struct pi_params {
+	char *device_name;
+	__u8 num_xhfcs;
+};
+
+/* PCI processor interface */
+struct xhfc_pi {
+	struct pci_dev *pdev;
+	int irq;
+	int iobase;
+	u_char *membase;
+	u_char *hw_membase;
+	int cardnum;
+	char name[10]; /* 'XHFC_PI0' = ProcessorInterface no. 0 */
+	struct pi_params driver_data;
+	spinlock_t lock;
+	__u8 num_xhfcs;
+	struct list_head list;
+
+	/* each PI may contain several XHFCs */
+	struct xhfc * xhfc;
+};
+
+
+/* prototypes: PCI bridge management */
+int init_pci_bridge(struct xhfc_pi * pi);
+int xhfc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+void xhfc_pci_remove(struct pci_dev *pdev);
+int xhfc_register_pi(void);
+int xhfc_unregister_pi(void);
+
+/* prototypes: xhfc register access */
+__u8 read_xhfc(struct xhfc *, __u8 reg_addr);
+__u32 read32_xhfc(struct xhfc *, __u8 reg_addr);
+void write_xhfc(struct xhfc *, __u8 reg_addr, __u8 value);
+void write32_xhfc(struct xhfc *, __u8 reg_addr, __u32 value);
+__u8 sread_xhfc(struct xhfc *, __u8 reg_addr);
+void write_xhfcregptr(struct xhfc *, __u8 reg_addr);
+__u8 read_xhfcregptr(struct xhfc *);
+
+#endif /* _XHFC_PCI2PI_H_ */
diff --git a/drivers/isdn/hardware/mISDN/xhfc_spi.c b/drivers/isdn/hardware/mISDN/xhfc_spi.c
new file mode 100644
index 000000000..bbde63ea6
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_spi.c
@@ -0,0 +1,393 @@
+/* xhfc_spi.c
+ * SPI support for xhfc_su.c
+ * based on PCI2PI Pci Bridge driver
+ *
+ * (C) 2022 Copyright Tobias Mädel
+ * (C) 2007 Copyright Cologne Chip AG
+ * Authors : Joerg Ciesielski, Tobias Mädel
+ * Contact : info@colognechip.com, t.maedel@alfeld.de
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include "xhfc_su.h"
+#include "xhfc_spi.h"
+
+int xhfc_spi_probe(struct spi_device *spi)
+{
+	struct xhfc_pi *pi = NULL;
+	int err = 0;
+	int irq = 0;
+
+	if (!(pi = kzalloc(sizeof(struct xhfc_pi), GFP_KERNEL))) {
+		printk(KERN_ERR "%s: No kmem for XHFC card\n",
+			 __FUNCTION__);
+		goto out;
+	}
+
+	sprintf(pi->name, "%s_%s", DRIVER_NAME, spi->dev.init_name);
+	if (!(pi->xhfc =
+		kzalloc(sizeof(struct xhfc),
+			 GFP_KERNEL))) {
+		printk(KERN_ERR "%s %s: No kmem for sizeof(xhfc_t)\n",
+			 pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	spi_set_drvdata(spi, pi);
+
+	mutex_init(&pi->lock);
+
+	struct gpio_desc *reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(reset_gpio))
+	{
+		err = PTR_ERR(reset_gpio);
+		dev_err(&spi->dev, "failed to request reset gpio: %d\n", err);
+		return err;
+	}
+	if (reset_gpio)
+	{
+		gpiod_set_value(reset_gpio, 0);
+		mdelay(1);
+		gpiod_set_value(reset_gpio, 1);
+		mdelay(100);
+	}
+
+	if (spi->irq)
+	{
+		char *irq_desc;
+
+		irq_desc = devm_kasprintf(&spi->dev, GFP_KERNEL, "%s-xhfc",
+					  dev_name(&spi->dev));
+		if (!irq_desc)
+		{
+			printk(KERN_ERR "%s %s: Failed to allocate interrupt name buffer\n",
+			 pi->name, __FUNCTION__);
+			goto out;
+		}
+
+		err = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+						xhfc_interrupt,
+						IRQF_ONESHOT,
+						irq_desc, pi);
+		if (err) 
+		{
+			printk(KERN_ERR "%s %s: Failed to request interrupt %d\n",
+			 pi->name, __FUNCTION__, err);
+			goto out;
+		}
+	}
+
+	pi->driver_data.num_xhfcs = 1;
+	pi->xhfc->pi = pi;
+	pi->pdev = spi;
+	err = setup_instance(pi->xhfc, &spi->dev);
+
+	if (!err)
+	{
+		printk(KERN_INFO "%s %s: Done, %s\n",
+			 pi->name, __FUNCTION__, pi->name);
+		return 0;
+	}
+	else
+	{
+		printk(KERN_ERR "%s %s: Failed to setup instance, err: %d\n",
+		       pi->name, __FUNCTION__, err);
+	}
+
+	out:
+	if (pi->xhfc)
+		kfree(pi->xhfc);
+	if (pi)
+		kfree(pi);
+	return 0;
+}
+
+int xhfc_spi_remove(struct spi_device *spi)
+{
+	struct xhfc_pi *pi = spi_get_drvdata(spi);
+	printk(KERN_INFO "%s %s: removing card\n", pi->name, __FUNCTION__);
+	release_instance(pi->xhfc);
+	kfree(pi);
+	return 0;
+}
+
+/* SPI mode transaction bit definitions */
+#define SPI_ADDR	0x40
+#define SPI_DATA	0x00
+#define SPI_RD	0x80
+#define SPI_WR	0x00
+#define SPI_BROAD	0x20
+#define SPI_MULTI	0x20
+
+inline __u8 spi_xhfc_read(struct spi_device *spi)
+{
+	uint8_t rxbuf[2];
+	uint8_t txbuf[2];
+
+	memset (rxbuf, 0x00, sizeof(rxbuf));
+	txbuf[0] = SPI_RD;
+	spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+	return rxbuf[0];
+}
+inline void spi_xhfc_write(struct spi_device *spi, __u8 value)
+{
+	uint8_t rxbuf[2];
+	uint8_t txbuf[2];
+
+	memset (rxbuf, 0x00, sizeof(rxbuf));
+	txbuf[0] = SPI_BROAD | SPI_WR;
+	txbuf[1] = value;
+	spi_write_then_read(spi, txbuf, 2, NULL, 0);
+	return;
+}
+
+
+inline __u8
+read_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	//printk(KERN_INFO "%s: called, reg_addr: 0x%02x\n", __FUNCTION__, reg_addr);
+	u_long flags;
+	__u8 data;
+	struct spi_device *spi = xhfc->pi->pdev;
+
+	//spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	uint8_t rxbuf[2];
+	uint8_t txbuf[3];
+	txbuf[0] = SPI_ADDR | SPI_WR;
+	txbuf[1] = reg_addr;
+	txbuf[2] = SPI_RD;
+	spi_write_then_read(spi, txbuf, 3, rxbuf, 1);
+
+	data = rxbuf[0];
+
+	//printk(KERN_INFO "%s: called, reg_addr: 0x%02x, read: 0x%02x\n", __FUNCTION__, reg_addr, data);
+
+	//spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return data;
+}
+
+/*
+ * read four bytes from the same register address by using a
+ * SPI multiple read access
+ */
+inline __u32
+read32_xhfc(struct xhfc * xhfc, __u8 reg_addr)
+{
+	printk(KERN_INFO "%s: called\n", __FUNCTION__);
+//	u_long flags;
+//	__u32 data;
+//
+//	spin_lock_irqsave(&xhfc->pi->lock, flags);
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 16 clock SPI master transfer
+//	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_WR | xhfc->
+//			  chipidx) << 8) | reg_addr);
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 8 clock SPI master transfer
+//	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//		       (SPI_DATA | SPI_RD | SPI_MULTI));
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 32 clock SPI master transfer
+//	// output data is arbitrary
+//	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, 0);
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//
+//	// read data from the SPI data receive register and return four bytes
+//	data = be32_to_cpu(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA));
+//
+//	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+//	return data;
+	return 0;
+}
+
+inline void
+write_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u8 value)
+{
+	//printk(KERN_INFO "%s: called, reg_addr: 0x%02x, value: 0x%02x\n", __FUNCTION__, reg_addr, value);
+	u_long flags;
+	struct spi_device *spi = xhfc->pi->pdev;
+
+	uint8_t txbuf[4];
+	txbuf[0] = SPI_ADDR | SPI_WR;
+	txbuf[1] = reg_addr;
+	txbuf[2] = SPI_WR;
+	txbuf[3] = value;
+
+	spi_write_then_read(spi, txbuf, 4, NULL, 0);
+
+	/*spin_lock_irqsave(&xhfc->pi->lock, flags);
+
+	spi_xhfc_set_register(spi, reg_addr);
+
+	spi_xhfc_write(spi, value);
+
+	spin_unlock_irqrestore(&xhfc->pi->lock, flags);*/
+	return;
+}
+
+/*
+ * writes four bytes to the same register address (e.g. A_FIFO_DATA) by using a
+ * SPI multiple write access
+ */
+inline void
+write32_xhfc(struct xhfc *xhfc, __u8 reg_addr, __u32 value)
+{
+	printk(KERN_INFO "%s: called\n", __FUNCTION__);
+//	u_long flags;
+//	spin_lock_irqsave(&xhfc->pi->lock, flags);
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 16 clock SPI master transfer
+//	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_WR | xhfc->
+//			  chipidx) << 8) | reg_addr);
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 8 clock SPI master transfer
+//	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//		       (SPI_DATA | SPI_WR | SPI_MULTI));
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 32 clock SPI master transfer
+//	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, cpu_to_be32(value));
+//
+//	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return;
+}
+
+/*
+ * reads a single byte with short read method (r*). This allows to read ram
+ * based registers that normally requires long read access times
+ */
+inline __u8
+sread_xhfc(struct xhfc *xhfc, __u8 reg_addr)
+{
+	printk(KERN_INFO "%s: called\n", __FUNCTION__);
+//	u_long flags;
+//	__u8 data;
+//
+//	spin_lock_irqsave(&xhfc->pi->lock, flags);
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 32 clock SPI master transfer
+//	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+//			(reg_addr << 16) | ((SPI_DATA | SPI_RD) << 8));
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 32 clock SPI master transfer to read R_INT_DATA register
+//	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) |
+//			(R_INT_DATA << 16) | ((SPI_DATA | SPI_RD) << 8));
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//
+//	// read data from the SPI data receive register and return one byte
+//	data = ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF;
+//
+//	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+//	return data;
+	return 0;
+}
+
+/*
+ * this function reads the currently selected regsiter from XHFC
+ */
+inline __u8
+read_xhfcregptr(struct xhfc * xhfc)
+{
+	printk(KERN_INFO "%s: called\n", __FUNCTION__);
+//	u_long flags;
+//	__u8 data;
+//
+//	spin_lock_irqsave(&xhfc->pi->lock, flags);
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 16 clock SPI master transfer
+//	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_RD | xhfc->chipidx) << 8));
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//
+//	// read data from the SPI data receive register and return one byte
+//	data = ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF;
+//
+//	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+//	return data;
+	return 0;
+}
+
+/*
+ * this function writes the XHFC register address pointer
+ */
+inline void
+write_xhfcregptr(struct xhfc *xhfc, __u8 reg_addr)
+{
+	printk(KERN_INFO "%s: called\n", __FUNCTION__);
+//	u_long flags;
+//
+//	spin_lock_irqsave(&xhfc->pi->lock, flags);
+//
+//	// wait until SPI master is idle
+//	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+//	// initiate a 16 clock SPI master transfer
+//	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA,
+//			((SPI_ADDR | SPI_WR | xhfc->
+//			  chipidx) << 8) | reg_addr);
+//
+//	spin_unlock_irqrestore(&xhfc->pi->lock, flags);
+	return;
+}
+
+static const struct of_device_id xhfc_of_ids[] = {
+	{ .compatible = "colognechip,xhfc2su-spi" },
+	{ .compatible = "colognechip,xhfc2su" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, xhfc_of_ids);
+
+static const struct spi_device_id xhfc_ids[] = {
+	{ "colognechip,xhfc2su-spi", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, xhfc_ids);
+
+static struct spi_driver xhfc_spi_driver = {
+	.driver = {
+		.name = "xhfc2su-spi",
+		.of_match_table = xhfc_of_ids,
+	},
+	.id_table = xhfc_ids,
+	.probe = xhfc_spi_probe,
+	.remove = xhfc_spi_remove,
+};
+
+module_spi_driver(xhfc_spi_driver);
diff --git a/drivers/isdn/hardware/mISDN/xhfc_spi.h b/drivers/isdn/hardware/mISDN/xhfc_spi.h
new file mode 100644
index 000000000..d6658d869
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_spi.h
@@ -0,0 +1,59 @@
+/* xhfc_spi.h
+ * SPI support for xhfc_su.c
+ * based on PCI2PI Pci Bridge driver
+ *
+ * (C) 2022 Copyright Tobias Mädel
+ * (C) 2007 Copyright Cologne Chip AG
+ * Authors : Joerg Ciesielski, Tobias Mädel
+ * Contact : info@colognechip.com, t.maedel@alfeld.de
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _XHFC_SPI_H_
+#define _XHFC_SPI_H_
+
+/* private driver_data */
+struct pi_params {
+	char *device_name;
+	__u8 num_xhfcs;
+};
+
+/* SPI data struct */
+struct xhfc_pi {
+	struct spi_device *pdev;
+	int irq;
+	int cardnum;
+	char name[10];
+	struct pi_params driver_data;
+	struct mutex lock;
+	__u8 num_xhfcs;
+	struct list_head list;
+
+	/* each PI may contain several XHFCs */
+	struct xhfc * xhfc;
+};
+
+/* prototypes: xhfc register access */
+__u8 read_xhfc(struct xhfc *, __u8 reg_addr);
+__u32 read32_xhfc(struct xhfc *, __u8 reg_addr);
+void write_xhfc(struct xhfc *, __u8 reg_addr, __u8 value);
+void write32_xhfc(struct xhfc *, __u8 reg_addr, __u32 value);
+__u8 sread_xhfc(struct xhfc *, __u8 reg_addr);
+void write_xhfcregptr(struct xhfc *, __u8 reg_addr);
+__u8 read_xhfcregptr(struct xhfc *);
+
+#endif /* _XHFC_SPI_H_ */
diff --git a/drivers/isdn/hardware/mISDN/xhfc_su.c b/drivers/isdn/hardware/mISDN/xhfc_su.c
new file mode 100644
index 000000000..169649949
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_su.c
@@ -0,0 +1,1991 @@
+/* xhfc_su.c
+ * mISDN driver for Cologne Chip AG's XHFC
+ *
+ * (c) 2007,2008 Copyright Cologne Chip AG
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info@colognechip.com
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * module params
+ *   debug=<n>, default=0, with n=0xHHHHGGGG
+ *      H - l1 driver flags described in hfcs_usb.h
+ *      G - common mISDN debug flags described at mISDNhw.h
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "xhfc_su.h"
+
+#if BRIDGE == BRIDGE_PCI2PI
+#include <linux/pci.h>
+#include "xhfc_pci2pi.h"
+#endif
+
+#if BRIDGE == BRIDGE_SPI
+#include <linux/spi/spi.h>
+#include "xhfc_spi.h"
+#endif
+
+
+const char *xhfc_rev = "Revision: 0.2.0 2016-06-10";
+
+/* modules params */
+static unsigned int debug = 0;
+
+/* driver globbls */
+static int xhfc_cnt;
+
+#ifdef MODULE
+MODULE_AUTHOR("Martin Bachem");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+
+/* prototypes for static functions */
+static int xhfc_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb);
+static int xhfc_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb);
+static int xhfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg);
+static int xhfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg);
+static int xhfc_setup_bch(struct bchannel *bch, int protocol);
+static void xhfc_setup_dch(struct dchannel *dch);
+static void xhfc_write_fifo(struct xhfc *xhfc, __u8 channel);
+static void xhfc_bh_handler(unsigned long ul_hw);
+static void ph_state(struct dchannel *dch);
+static void f7_timer_expire(struct timer_list *t);
+/*
+ * Physical S/U commands to control Line Interface
+ */
+char *XHFC_PH_COMMANDS[] = {
+	"L1_ACTIVATE_TE",
+	"L1_FORCE_DEACTIVATE_TE",
+	"L1_ACTIVATE_NT",
+	"L1_DEACTIVATE_NT",
+	"L1_SET_TESTLOOP_B1",
+	"L1_SET_TESTLOOP_B2",
+	"L1_SET_TESTLOOP_D",
+	"L1_UNSET_TESTLOOP_B1",
+	"L1_UNSET_TESTLOOP_B2",
+	"L1_UNSET_TESTLOOP_D"
+};
+
+
+static inline void
+xhfc_waitbusy(struct xhfc *xhfc)
+{
+	while (read_xhfc(xhfc, R_STATUS) & M_BUSY);
+}
+
+static inline void
+xhfc_selfifo(struct xhfc *xhfc, __u8 fifo)
+{
+	write_xhfc(xhfc, R_FIFO, fifo);
+	xhfc_waitbusy(xhfc);
+}
+
+static inline void
+xhfc_inc_f(struct xhfc *xhfc)
+{
+	write_xhfc(xhfc, A_INC_RES_FIFO, M_INC_F);
+	xhfc_waitbusy(xhfc);
+}
+
+static inline void
+xhfc_resetfifo(struct xhfc *xhfc)
+{
+	write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO | M_RES_FIFO_ERR);
+	xhfc_waitbusy(xhfc);
+}
+
+/*
+ * disable all interrupts by disabling M_GLOB_IRQ_EN
+ */
+void
+disable_interrupts(struct xhfc *xhfc)
+{
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s\n", xhfc->name, __FUNCTION__);
+	SET_V_GLOB_IRQ_EN(xhfc->irq_ctrl, 0);
+	write_xhfc(xhfc, R_IRQ_CTRL, xhfc->irq_ctrl);
+}
+
+/*
+ * start interrupt and set interrupt mask
+ */
+void
+enable_interrupts(struct xhfc *xhfc)
+{
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s\n", xhfc->name, __FUNCTION__);
+
+	write_xhfc(xhfc, R_SU_IRQMSK, xhfc->su_irqmsk);
+
+	/* use defined timer interval */
+	write_xhfc(xhfc, R_TI_WD, xhfc->ti_wd);
+	SET_V_TI_IRQMSK(xhfc->misc_irqmsk, 1);
+	write_xhfc(xhfc, R_MISC_IRQMSK, xhfc->misc_irqmsk);
+
+	/* clear all pending interrupts bits */
+	read_xhfc(xhfc, R_MISC_IRQ);
+	read_xhfc(xhfc, R_SU_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL0_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL1_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL2_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL3_IRQ);
+
+	/* enable global interrupts */
+	SET_V_GLOB_IRQ_EN(xhfc->irq_ctrl, 1);
+	SET_V_FIFO_IRQ_EN(xhfc->irq_ctrl, 1);
+	write_xhfc(xhfc, R_IRQ_CTRL, xhfc->irq_ctrl);
+}
+
+/*
+ * Setup S/U interface, enable/disable B-Channels
+ */
+static void
+setup_su(struct xhfc *xhfc, __u8 pt, __u8 bc, __u8 enable)
+{
+	struct port *port = &xhfc->port[pt];
+
+	if (!((bc == 0) || (bc == 1))) {
+		printk(KERN_INFO "%s %s: pt(%i) ERROR: bc(%i) unvalid!\n",
+		       xhfc->name, __FUNCTION__, pt, bc);
+		return;
+	}
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s %s pt(%i) bc(%i)\n",
+		       xhfc->name, __FUNCTION__,
+		       (enable) ? ("enable") : ("disable"), pt, bc);
+
+	if (bc) {
+		SET_V_B2_RX_EN(port->su_ctrl2, (enable ? 1 : 0));
+		SET_V_B2_TX_EN(port->su_ctrl0, (enable ? 1 : 0));
+	} else {
+		SET_V_B1_RX_EN(port->su_ctrl2, (enable ? 1 : 0));
+		SET_V_B1_TX_EN(port->su_ctrl0, (enable ? 1 : 0));
+	}
+
+	if (xhfc->port[pt].mode & PORT_MODE_NT)
+		SET_V_SU_MD(xhfc->port[pt].su_ctrl0, 1);
+
+	write_xhfc(xhfc, R_SU_SEL, pt);
+	write_xhfc(xhfc, A_SU_CTRL0, xhfc->port[pt].su_ctrl0);
+	write_xhfc(xhfc, A_SU_CTRL2, xhfc->port[pt].su_ctrl2);
+}
+
+/*
+ * setup port (line interface) with SU_CRTLx
+ */
+static void
+init_su(struct port *port)
+{
+	struct xhfc *xhfc = port->xhfc;
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s port(%i)\n", xhfc->name,
+		       __FUNCTION__, port->idx);
+
+	write_xhfc(xhfc, R_SU_SEL, port->idx);
+
+	if (port->mode & PORT_MODE_NT)
+		SET_V_SU_MD(port->su_ctrl0, 1);
+
+	if (port->mode & PORT_MODE_EXCH_POL)
+		port->su_ctrl2 = M_SU_EXCHG;
+
+	if (port->mode & PORT_MODE_UP0) {
+		SET_V_ST_SEL(port->st_ctrl3, 1);
+		write_xhfc(xhfc, A_MS_TX, 0x0F);
+		SET_V_ST_SQ_EN(port->su_ctrl0, 1);
+	}
+
+	/* configure end of pulse control for ST mode (TE & NT) */
+	if (port->mode & PORT_MODE_S0) {
+		SET_V_ST_PU_CTRL(port->su_ctrl0, 1);
+		port->st_ctrl3 = 0xf8;
+	}
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s su_ctrl0(0x%02x) "
+		       "su_ctrl1(0x%02x) "
+		       "su_ctrl2(0x%02x) "
+		       "st_ctrl3(0x%02x)\n",
+		       xhfc->name, __FUNCTION__,
+		       port->su_ctrl0,
+		       port->su_ctrl1, port->su_ctrl2, port->st_ctrl3);
+
+	write_xhfc(xhfc, A_ST_CTRL3, port->st_ctrl3);
+	write_xhfc(xhfc, A_SU_CTRL0, port->su_ctrl0);
+	write_xhfc(xhfc, A_SU_CTRL1, port->su_ctrl1);
+	write_xhfc(xhfc, A_SU_CTRL2, port->su_ctrl2);
+
+	if (port->mode & PORT_MODE_TE)
+		write_xhfc(xhfc, A_SU_CLK_DLY, CLK_DLY_TE);
+	else
+		write_xhfc(xhfc, A_SU_CLK_DLY, CLK_DLY_NT);
+
+	write_xhfc(xhfc, A_SU_WR_STA, 0);
+}
+
+/*
+ * Setup Fifo using A_CON_HDLC, A_SUBCH_CFG, A_FIFO_CTRL
+ */
+static void
+setup_fifo(struct xhfc *xhfc, __u8 fifo, __u8 conhdlc, __u8 subcfg,
+	   __u8 fifoctrl, __u8 enable)
+{
+	xhfc_selfifo(xhfc, fifo);
+	write_xhfc(xhfc, A_CON_HDLC, conhdlc);
+	write_xhfc(xhfc, A_SUBCH_CFG, subcfg);
+	write_xhfc(xhfc, A_FIFO_CTRL, fifoctrl);
+
+	if (enable)
+		xhfc->fifo_irqmsk |= (1 << fifo);
+	else
+		xhfc->fifo_irqmsk &= ~(1 << fifo);
+
+	xhfc_resetfifo(xhfc);
+	xhfc_selfifo(xhfc, fifo);
+
+	if (debug & DEBUG_HW) {
+		printk(KERN_INFO
+		       "%s %s: fifo(%i) conhdlc(0x%02x) "
+		       "subcfg(0x%02x) fifoctrl(0x%02x)\n",
+		       xhfc->name, __FUNCTION__, fifo,
+		       sread_xhfc(xhfc, A_CON_HDLC),
+		       sread_xhfc(xhfc, A_SUBCH_CFG),
+		       sread_xhfc(xhfc, A_FIFO_CTRL)
+		    );
+	}
+}
+
+/*
+ * init BChannel prototol
+ */
+static int
+xhfc_setup_bch(struct bchannel *bch, int protocol)
+{
+	struct port *port = bch->hw;
+	struct xhfc *xhfc = port->xhfc;
+	__u8 channel = (port->idx * 4) + (bch->nr - 1);
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "channel(%i) protocol %x-->%x\n",
+		       channel, bch->state, protocol);
+
+	switch (protocol) {
+		case (-1):
+			bch->state = -1;
+			fallthrough;
+		case (ISDN_P_NONE):
+			if (bch->state == ISDN_P_NONE)
+				return (0);
+			bch->state = ISDN_P_NONE;
+			setup_fifo(xhfc, (channel << 1), 4, 0, 0, 0);
+			setup_fifo(xhfc, (channel << 1) + 1, 4, 0, 0, 0);
+			setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0,
+				 0);
+			clear_bit(FLG_HDLC, &bch->Flags);
+			clear_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_P_B_RAW):
+			setup_fifo(xhfc, (channel << 1), 6, 0, 0, 1);
+			setup_fifo(xhfc, (channel << 1) + 1, 6, 0, 0, 1);
+			setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0,
+				 1);
+			bch->state = protocol;
+			set_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_P_B_HDLC):
+			setup_fifo(xhfc, (channel << 1), 4, 0, M_FR_ABO, 1);
+			setup_fifo(xhfc, (channel << 1) + 1, 4, 0,
+				   M_FR_ABO | M_FIFO_IRQMSK, 1);
+			setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0,
+				 1);
+			bch->state = protocol;
+			set_bit(FLG_HDLC, &bch->Flags);
+			break;
+		default:
+			return (-ENOPROTOOPT);
+	}
+	return (0);
+}
+
+/*
+ * init DChannel TX/RX fifos
+ */
+static void
+xhfc_setup_dch(struct dchannel *dch)
+{
+	struct port *port = dch->hw;
+	struct xhfc *xhfc = port->xhfc;
+	__u8 channel = (port->idx * 4) + 2;
+	setup_fifo(xhfc, (channel << 1), 5, 2, M_FR_ABO, 1);
+	setup_fifo(xhfc, (channel << 1) + 1, 5, 2,
+		   M_FR_ABO | M_FIFO_IRQMSK, 1);
+}
+
+/*
+ * init EChannel RX fifo
+ */
+static void
+xhfc_setup_ech(struct dchannel *ech)
+{
+	struct port *port = ech->hw;
+	struct xhfc *xhfc = port->xhfc;
+	__u8 channel = (port->idx * 4) + 3;
+	setup_fifo(xhfc, (channel << 1) + 1, 5, 2,
+		   M_FR_ABO | M_FIFO_IRQMSK, 1);
+}
+
+static void
+xhfc_ph_command(struct port *port, u_char command)
+{
+	struct xhfc *xhfc = port->xhfc;
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s %s: %s (%i)\n",
+		       __FUNCTION__, port->name, XHFC_PH_COMMANDS[command],
+		       command);
+
+	switch (command) {
+		case L1_ACTIVATE_TE:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_ACTIVATE);
+			break;
+
+		case L1_FORCE_DEACTIVATE_TE:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_DEACTIVATE);
+			break;
+
+		case L1_ACTIVATE_NT:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA,
+				   STA_ACTIVATE | M_SU_SET_G2_G3);
+			break;
+
+		case L1_DEACTIVATE_NT:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_DEACTIVATE);
+			break;
+
+		case L1_SET_TESTLOOP_B1:
+			/* connect B1-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx * 8, 0xC6, 0, 0, 0);
+			/* connect B1-SU TX with PCM RX */
+			setup_fifo(xhfc, port->idx * 8 + 1, 0xC6, 0, 0, 0);
+
+			/* PCM timeslot B1 TX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8);
+			/* enable B1 TX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG, port->idx * 8 + 0x80);
+
+			/* PCM timeslot B1 RX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 1);
+			/* enable B1 RX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG,
+				   port->idx * 8 + 1 + 0xC0);
+
+			setup_su(xhfc, port->idx, 0, 1);
+			break;
+
+		case L1_UNSET_TESTLOOP_B1:
+			/* disable RX/TX fifos */
+			setup_fifo(xhfc, port->idx * 8, 4, 0, 0, 0);
+			setup_fifo(xhfc, port->idx * 8 + 1, 4, 0, 0, 0);
+
+			/* disable PCM timeslots */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 1);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+
+			setup_su(xhfc, port->idx, 0, 0);
+			break;
+
+		case L1_SET_TESTLOOP_B2:
+			/* connect B2-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx * 8 + 2, 0xC6, 0, 0, 0);
+			/* connect B2-SU TX with PCM RX */
+			setup_fifo(xhfc, port->idx * 8 + 3, 0xC6, 0, 0, 0);
+
+			/* PCM timeslot B2 TX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 2);
+			/* enable B2 TX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG,
+				   port->idx * 8 + 2 + 0x80);
+
+			/* PCM timeslot B2 RX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 3);
+			/* enable B2 RX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG,
+				   port->idx * 8 + 3 + 0xC0);
+
+			setup_su(xhfc, port->idx, 1, 1);
+			break;
+
+		case L1_UNSET_TESTLOOP_B2:
+			/* disable RX/TX fifos */
+			setup_fifo(xhfc, port->idx * 8 + 2, 4, 0, 0, 0);
+			setup_fifo(xhfc, port->idx * 8 + 3, 4, 0, 0, 0);
+
+			/* disable PCM timeslots */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 2);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 3);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+
+			setup_su(xhfc, port->idx, 1, 0);
+			break;
+
+		case L1_SET_TESTLOOP_D:
+			/* connect D-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx * 8 + 4, 0xC4, 2, 0, 0);
+			/* connect D-SU TX with PCM RX */
+			setup_fifo(xhfc, port->idx * 8 + 5, 0xC4, 2, 0, 0);
+
+			/* PCM timeslot D TX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 4);
+			/* enable D TX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG, port->idx * 8 + 4 + 0x80);
+
+			/* PCM timeslot D RX */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 5);
+			/* enable D RX timeslot on STIO1 */
+			write_xhfc(xhfc, A_SL_CFG, port->idx * 8 + 5 + 0xC0);
+			break;
+
+		case L1_UNSET_TESTLOOP_D:
+			// enable Fifos
+			setup_fifo(xhfc, port->idx * 8 + 4, 5, 2, M_FR_ABO, 1);
+			setup_fifo(xhfc, port->idx * 8 + 5, 5, 2, M_FR_ABO | M_FIFO_IRQMSK, 1);
+
+			/* disable PCM timeslots */
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 4);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+			write_xhfc(xhfc, R_SLOT, port->idx * 8 + 5);
+			write_xhfc(xhfc, A_SL_CFG, 0);
+			break;
+	}
+}
+
+/*
+ * xhfc reset sequence:
+ */
+static int
+reset_xhfc(struct xhfc *xhfc)
+{
+	if (debug & DEBUG_HW) {
+		printk(KERN_INFO "%s %s", xhfc->name, __FUNCTION__);
+	}
+
+	/* software reset to enable R_FIFO_MD setting */
+	write_xhfc(xhfc, R_CIRM, M_SRES);
+	udelay(5);
+	write_xhfc(xhfc, R_CIRM, 0);
+
+	write_xhfc(xhfc, R_FIFO_THRES, 0x11);
+
+	return 0;
+}
+
+/**
+ * pcm init sequence
+ */
+static int
+init_pcm(struct xhfc *xhfc)
+{
+	int timeout = 0x2000;
+
+	while ((read_xhfc(xhfc, R_STATUS) & (M_BUSY | M_PCM_INIT)) && (timeout)) {
+                timeout--;
+        }
+
+        if (!(timeout)) {
+                if (debug & DEBUG_HW) {
+                        printk(KERN_ERR
+                               "%s %s: initialization sequence "
+                               "not completed!\n",
+                               xhfc->name, __FUNCTION__);
+                }
+                return (-ENODEV);
+        }
+
+        /* set PCM master mode */
+        SET_V_PCM_MD(xhfc->pcm_md0, 1);
+        write_xhfc(xhfc, R_PCM_MD0, xhfc->pcm_md0);
+
+        /* set pll adjust */
+        SET_V_PCM_IDX(xhfc->pcm_md0, 0x09);
+        SET_V_PLL_ADJ(xhfc->pcm_md1, 3);
+        write_xhfc(xhfc, R_PCM_MD0, xhfc->pcm_md0);
+	write_xhfc(xhfc, R_PCM_MD1, xhfc->pcm_md1);
+
+	return 0;
+}
+
+
+/*
+ * initialise the XHFC ISDN controller
+ * return 0 on success.
+ */
+static int
+init_xhfc(struct xhfc *xhfc)
+{
+	int err = 0;
+	__u8 chip_id;
+
+	chip_id = read_xhfc(xhfc, R_CHIP_ID);
+	switch (chip_id) {
+		case CHIP_ID_1SU:
+			xhfc->num_ports = 1;
+			xhfc->channels = 4;
+			xhfc->max_z = 0xFF;
+
+			/* timer irq interval 16 ms */
+			SET_V_EV_TS(xhfc->ti_wd, 6);
+
+			write_xhfc(xhfc, R_FIFO_MD, 2);
+			SET_V_SU0_IRQMSK(xhfc->su_irqmsk, 1);
+			sprintf(xhfc->name, "%s_PI%d_%i",
+				CHIP_NAME_1SU,
+				xhfc->pi->cardnum, xhfc->chipidx);
+			break;
+
+		case CHIP_ID_2SU:
+			xhfc->num_ports = 2;
+			xhfc->channels = 8;
+			xhfc->max_z = 0x7F;
+
+			/* timer irq interval 8 ms */
+			SET_V_EV_TS(xhfc->ti_wd, 5);
+
+			write_xhfc(xhfc, R_FIFO_MD, 1);
+			SET_V_SU0_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU1_IRQMSK(xhfc->su_irqmsk, 1);
+			sprintf(xhfc->name, "%s_PI%d_%i",
+				CHIP_NAME_2SU,
+				xhfc->pi->cardnum, xhfc->chipidx);
+			break;
+
+		case CHIP_ID_2S4U:
+			xhfc->num_ports = 4;
+			xhfc->channels = 16;
+			xhfc->max_z = 0x3F;
+
+			/* timer irq interval 4 ms */
+			SET_V_EV_TS(xhfc->ti_wd, 4);
+
+			write_xhfc(xhfc, R_FIFO_MD, 0);
+			SET_V_SU0_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU1_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU2_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU3_IRQMSK(xhfc->su_irqmsk, 1);
+			sprintf(xhfc->name, "%s_PI%d_%i",
+				CHIP_NAME_2S4U,
+				xhfc->pi->cardnum, xhfc->chipidx);
+			break;
+		case CHIP_ID_4SU:
+			xhfc->num_ports = 4;
+			xhfc->channels = 16;
+			xhfc->max_z = 0x3F;
+
+			/* timer irq interval 4 ms */
+			SET_V_EV_TS(xhfc->ti_wd, 4);
+
+			write_xhfc(xhfc, R_FIFO_MD, 0);
+			SET_V_SU0_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU1_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU2_IRQMSK(xhfc->su_irqmsk, 1);
+			SET_V_SU3_IRQMSK(xhfc->su_irqmsk, 1);
+			sprintf(xhfc->name, "%s_PI%d_%i",
+				CHIP_NAME_4SU,
+				xhfc->pi->cardnum, xhfc->chipidx);
+			break;
+		default:
+			err = -ENODEV;
+	}
+
+	if (err) {
+		if (debug & DEBUG_HW)
+			printk(KERN_ERR "%s %s: unkown Chip ID 0x%x\n",
+			       xhfc->name, __FUNCTION__, chip_id);
+		return (err);
+	} else {
+		if (debug & DEBUG_HW)
+			printk(KERN_INFO "%s ChipID: 0x%x\n",
+			       xhfc->name, chip_id);
+	}
+
+	mutex_init(&xhfc->lock);
+	spin_lock_init(&xhfc->lock_irq);
+	mutex_init(&xhfc->transaction_lock);
+	reset_xhfc(xhfc);
+
+	/* init pcm */
+	init_pcm(xhfc);
+
+	/* perfom short irq test */
+	xhfc->testirq = 1;
+	enable_interrupts(xhfc);
+	mdelay(1 << GET_V_EV_TS(xhfc->ti_wd));
+
+	/*struct spi_device *spi = xhfc->pi->pdev;
+
+	uint8_t txbuf[4];
+	txbuf[0] = 0x60;
+	txbuf[1] = R_IRQ_CTRL;
+
+	spi_write_then_read(spi, txbuf, 2, NULL, 0);
+	*/
+	//mdelay(1000);
+	disable_interrupts(xhfc);
+
+	if (xhfc->irq_cnt > 2) {
+		xhfc->testirq = 0;
+		return (0);
+	} else {
+		if (debug & DEBUG_HW)
+			printk(KERN_INFO
+			       "%s %s: ERROR getting IRQ (irq_cnt %i)\n",
+			       xhfc->name, __FUNCTION__, xhfc->irq_cnt);
+		return (-EIO);
+	}
+}
+
+/*
+ * init mISDN interface (called for each XHFC)
+ */
+int
+setup_instance(struct xhfc *xhfc, struct device *parent)
+{
+	struct port *p;
+	int err = 0, i, j;
+
+	if (debug)
+		printk(KERN_INFO "%s: %s\n", DRIVER_NAME, __func__);
+
+	tasklet_init(&xhfc->tasklet, xhfc_bh_handler,
+		     (unsigned long) xhfc);
+
+	err = init_xhfc(xhfc);
+	if (err)
+		goto out;
+
+	err = -ENOMEM;
+	xhfc->port =
+	    kzalloc(sizeof(struct port) * xhfc->num_ports, GFP_KERNEL);
+	for (i = 0; i < xhfc->num_ports; i++) {
+		p = xhfc->port + i;
+		p->idx = i;
+		p->xhfc = xhfc;
+		mutex_init(&p->lock);
+
+		/* init D-Channel Interface */
+		mISDN_initdchannel(&p->dch, MAX_DFRAME_LEN_L1, ph_state);
+		p->dch.dev.D.send = xhfc_l2l1D;
+		p->dch.dev.D.ctrl = xhfc_dctrl;
+		p->dch.debug = debug & 0xFFFF;
+		p->dch.hw = p;
+		p->dch.dev.Dprotocols =
+		    (1 << ISDN_P_TE_S0) |
+		    (1 << ISDN_P_NT_S0) |
+		    (1 << ISDN_P_TE_UP0) |
+		    (1 << ISDN_P_NT_UP0);
+
+		/* init E-Channel Interface */
+		mISDN_initdchannel(&p->ech, MAX_DFRAME_LEN_L1, NULL);
+		p->ech.hw = p;
+		p->ech.debug = debug & 0xFFFF;
+
+		/* init B-Channel Interfaces */
+		p->dch.dev.Bprotocols =
+		    (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | (1 <<
+							     (ISDN_P_B_HDLC
+							      &
+							      ISDN_P_B_MASK));
+		p->dch.dev.nrbchan = 2;
+		for (j = 0; j < 2; j++) {
+			p->bch[j].nr = j + 1;
+			set_channelmap(j + 1, p->dch.dev.channelmap);
+			p->bch[j].debug = debug;
+			mISDN_initbchannel(&p->bch[j], MAX_DATA_MEM, 0);
+			p->bch[j].hw = p;
+			p->bch[j].ch.send = xhfc_l2l1B;
+			p->bch[j].ch.ctrl = xhfc_bctrl;
+			p->bch[j].ch.nr = j + 1;
+			list_add(&p->bch[j].ch.list,
+				 &p->dch.dev.bchannels);
+		}
+
+		/*
+		 * init F7 timer to delay ACTIVATE INDICATION
+		 */
+		timer_setup(&p->f7_timer, f7_timer_expire, 0);
+
+		snprintf(p->name, MISDN_MAX_IDLEN - 1, "%s.%d",
+			 DRIVER_NAME, xhfc_cnt + 1);
+		printk(KERN_INFO "%s: registered as '%s'\n", DRIVER_NAME,
+		       p->name);
+
+		err = mISDN_register_device(&p->dch.dev, parent, p->name);
+		if (err) {
+			mISDN_freebchannel(&p->bch[1]);
+			mISDN_freebchannel(&p->bch[0]);
+			mISDN_freedchannel(&p->dch);
+			mISDN_freedchannel(&p->ech);
+		} else {
+			xhfc_cnt++;
+			xhfc_setup_dch(&p->dch);
+			enable_interrupts(xhfc);
+		}
+	}
+
+      out:
+	return err;
+}
+
+int
+release_instance(struct xhfc *hw)
+{
+	struct port *p;
+	int i;
+
+	if (debug)
+		printk(KERN_INFO "%s: %s\n", DRIVER_NAME, __func__);
+
+	disable_interrupts(hw);
+	tasklet_disable(&hw->tasklet);
+	tasklet_kill(&hw->tasklet);
+
+	for (i = 0; i < hw->num_ports; i++) {
+		p = hw->port + i;
+		/* TODO
+		   xhfc_setup_bch(&p->bch[0], ISDN_P_NONE);
+		   xhfc_setup_bch(&p->bch[1], ISDN_P_NONE);
+		 */
+		if (p->mode & PORT_MODE_TE)
+			l1_event(p->dch.l1, CLOSE_CHANNEL);
+
+		mISDN_unregister_device(&p->dch.dev);
+		mISDN_freebchannel(&p->bch[1]);
+		mISDN_freebchannel(&p->bch[0]);
+		mISDN_freedchannel(&p->dch);
+		mISDN_freedchannel(&p->ech);
+
+		if (timer_pending(&p->f7_timer)) {
+			del_timer(&p->f7_timer);
+		}
+	}
+
+	if (hw) {
+		if (hw->port)
+			kfree(hw->port);
+		kfree(hw);
+	}
+	return 0;
+}
+
+/*
+ * Layer 1 callback function
+ */
+static int
+xhfc_l1callback(struct dchannel *dch, u_int cmd)
+{
+	struct port *p = dch->hw;
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s: %s cmd 0x%x\n",
+		       p->name, __func__, cmd);
+
+	switch (cmd) {
+		case INFO3_P8:
+		case INFO3_P10:
+		case HW_RESET_REQ:
+		case HW_POWERUP_REQ:
+			break;
+
+		case HW_DEACT_REQ:
+			skb_queue_purge(&dch->squeue);
+			if (dch->tx_skb) {
+				dev_kfree_skb(dch->tx_skb);
+				dch->tx_skb = NULL;
+			}
+			dch->tx_idx = 0;
+			if (dch->rx_skb) {
+				dev_kfree_skb(dch->rx_skb);
+				dch->rx_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			break;
+		case PH_ACTIVATE_IND:
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+			_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0,
+				    NULL, GFP_ATOMIC);
+			break;
+		case PH_DEACTIVATE_IND:
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+			_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0,
+				    NULL, GFP_ATOMIC);
+			break;
+		default:
+			if (dch->debug & DEBUG_HW)
+				printk(KERN_INFO
+				       "%s: %s: unknown cmd %x\n", p->name,
+				       __func__, cmd);
+			return -1;
+	}
+	return 0;
+}
+
+static void
+deactivate_bchannel(struct bchannel *bch)
+{
+	struct port *p = bch->hw;
+
+	if (bch->debug)
+		printk(KERN_INFO "%s: %s: bch->nr(%i)\n",
+		       p->name, __func__, bch->nr);
+
+	mutex_lock(&p->lock);
+	mISDN_clear_bchannel(bch);
+	mutex_unlock(&p->lock);
+
+	mutex_lock(&p->xhfc->lock);
+	xhfc_setup_bch(bch, ISDN_P_NONE);
+	mutex_unlock(&p->xhfc->lock);
+}
+
+/*
+ * Layer2 -> Layer 1 Bchannel data
+ */
+static int
+xhfc_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+	struct bchannel *bch = container_of(ch, struct bchannel, ch);
+	struct port *p = bch->hw;
+	__u8 channel = (p->idx * 4) + (bch->nr - 1);
+	int ret = -EINVAL;
+	struct mISDNhead *hh = mISDN_HEAD_P(skb);
+
+	if (debug & DEBUG_HW)
+		//printk(KERN_INFO "%s: %s\n", p->name, __func__);
+
+	switch (hh->prim) {
+		case PH_DATA_REQ:
+			mutex_lock(&p->lock);
+			ret = bchannel_senddata(bch, skb);
+			mutex_unlock(&p->lock);
+
+			if (ret > 0) {
+				mutex_lock(&p->xhfc->lock);
+				xhfc_write_fifo(p->xhfc, channel);
+				mutex_unlock(&p->xhfc->lock);
+				ret = 0;
+			}
+			return ret;
+		case PH_ACTIVATE_REQ:
+			if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+				mutex_lock(&p->xhfc->lock);
+				ret = xhfc_setup_bch(bch, ch->protocol);
+				mutex_unlock(&p->xhfc->lock);
+			} else
+				ret = 0;
+			if (!ret)
+				_queue_data(ch, PH_ACTIVATE_IND,
+					    MISDN_ID_ANY, 0, NULL,
+					    GFP_KERNEL);
+			break;
+		case PH_DEACTIVATE_REQ:
+			deactivate_bchannel(bch);
+			_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY,
+				    0, NULL, GFP_KERNEL);
+			ret = 0;
+			break;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return ret;
+}
+
+/*
+ * Layer2 -> Layer 1 Dchannel data
+ */
+static int
+xhfc_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+	struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+	struct dchannel *dch = container_of(dev, struct dchannel, dev);
+	struct mISDNhead *hh = mISDN_HEAD_P(skb);
+	struct port *p = dch->hw;
+	int ret = -EINVAL;
+
+	switch (hh->prim) {
+		case PH_DATA_REQ:
+			if (debug & DEBUG_HW)
+				printk(KERN_INFO "%s: %s: PH_DATA_REQ\n",
+				       p->name, __func__);
+
+			mutex_lock(&p->lock);
+			ret = dchannel_senddata(dch, skb);
+			mutex_unlock(&p->lock);
+			if (ret > 0) {
+				ret = 0;
+				queue_ch_frame(ch, PH_DATA_CNF, hh->id,
+					       NULL);
+			}
+			return ret;
+
+		case PH_ACTIVATE_REQ:
+			if (debug & DEBUG_HW)
+				printk(KERN_INFO
+				       "%s: %s: PH_ACTIVATE_REQ %s\n",
+				       p->name, __func__,
+				       (p->mode & PORT_MODE_NT) ?
+				       "NT" : "TE");
+
+			if (p->mode & PORT_MODE_NT) {
+				ret = 0;
+				if (test_bit(FLG_ACTIVE, &dch->Flags)) {
+					_queue_data(&dch->dev.D,
+						    PH_ACTIVATE_IND,
+						    MISDN_ID_ANY, 0, NULL,
+						    GFP_ATOMIC);
+				} else {
+					mutex_lock(&p->xhfc->lock);
+					xhfc_ph_command(p, L1_ACTIVATE_NT);
+					mutex_unlock(&p->xhfc->lock);
+					test_and_set_bit(FLG_L2_ACTIVATED,
+							 &dch->Flags);
+				}
+			} else {
+				mutex_lock(&p->xhfc->lock);
+				xhfc_ph_command(p, L1_ACTIVATE_TE);
+				mutex_unlock(&p->xhfc->lock);
+				ret = l1_event(dch->l1, hh->prim);
+			}
+			break;
+
+		case PH_DEACTIVATE_REQ:
+			if (debug & DEBUG_HW)
+				printk(KERN_INFO
+				       "%s: %s: PH_DEACTIVATE_REQ\n",
+				       p->name, __func__);
+			test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+
+			if (p->mode & PORT_MODE_NT) {
+				mutex_lock(&p->xhfc->lock);
+				xhfc_ph_command(p, L1_DEACTIVATE_NT);
+				mutex_unlock(&p->xhfc->lock);
+
+				mutex_lock(&p->lock);
+				skb_queue_purge(&dch->squeue);
+				if (dch->tx_skb) {
+					dev_kfree_skb(dch->tx_skb);
+					dch->tx_skb = NULL;
+				}
+				dch->tx_idx = 0;
+				if (dch->rx_skb) {
+					dev_kfree_skb(dch->rx_skb);
+					dch->rx_skb = NULL;
+				}
+				test_and_clear_bit(FLG_TX_BUSY,
+						   &dch->Flags);
+				mutex_unlock(&p->lock);
+				ret = 0;
+			} else {
+				ret = l1_event(dch->l1, hh->prim);
+			}
+			break;
+	}
+	return ret;
+}
+
+/*
+ * Layer 1 B-channel hardware access
+ */
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+	int ret = 0;
+
+	switch (cq->op) {
+		case MISDN_CTRL_GETOP:
+			cq->op = MISDN_CTRL_FILL_EMPTY;
+			break;
+		case MISDN_CTRL_FILL_EMPTY:
+			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+			if (debug & DEBUG_HW_OPEN)
+				printk(KERN_INFO
+				       "%s: FILL_EMPTY request (nr=%d "
+				       "off=%d)\n", __func__, bch->nr,
+				       !!cq->p1);
+			break;
+		default:
+			printk(KERN_WARNING "%s: unknown Op %x\n",
+			       __func__, cq->op);
+			ret = -EINVAL;
+			break;
+	}
+	return ret;
+}
+
+/*
+ * Layer 1 B-channel hardware access
+ */
+static int
+xhfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
+{
+	struct bchannel *bch = container_of(ch, struct bchannel, ch);
+	int ret = -EINVAL;
+
+	if (bch->debug & DEBUG_HW)
+		printk(KERN_INFO "%s: cmd:%x %p\n", __func__, cmd, arg);
+
+	switch (cmd) {
+		case HW_TESTRX_RAW:
+		case HW_TESTRX_HDLC:
+		case HW_TESTRX_OFF:
+			ret = -EINVAL;
+			break;
+
+		case CLOSE_CHANNEL:
+			test_and_clear_bit(FLG_OPEN, &bch->Flags);
+			deactivate_bchannel(bch);
+			ch->protocol = ISDN_P_NONE;
+			ch->peer = NULL;
+			module_put(THIS_MODULE);
+			ret = 0;
+			break;
+		case CONTROL_CHANNEL:
+			ret = channel_bctrl(bch, arg);
+			break;
+		default:
+			printk(KERN_WARNING "%s: unknown prim(%x)\n",
+			       __func__, cmd);
+	}
+	return ret;
+}
+
+static int
+open_dchannel(struct port *p, struct mISDNchannel *ch,
+	      struct channel_req *rq)
+{
+	int err = 0;
+
+	if (debug & DEBUG_HW_OPEN)
+		printk(KERN_INFO "%s: %s: dev(%d) open from %p\n",
+		       p->name, __func__, p->dch.dev.id,
+		       __builtin_return_address(0));
+	if (rq->protocol == ISDN_P_NONE)
+		return -EINVAL;
+
+	test_and_clear_bit(FLG_ACTIVE, &p->dch.Flags);
+	test_and_clear_bit(FLG_ACTIVE, &p->ech.Flags);
+	p->dch.state = 0;
+
+	mutex_lock(&p->xhfc->lock);
+
+	/* E-Channel logging */
+	if (rq->adr.channel == 1) {
+		xhfc_setup_ech(&p->ech);
+		set_bit(FLG_ACTIVE, &p->ech.Flags);
+		_queue_data(&p->ech.dev.D, PH_ACTIVATE_IND,
+			     MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+	}
+
+	if (!p->initdone) {
+		if (IS_ISDN_P_S0(rq->protocol))
+			p->mode |= PORT_MODE_S0;
+		else if (IS_ISDN_P_UP0(rq->protocol))
+			p->mode |= PORT_MODE_UP0;
+
+		if (IS_ISDN_P_TE(rq->protocol)) {
+			p->mode |= PORT_MODE_TE;
+			err = create_l1(&p->dch, xhfc_l1callback);
+			if (err) {
+				mutex_unlock(&p->xhfc->lock);
+				return err;
+			}
+		} else {
+			p->mode |= PORT_MODE_NT;
+		}
+		init_su(p);
+		ch->protocol = rq->protocol;
+		p->initdone = 1;
+	} else {
+		if (rq->protocol != ch->protocol) {
+			mutex_unlock(&p->xhfc->lock);
+			return -EPROTONOSUPPORT;
+		}
+	}
+
+	/* force initial layer1 statechanges */
+	p->xhfc->su_irq = p->xhfc->su_irqmsk;
+
+	mutex_unlock(&p->xhfc->lock);
+
+	if (((ch->protocol == ISDN_P_NT_S0) && (p->dch.state == 3)) ||
+	    ((ch->protocol == ISDN_P_TE_S0) && (p->dch.state == 7)))
+		_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+			    0, NULL, GFP_KERNEL);
+
+	rq->ch = ch;
+	if (!try_module_get(THIS_MODULE))
+		printk(KERN_WARNING "%s: %s: cannot get module\n",
+		       p->name, __func__);
+	return 0;
+}
+
+static int
+open_bchannel(struct port *p, struct channel_req *rq)
+{
+	struct bchannel *bch;
+
+	if (rq->adr.channel > 2)
+		return -EINVAL;
+	if (rq->protocol == ISDN_P_NONE)
+		return -EINVAL;
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s: %s B%i\n",
+		       p->name, __func__, rq->adr.channel);
+
+	bch = &p->bch[rq->adr.channel - 1];
+	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+		return -EBUSY;	/* b-channel can be only open once */
+	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+	bch->ch.protocol = rq->protocol;
+	rq->ch = &bch->ch;
+
+	if (!try_module_get(THIS_MODULE))
+		printk(KERN_WARNING "%s: %s:cannot get module\n",
+		       p->name, __func__);
+	return 0;
+}
+
+static int
+channel_ctrl(struct port *p, struct mISDN_ctrl_req *cq)
+{
+	int ret = 0;
+
+	if (debug)
+		printk(KERN_INFO "%s: %s op(0x%x) channel(0x%x)\n",
+		       p->name, __func__, (cq->op), (cq->channel));
+
+	switch (cq->op) {
+		case MISDN_CTRL_GETOP:
+			cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
+			    MISDN_CTRL_DISCONNECT;
+			break;
+
+		case MISDN_CTRL_LOOP:
+			/*
+			 * control testloops (line RX -> line TX)
+			 *
+			 * cq->channel:
+			 *   0 disable all
+			 *   bit0 : 1: set B1 loop, 0: unset B1 loop
+			 *   bit1 : 1: set B2 loop, 0: unset B2 loop
+			 *   bit2 : 1: set D  loop, 0: unset D  loop
+			 *
+			 *   e.g. 3 enables B1 + B2 and disabled D loop
+			 */
+			if ((cq->channel < 0) || (cq->channel > 7)) {
+				ret = -EINVAL;
+				break;
+			}
+
+			mutex_lock(&p->xhfc->lock);
+			if (cq->channel & 1) {
+				xhfc_ph_command(p, L1_SET_TESTLOOP_B1);
+			} else {
+				xhfc_ph_command(p, L1_UNSET_TESTLOOP_B1);
+			}
+			if (cq->channel & 2) {
+				xhfc_ph_command(p, L1_SET_TESTLOOP_B2);
+			} else {
+				xhfc_ph_command(p, L1_UNSET_TESTLOOP_B2);
+			}
+			if (cq->channel & 4) {
+				xhfc_ph_command(p, L1_SET_TESTLOOP_D);
+			} else {
+				xhfc_ph_command(p, L1_UNSET_TESTLOOP_D);
+			}
+			mutex_unlock(&p->xhfc->lock);
+			break;
+
+		default:
+			printk(KERN_WARNING "%s: %s: unknown Op %x\n",
+			       p->name, __func__, cq->op);
+			ret = -EINVAL;
+			break;
+	}
+	return ret;
+}
+
+/*
+ * device control function
+ */
+static int
+xhfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
+{
+	struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+	struct dchannel *dch = container_of(dev, struct dchannel, dev);
+	struct port *p = dch->hw;
+	struct channel_req *rq;
+	int err = 0;
+
+	if (dch->debug & DEBUG_HW)
+		printk(KERN_INFO "%s: %s: cmd:%x %p\n",
+		       p->name, __func__, cmd, arg);
+	switch (cmd) {
+		case OPEN_CHANNEL:
+			rq = arg;
+			if ((IS_ISDN_P_S0(rq->protocol)) ||
+			    (IS_ISDN_P_UP0(rq->protocol)))
+				err = open_dchannel(p, ch, rq);
+			else
+				err = open_bchannel(p, rq);
+			break;
+		case CLOSE_CHANNEL:
+			if (debug & DEBUG_HW_OPEN)
+				printk(KERN_INFO
+				       "%s: %s: dev(%d) close from %p\n",
+				       p->name, __func__, p->dch.dev.id,
+				       __builtin_return_address(0));
+			module_put(THIS_MODULE);
+			break;
+		case CONTROL_CHANNEL:
+			err = channel_ctrl(p, arg);
+			break;
+		default:
+			if (dch->debug & DEBUG_HW)
+				printk(KERN_INFO
+				       "%s: %s: unknown command %x\n",
+				       p->name, __func__, cmd);
+			return -EINVAL;
+	}
+	return err;
+}
+
+/*
+ * send ACTIVATE INDICATION to l2
+ */
+static void
+f7_timer_expire(struct timer_list *t)
+{
+	struct port *port = from_timer(port, t, f7_timer);
+	l1_event(port->dch.l1, XHFC_L1_F7);
+}
+
+/*
+ * S0 TE state change event handler
+ */
+static void
+ph_state_te(struct dchannel *dch)
+{
+	struct port *p = dch->hw;
+
+	if (debug)
+		printk(KERN_INFO "%s: %s: TE F%d\n",
+		       p->name, __func__, dch->state);
+
+	if ((dch->state != 7) && timer_pending(&p->f7_timer))
+		del_timer(&p->f7_timer);
+
+	switch (dch->state) {
+		case 0:
+			l1_event(dch->l1, XHFC_L1_F0);
+			break;
+		case 3:
+			l1_event(dch->l1, XHFC_L1_F3);
+			break;
+		case 5:
+		case 8:
+			l1_event(dch->l1, ANYSIGNAL);
+			break;
+		case 6:
+			l1_event(dch->l1, INFO2);
+			break;
+		case 7:
+			/* delay ACTIVATE INDICATION for 1ms */
+			if (!(timer_pending(&p->f7_timer))) {
+				p->f7_timer.expires = jiffies + (HZ / 1000);
+				add_timer(&p->f7_timer);
+			}
+			break;
+	}
+}
+
+/*
+ * S0 NT state change event handler
+ */
+static void
+ph_state_nt(struct dchannel *dch)
+{
+	struct port *p = dch->hw;
+
+	if (debug & DEBUG_HW)
+		printk(KERN_INFO "%s: %s: NT G%d\n",
+		       p->name, __func__, dch->state);
+
+	switch (dch->state) {
+		case (1):
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+			test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+			p->nt_timer = 0;
+			p->timers &= ~NT_ACTIVATION_TIMER;
+			_queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
+				    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+			break;
+		case (2):
+			if (p->nt_timer < 0) {
+				p->nt_timer = 0;
+				p->timers &= ~NT_ACTIVATION_TIMER;
+				write_xhfc(p->xhfc, R_SU_SEL, p->idx);
+				write_xhfc(p->xhfc, A_SU_WR_STA, 4 | STA_LOAD);
+				udelay(10);
+				write_xhfc(p->xhfc, A_SU_WR_STA, 4);
+				dch->state = 4;
+			} else {
+				p->timers |= NT_ACTIVATION_TIMER;
+				p->nt_timer = NT_T1_COUNT;
+				write_xhfc(p->xhfc, R_SU_SEL, p->idx);
+				write_xhfc(p->xhfc, A_SU_WR_STA, M_SU_SET_G2_G3);
+			}
+			break;
+		case (3):
+			p->nt_timer = 0;
+			p->timers &= ~NT_ACTIVATION_TIMER;
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+			_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
+				    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+			break;
+		case (4):
+			p->nt_timer = 0;
+			p->timers &= ~NT_ACTIVATION_TIMER;
+			return;
+		default:
+			break;
+	}
+}
+
+static void
+ph_state(struct dchannel *dch)
+{
+	struct port *p = dch->hw;
+	if (p->mode & PORT_MODE_NT)
+		ph_state_nt(dch);
+	else if (p->mode & PORT_MODE_TE)
+		ph_state_te(dch);
+}
+
+/*
+ * fill fifo with TX data
+ */
+static void
+xhfc_write_fifo(struct xhfc *xhfc, __u8 channel)
+{
+	__u8 fcnt, tcnt, i, free, f1, f2, fstat, *data;
+	int remain, tx_busy = 0;
+	int hdlc = 0;
+	int *tx_idx = NULL;
+	struct sk_buff **tx_skb = NULL;
+	struct port *port = xhfc->port + (channel / 4);
+	struct bchannel *bch = NULL;
+	struct dchannel *dch = NULL;
+
+
+	/* protect against layer2 down processes like l2l1D, l2l1B, etc */
+	mutex_lock(&port->lock);
+
+	switch (channel % 4) {
+		case 0:
+		case 1:
+			bch = &port->bch[channel % 4];
+			tx_skb = &bch->tx_skb;
+			tx_idx = &bch->tx_idx;
+			tx_busy = test_bit(FLG_TX_BUSY, &bch->Flags);
+			hdlc = test_bit(FLG_HDLC, &bch->Flags);
+			break;
+		case 2:
+			dch = &port->dch;
+			tx_skb = &dch->tx_skb;
+			tx_idx = &dch->tx_idx;
+			tx_busy = test_bit(FLG_TX_BUSY, &dch->Flags);
+			hdlc = 1;
+			break;
+		case 3:
+		default:
+			mutex_unlock(&port->lock);
+			return;
+	}
+	if (!*tx_skb || !tx_busy) {
+		mutex_unlock(&port->lock);
+		return;
+	}
+
+      send_buffer:
+	remain = (*tx_skb)->len - *tx_idx;
+	if (remain <= 0) {
+		mutex_unlock(&port->lock);
+		return;
+	}
+
+	xhfc_selfifo(xhfc, (channel * 2));
+
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	free = (xhfc->max_z - (read_xhfc(xhfc, A_USAGE)));
+	tcnt = (free >= remain) ? remain : free;
+
+	f1 = read_xhfc(xhfc, A_F1);
+	f2 = read_xhfc(xhfc, A_F2);
+
+	fcnt = 0x07 - ((f1 - f2) & 0x07); /* free frame count in tx fifo */
+
+	if (debug & DEBUG_HFC_FIFO_STAT) {
+		printk(KERN_INFO
+		       "%s channel(%i) len(%i) idx(%i) f1(%i) f2(%i) fcnt(%i) "
+		       "tcnt(%i) free(%i) fstat(%i)\n",
+		       __FUNCTION__, channel, (*tx_skb)->len, *tx_idx,
+		       f1, f2, fcnt, tcnt, free, fstat);
+	}
+
+	/* check for fifo underrun during frame transmission */
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	if (fstat & M_FIFO_ERR) {
+		if (debug & DEBUG_HFC_FIFO_ERR) {
+			printk(KERN_INFO
+			       "%s transmit fifo channel(%i) underrun idx(%i),"
+			       "A_FIFO_STA(0x%02x)\n",
+			       __FUNCTION__, channel, *tx_idx, fstat);
+		}
+
+		write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO_ERR);
+
+		/* restart frame transmission */
+		if (hdlc && *tx_idx) {
+			*tx_idx = 0;
+			goto send_buffer;
+		}
+	}
+
+	if (free && fcnt && tcnt) {
+		data = (*tx_skb)->data + *tx_idx;
+		*tx_idx += tcnt;
+
+		if (debug & DEBUG_HFC_FIFO_DATA) {
+			printk("%s channel(%i) writing: ",
+			       xhfc->name, channel);
+
+			i = 0;
+			while (i < tcnt)
+				printk("%02x ", *(data + (i++)));
+			printk("\n");
+		}
+
+		/* write data to FIFO */
+		i = 0;
+		while (i < tcnt) {
+                        write_xhfc(xhfc, A_FIFO_DATA, *(data + i));
+                        i++;
+		        /*
+		        // optimized bulk writes
+			if ((tcnt - i) >= 4) {
+				write32_xhfc(xhfc, A_FIFO_DATA,
+					     *((__u32 *) (data + i)));
+				i += 4;
+			} else {
+				write_xhfc(xhfc, A_FIFO_DATA, *(data + i));
+				i++;
+			}
+			*/
+		}
+
+		/* skb data complete */
+		if (*tx_idx == (*tx_skb)->len) {
+			if (hdlc)
+				xhfc_inc_f(xhfc);
+			else
+				xhfc_selfifo(xhfc, (channel * 2));
+
+			/* check for fifo underrun during frame transmission */
+			fstat = read_xhfc(xhfc, A_FIFO_STA);
+			if (fstat & M_FIFO_ERR) {
+				if (debug & DEBUG_HFC_FIFO_ERR) {
+					printk(KERN_INFO
+					       "%s transmit fifo channel(%i) "
+					       "underrun during transmission, "
+					       "A_FIFO_STA(0x%02x)\n",
+					       __FUNCTION__,
+					       channel, fstat);
+				}
+				write_xhfc(xhfc, A_INC_RES_FIFO,
+					   M_RES_FIFO_ERR);
+
+				if (hdlc) {
+					// restart frame transmission
+					*tx_idx = 0;
+					goto send_buffer;
+				}
+			}
+
+			dev_kfree_skb(*tx_skb);
+			*tx_skb = NULL;
+			if (bch) {
+				get_next_bframe(bch);
+			}
+			if (dch)
+				get_next_dframe(dch);
+
+			if (*tx_skb) {
+				if (debug & DEBUG_HFC_FIFO_DATA)
+					printk(KERN_INFO
+					       "channel(%i) has next_tx_frame\n",
+					       channel);
+				if ((free - tcnt) > 8) {
+					if (debug & DEBUG_HFC_FIFO_DATA)
+						printk(KERN_INFO
+						       "channel(%i) continue "
+						       "B-TX immediatetly\n",
+						       channel);
+					goto send_buffer;
+				}
+			}
+
+		} else {
+			/* tx buffer not complete, but fifo filled to maximum */
+			xhfc_selfifo(xhfc, (channel * 2));
+		}
+	}
+	mutex_unlock(&port->lock);
+}
+
+/*
+ * read RX data out of fifo
+ */
+static void
+xhfc_read_fifo(struct xhfc *xhfc, __u8 channel)
+{
+	__u8 f1 = 0, f2 = 0, z1 = 0, z2 = 0, pending;
+	__u8 fstat = 0;
+	int i;
+	int rcnt; /* read rcnt bytes out of fifo */
+	__u8 *data; /* new data pointer */
+	struct sk_buff **rx_skb = NULL;	/* data buffer for upper layer */
+	struct port *port = xhfc->port + (channel / 4);
+	struct bchannel *bch = NULL;
+	struct dchannel *dch = NULL;
+	struct dchannel *ech = NULL;
+	int maxlen = 0, hdlc = 0;
+
+
+	/* protect against layer2 down processes like l2l1D, l2l1B, etc */
+	mutex_lock(&port->lock);
+
+	switch (channel % 4) {
+		case 0:
+		case 1:
+			bch = &port->bch[channel % 4];
+			rx_skb = &bch->rx_skb;
+			hdlc = test_bit(FLG_HDLC, &bch->Flags);
+			maxlen = bch->maxlen;
+			break;
+		case 2:
+			dch = &port->dch;
+			rx_skb = &dch->rx_skb;
+			hdlc = 1;
+			maxlen = dch->maxlen;
+			break;
+		case 3:
+			ech = &port->ech;
+			rx_skb = &ech->rx_skb;
+			maxlen = ech->maxlen;
+			hdlc = 1;
+			break;
+		default:
+			mutex_unlock(&port->lock);
+			return;
+	}
+
+      receive_buffer:
+	xhfc_selfifo(xhfc, (channel * 2) + 1);
+
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	if (fstat & M_FIFO_ERR) {
+		if (debug & DEBUG_HFC_FIFO_ERR)
+			printk(KERN_INFO
+			       "RX fifo overflow channel(%i), "
+			       "A_FIFO_STA(0x%02x) f0cnt(%i)\n",
+			       channel, fstat, xhfc->f0_akku);
+		write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO_ERR);
+	}
+
+	if (hdlc) {
+		/* hdlc rcnt */
+		f1 = read_xhfc(xhfc, A_F1);
+		f2 = read_xhfc(xhfc, A_F2);
+		z1 = read_xhfc(xhfc, A_Z1);
+		z2 = read_xhfc(xhfc, A_Z2);
+
+		rcnt = (z1 - z2) & xhfc->max_z;
+		if (f1 != f2)
+			rcnt++;
+
+	} else {
+		/* transparent rcnt */
+		rcnt = read_xhfc(xhfc, A_USAGE) - 1;
+	}
+
+	if (debug & DEBUG_HFC_FIFO_STAT) {
+		if (*rx_skb)
+			i = (*rx_skb)->len;
+		else
+			i = 0;
+		printk(KERN_INFO "reading %i bytes channel(%i) "
+		       "irq_cnt(%i) fstat(%i) idx(%i/%i) f1(%i) f2(%i) "
+		       "z1(%i) z2(%i)\n",
+		       rcnt, channel, xhfc->irq_cnt, fstat, i, maxlen,
+		       f1, f2, z1, z2);
+	}
+
+	if (rcnt > 0) {
+		if (!(*rx_skb)) {
+			*rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC);
+			if (!(*rx_skb)) {
+				printk(KERN_INFO "%s: No mem for rx_skb\n",
+				       __FUNCTION__);
+				mutex_unlock(&port->lock);
+				return;
+			}
+		}
+
+		if ((rcnt + (*rx_skb)->len) > maxlen) {
+			if (debug & DEBUG_HFC_FIFO_ERR) {
+				printk(KERN_INFO
+				       "%s: channel(%i) fifo rx data exceeding skb maxlen(%d)\n",
+				       __FUNCTION__, channel, maxlen);
+			}
+			skb_trim(*rx_skb, 0);
+			xhfc_resetfifo(xhfc);
+			mutex_unlock(&port->lock);
+			return;
+		}
+		data = skb_put(*rx_skb, rcnt);
+
+		/* read data from FIFO */
+		i = 0;
+		while (i < rcnt) {
+		        *(data + i) = read_xhfc(xhfc, A_FIFO_DATA);
+		        i++;
+        		/*
+        		// optimized bulk reads:
+			if ((rcnt - i) >= 4) {
+				*((__u32 *) (data + i)) =
+				    read32_xhfc(xhfc, A_FIFO_DATA);
+				i += 4;
+			} else {
+				*(data + i) = read_xhfc(xhfc, A_FIFO_DATA);
+				i++;
+			}
+                        */
+		}
+	} else {
+		mutex_unlock(&port->lock);
+		return;
+	}
+
+	if (hdlc) {
+		if (f1 != f2) {
+			xhfc_inc_f(xhfc);
+
+			if (debug & DEBUG_HFC_FIFO_DATA) {
+				printk(KERN_INFO
+				       "channel(%i) new RX len(%i): ",
+				       channel, (*rx_skb)->len);
+				i = 0;
+				printk("  ");
+				while (i < (*rx_skb)->len)
+					printk("%02x ",
+					       (*rx_skb)->data[i++]);
+				printk("\n");
+			}
+
+			/* check minimum frame size */
+			if ((*rx_skb)->len < 4) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					printk(KERN_INFO
+					       "%s: frame in channel(%i) "
+					       "< minimum size\n",
+					       __FUNCTION__, channel);
+				goto read_exit;
+			}
+
+			/* check crc */
+			if ((*rx_skb)->data[(*rx_skb)->len - 1]) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					printk(KERN_INFO
+					       "%s: channel(%i) CRC-error\n",
+					       __FUNCTION__, channel);
+				goto read_exit;
+			}
+
+			/* remove cksum */
+			skb_trim(*rx_skb, (*rx_skb)->len - 3);
+
+			/* send PH_DATA_IND */
+			if (bch)
+				recv_Bchannel(bch, MISDN_ID_ANY, false);
+			if (dch)
+				recv_Dchannel(dch);
+			if (ech)
+				recv_Echannel(ech, &port->dch);
+
+		      read_exit:
+			if (*rx_skb)
+				skb_trim(*rx_skb, 0);
+
+			pending = read_xhfc(xhfc, A_USAGE);
+			f2++;
+			f2 %= 8;
+			if (pending > 8 || f1 != f2) {
+				if (debug & DEBUG_HFC_FIFO_STAT)
+					printk(KERN_DEBUG
+					       "%s: channel(%i) continue for %d bytes f2(%d)\n",
+					       __func__, channel, pending, f2);
+				goto receive_buffer;
+			}
+			mutex_unlock(&port->lock);
+			return;
+
+
+		} else {
+			xhfc_selfifo(xhfc, (channel * 2) + 1);
+		}
+	} else {
+		xhfc_selfifo(xhfc, (channel * 2) + 1);
+		if (bch && ((*rx_skb)->len >= 128))
+			recv_Bchannel(bch, MISDN_ID_ANY, false);
+	}
+	mutex_unlock(&port->lock);
+}
+
+/*
+ * IRQ work bottom half
+ */
+static void
+xhfc_bh_handler(unsigned long ul_hw)
+{
+	struct xhfc *xhfc = (struct xhfc *) ul_hw;
+	int i;
+	__u8 su_state;
+	__u8 su_irq, misc_irq;
+	__u32 fifo_irq;
+	struct dchannel *dch;
+	unsigned long flags;
+
+	/* collect XHFC irq sources */
+	spin_lock_irqsave(&xhfc->lock_irq, flags);
+	su_irq = xhfc->su_irq;
+	misc_irq = xhfc->misc_irq;
+	fifo_irq = xhfc->fifo_irq;
+	xhfc->su_irq = xhfc->misc_irq = xhfc->fifo_irq = 0;
+	spin_unlock_irqrestore(&xhfc->lock_irq, flags);
+
+	/* timer interrupt */
+	if (GET_V_TI_IRQ(misc_irq)) {
+		/* Handle tx Fifos */
+		for (i = 0; i < xhfc->channels; i++) {
+			if ((1 << (i * 2)) & (xhfc->fifo_irqmsk)) {
+				mutex_lock(&xhfc->lock);
+				xhfc_write_fifo(xhfc, i);
+				mutex_unlock(&xhfc->lock);
+			}
+		}
+
+		/* handle NT Timer */
+		for (i = 0; i < xhfc->num_ports; i++) {
+			if ((xhfc->port[i].mode & PORT_MODE_NT)
+			    && (xhfc->port[i].timers & NT_ACTIVATION_TIMER)) {
+				if ((--xhfc->port[i].nt_timer) < 0) {
+					mutex_lock(&xhfc->lock);
+					ph_state(&xhfc->port[i].dch);
+					mutex_unlock(&xhfc->lock);
+				}
+			}
+		}
+	}
+
+	/* set fifo_irq when RX data over treshold */
+	for (i = 0; i < xhfc->num_ports; i++)
+		fifo_irq |= read_xhfc(xhfc, R_FILL_BL0 + i) << (i * 8);
+
+	/* Handle rx Fifos */
+	if ((fifo_irq & xhfc->fifo_irqmsk) & FIFO_MASK_RX) {
+		for (i = 0; i < xhfc->channels; i++) {
+			if ((fifo_irq & (1 << (i * 2 + 1)))
+			    & (xhfc->fifo_irqmsk)) {
+				mutex_lock(&xhfc->lock);
+				xhfc_read_fifo(xhfc, i);
+				mutex_unlock(&xhfc->lock);
+			}
+		}
+	}
+
+	/* su interrupt */
+	if (su_irq & xhfc->su_irqmsk) {
+		for (i = 0; i < xhfc->num_ports; i++) {
+			write_xhfc(xhfc, R_SU_SEL, i);
+			su_state = read_xhfc(xhfc, A_SU_RD_STA);
+			dch = &xhfc->port[i].dch;
+			if (GET_V_SU_STA(su_state) != dch->state) {
+				dch->state = GET_V_SU_STA(su_state);
+				mutex_lock(&xhfc->lock);
+				ph_state(dch);
+				mutex_unlock(&xhfc->lock);
+			}
+		}
+	}
+}
+
+/*
+ * Interrupt handler
+ */
+irqreturn_t
+xhfc_interrupt(int intno, void *dev_id)
+{
+	struct xhfc_pi *pi = dev_id;
+	struct xhfc *xhfc = NULL;
+	__u8 i, j;
+	__u32 xhfc_irqs;
+	int sched_bh = 0;
+
+#ifdef USE_F0_COUNTER
+	__u32 f0_cnt;
+#endif
+
+	//printk(KERN_INFO "%s %s: xhfc_interrupt fired\n",
+	//		       xhfc->name, __FUNCTION__);
+
+	xhfc_irqs = 0;
+	for (i = 0; i < pi->driver_data.num_xhfcs; i++) {
+		xhfc = &pi->xhfc[i];
+		if (GET_V_GLOB_IRQ_EN(xhfc->irq_ctrl)
+		    && (read_xhfc(xhfc, R_IRQ_OVIEW)))
+			/* mark this xhfc possibly had irq */
+			xhfc_irqs |= (1 << i);
+	}
+	if (!xhfc_irqs) {
+		if (debug & DEBUG_HFC_IRQ)
+			printk(KERN_INFO
+			       "%s %s NOT M_GLOB_IRQ_EN or R_IRQ_OVIEW \n",
+			       xhfc->name, __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	xhfc_irqs = 0;
+	for (i = 0; i < pi->driver_data.num_xhfcs; i++) {
+		xhfc = &pi->xhfc[i];
+
+		//mutex_lock(&xhfc->lock_irq);
+		mutex_lock(&xhfc->transaction_lock);
+
+		xhfc->misc_irq |= read_xhfc(xhfc, R_MISC_IRQ);
+		xhfc->su_irq |= read_xhfc(xhfc, R_SU_IRQ);
+
+		/* get fifo IRQ states in bundle */
+		for (j = 0; j < 4; j++)
+			xhfc->fifo_irq |=
+			    (read_xhfc(xhfc, R_FIFO_BL0_IRQ + j) <<
+			     (j * 8));
+
+		sched_bh = (xhfc->misc_irq & xhfc->misc_irqmsk)
+		            || (xhfc->su_irq & xhfc->su_irqmsk)
+		            || (xhfc->fifo_irq & xhfc->fifo_irqmsk);
+
+		mutex_unlock(&xhfc->transaction_lock);
+		//mutex_unlock(&xhfc->lock_irq);
+
+		/* call bottom half at events
+		 *   - Timer Interrupt (or other misc_irq sources)
+		 *   - SU State change
+		 *   - Fifo FrameEnd interrupts (only at rx fifos enabled)
+		 */
+		if (sched_bh) {
+
+			/* mark this xhfc really had irq */
+			xhfc_irqs |= (1 << i);
+
+			/* queue bottom half */
+			/*if (!(xhfc->testirq))
+				tasklet_schedule(&xhfc->tasklet);*/
+
+			if (!(xhfc->testirq))
+				xhfc_bh_handler((unsigned long) xhfc);
+
+			/* count irqs */
+			xhfc->irq_cnt++;
+
+#ifdef USE_F0_COUNTER
+			/* akkumulate f0 counter diffs */
+			f0_cnt = read_xhfc(xhfc, R_F0_CNTL);
+			f0_cnt += read_xhfc(xhfc, R_F0_CNTH) << 8;
+			xhfc->f0_akku += (f0_cnt - xhfc->f0_cnt);
+			if ((f0_cnt - xhfc->f0_cnt) < 0)
+				xhfc->f0_akku += 0xFFFF;
+			xhfc->f0_cnt = f0_cnt;
+#endif
+		}
+	}
+
+	return ((xhfc_irqs) ? IRQ_HANDLED : IRQ_NONE);
+}
+
+// BRIDGE_SPI uses the module_spi_driver macro, instead of 
+// module_init/xhfc_register_pi functions
+#if BRIDGE != BRIDGE_SPI
+static int __init
+xhfc_init(void)
+{
+	int err = -ENODEV;
+
+	printk(KERN_INFO DRIVER_NAME " driver Rev. %s debug(0x%x)\n",
+	       xhfc_rev, debug);
+
+	err = xhfc_register_pi();
+	printk(KERN_INFO DRIVER_NAME ": %d interfaces installed\n",
+	       xhfc_cnt);
+
+	return err;
+}
+
+static void __exit
+xhfc_cleanup(void)
+{
+	if (debug)
+		printk(KERN_INFO DRIVER_NAME ": %s\n", __func__);
+
+	xhfc_unregister_pi();
+}
+
+module_init(xhfc_init);
+module_exit(xhfc_cleanup);
+#endif
\ No newline at end of file
diff --git a/drivers/isdn/hardware/mISDN/xhfc_su.h b/drivers/isdn/hardware/mISDN/xhfc_su.h
new file mode 100644
index 000000000..57f4a1580
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/xhfc_su.h
@@ -0,0 +1,207 @@
+/* xhfc_su.h
+ * mISDN driver for Cologne Chip' XHFC
+ *
+ * (c) 2007,2008 Copyright Cologne Chip AG
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info@colognechip.com
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _XHFC_SU_H_
+#define _XHFC_SU_H_
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/mISDNhw.h>
+#include "xhfc24sucd.h"
+
+#define DRIVER_NAME "XHFC"
+
+#ifndef CHIP_ID_2S4U
+#define CHIP_ID_2S4U	0x62
+#endif
+#ifndef CHIP_ID_4SU
+#define CHIP_ID_4SU	0x63
+#endif
+#ifndef CHIP_ID_1SU
+#define CHIP_ID_1SU	0x60
+#endif
+#ifndef CHIP_ID_2SU
+#define CHIP_ID_2SU	0x61
+#endif
+
+
+/* define bridge for chip register access */
+#define BRIDGE_UNKNOWN	0
+#define BRIDGE_PCI2PI	1 /* used at Cologne Chip AG's Evaluation Card */
+#define BRIDGE_SPI		2 /* used for Osmocom XHFC-2SU evaluation board */
+#define BRIDGE		BRIDGE_SPI
+
+#define MAX_PORT	4
+#define CHAN_PER_PORT	4	/* D, B1, B2, PCM */
+#define MAX_CHAN	MAX_PORT * CHAN_PER_PORT
+
+/* flags in _u16  port->portmode */
+#define PORT_UNUSED		0x0000
+#define PORT_MODE_NT		0x0001
+#define PORT_MODE_TE		0x0002
+#define PORT_MODE_S0		0x0004
+#define PORT_MODE_UP0		0x0008
+#define PORT_MODE_EXCH_POL	0x0010
+#define PORT_MODE_LOOP_B1	0x0020
+#define PORT_MODE_LOOP_B2	0x0040
+#define PORT_MODE_LOOP_D	0x0080
+
+/* flags in _u8 port->timers */
+#define NT_ACTIVATION_TIMER	0x0001
+
+#define PORT_MODE_LOOPS		0xE0	/* mask port mode Loop B1/B2/D */
+
+
+/* NT / TE defines */
+#define NT_T1_COUNT	250	/* number of 4ms interrupts for G2 timeout */
+#define CLK_DLY_TE	0x0e	/* CLKDEL in TE mode */
+#define CLK_DLY_NT	0x6c	/* CLKDEL in NT mode */
+#define STA_ACTIVATE	0x60	/* start activation   in A_SU_WR_STA */
+#define STA_DEACTIVATE	0x40	/* start deactivation in A_SU_WR_STA */
+#define STA_LOAD	0x10	/* load state in A_SU_WR_STA */
+#define LIF_MODE_NT	0x04	/* Line Interface NT mode */
+#define XHFC_TIMER_T3	8000	/* 8s activation timer T3 */
+#define XHFC_TIMER_T4	500	/* 500ms deactivation timer T4 */
+
+/* xhfc Layer1 physical commands */
+#define L1_ACTIVATE_TE		0x00
+#define L1_FORCE_DEACTIVATE_TE	0x01
+#define L1_ACTIVATE_NT		0x02
+#define L1_DEACTIVATE_NT	0x03
+#define L1_SET_TESTLOOP_B1		0x04
+#define L1_SET_TESTLOOP_B2		0x05
+#define L1_SET_TESTLOOP_D		0x06
+#define L1_UNSET_TESTLOOP_B1		0x07
+#define L1_UNSET_TESTLOOP_B2		0x08
+#define L1_UNSET_TESTLOOP_D		0x09
+
+
+/* xhfc Layer1 Flags (stored in xhfc_port_t->l1_flags) */
+#define HFC_L1_ACTIVATING	1
+#define HFC_L1_ACTIVATED	2
+#define HFC_L1_DEACTTIMER	4
+#define HFC_L1_ACTTIMER		8
+
+/* XHFC l1 meta states */
+#define XHFC_L1_F0		HW_RESET_IND
+#define XHFC_L1_F3		HW_DEACT_IND
+#define XHFC_L1_F7		INFO4_P8
+
+#define FIFO_MASK_TX	0x55555555
+#define FIFO_MASK_RX	0xAAAAAAAA
+
+
+/* DEBUG flags, use combined value for module parameter debug=x */
+#define DEBUG_HFC_FIFO_ERR	0x00010000
+#define DEBUG_HFC_FIFO_STAT	0x00020000
+#define DEBUG_HFC_FIFO_DATA	0x00040000
+#define DEBUG_HFC_IRQ		0x00100000
+
+#define USE_F0_COUNTER	1
+#define DEFAULT_TRANSP_BURST_SZ 128
+
+
+struct xhfc_port;
+struct xhfc_pi;
+struct xhfc;
+
+/* port struct for each S/U port */
+struct port {
+	struct xhfc * xhfc;
+	struct mutex lock;
+
+	int idx;
+	char name[20];	/* XHFC_PI0_0_0 = PI no-0 XJFC no 0, port no 0 */
+
+	struct dchannel dch;
+	struct dchannel ech;
+	struct bchannel bch[2];
+
+	__u8 dpid;	/* D-channel Protocoll ID */
+	__u16 mode;	/* NT/TE + ST/U */
+	__u8 timers;
+	__u8 initdone;
+	int nt_timer;
+	struct timer_list f7_timer;
+
+	u_long	l1_flags;
+	struct timer_list t3_timer; /* timer 3 for activation/deactivation */
+	struct timer_list t4_timer; /* timer 4 for activation/deactivation */
+
+	/* chip registers */
+	__u8 su_ctrl0;
+	__u8 su_ctrl1;
+	__u8 su_ctrl2;
+	__u8 st_ctrl3;
+};
+
+/* hardware structure */
+struct xhfc {
+	struct xhfc_pi * pi;		/* backpointer to xhfc_pi */
+	struct port *port;		/* one for each Line interface */
+	char name[15];		/* XHFC_PI0_0 = PI no 0, XHFC no 0 */
+	__u8 chipnum;		/* global chip no */
+	__u8 chipidx;		/* index in pi->xhfcs[NUM_XHFCS] */
+	__u8 param_idx;		/* used to access module param arrays */
+
+	struct mutex lock;
+	spinlock_t lock_irq;
+	struct mutex transaction_lock;
+	struct tasklet_struct tasklet;	/* interrupt bottom half */
+
+	__u8 testirq;
+
+	int num_ports;	/* number of S and U interfaces */
+	int channels;	/* 4 channels per port: B1/B2/D/E */
+	__u8 max_z;	/* fifo depth -1 */
+
+	__u32 irq_cnt;	/* count irqs */
+	__u32 f0_cnt;	/* last F0 counter value */
+	__u32 f0_akku;	/* akkumulated f0 counter deltas */
+
+	/* chip registers */
+	__u8 irq_ctrl;
+	__u8 misc_irqmsk;	/* mask of enabled interrupt sources */
+	__u8 misc_irq;		/* collect interrupt status bits */
+
+	__u8 su_irqmsk;		/* mask of line intf state change interrupts */
+	__u8 su_irq;		/* collect interrupt status bits */
+	__u8 ti_wd;		/* timer interval */
+	__u8 pcm_md0;
+	__u8 pcm_md1;
+
+	__u32 fifo_irq;		/* fifo bl irq */
+	__u32 fifo_irqmsk;	/* fifo bl irq */
+};
+
+
+/*
+ * interface prototypes exportet for PI implementation, e.g. xhfc_pci2pi
+ */
+int setup_instance(struct xhfc *hw, struct device *parent);
+int release_instance(struct xhfc *hw);
+void enable_interrupts(struct xhfc *xhfc);
+void disable_interrupts(struct xhfc *xhfc);
+irqreturn_t xhfc_interrupt(int intno, void *dev_id);
+
+#endif /* _XHFC_SU_H_ */
