diff --git a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py
index ad70e584bb..de5c24ba0e 100644
--- a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py
+++ b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py
@@ -18,5 +18,5 @@ except ImportError, e:
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
- self.eeprom_path = "/tmp/eeprom"
+ self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0053/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)
diff --git a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py
index 020faab9db..645c76b9f0 100644
--- a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py
+++ b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py
@@ -1,19 +1,23 @@
-#!/usr/bin/env python
+# sfputil.py
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
try:
- from sonic_sfp.sfputilbase import sfputilbase
-except ImportError, e:
- raise ImportError (str(e) + "- required module not found")
+ import time
+ from sonic_sfp.sfputilbase import SfpUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
-class sfputil(sfputilbase):
- """Platform specific sfputil class"""
+class SfpUtil(SfpUtilBase):
+ """Platform-specific SfpUtil class"""
- port_start = 0
- port_end = 31
- ports_in_block = 32
+ PORT_START = 0
+ PORT_END = 31
+ PORTS_IN_BLOCK = 32
- port_to_eeprom_mapping = {}
+ _port_to_eeprom_mapping = {}
port_to_i2c_mapping = {
0: 22,
1: 23,
@@ -49,12 +53,117 @@ class sfputil(sfputilbase):
31: 21
}
- _qsfp_ports = range(0, ports_in_block + 1)
+ @property
+ def port_start(self):
+ return self.PORT_START
- def __init__(self, port_num):
- # Override port_to_eeprom_mapping for class initialization
- eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'
- for x in range(self.port_start, self.port_end + 1):
+ @property
+ def port_end(self):
+ return self.PORT_END
+
+ @property
+ def qsfp_ports(self):
+ return range(0, self.PORTS_IN_BLOCK + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ def __init__(self):
+ eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
+
+ for x in range(0, self.port_end + 1):
port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x])
self.port_to_eeprom_mapping[x] = port_eeprom_path
- sfputilbase.__init__(self, port_num)
+ SfpUtilBase.__init__(self)
+
+ def get_presence(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/present")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ if reg_value == 0:
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ if reg_value == 0:
+ return False
+
+ return True
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod", "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ # LPMode is active high; set or clear the bit accordingly
+ if lpmode is True:
+ reg_value = 1
+ else:
+ reg_value = 0
+
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ return True
+
+ def reset(self, port_num):
+ QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/class/swps/port"+str(port_num)+"/reset"
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = 0
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ # Sleep 2 second to allow it to settle
+ time.sleep(2)
+
+ # Flip the value back write back to the register to take port out of reset
+ try:
+ reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = 1
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ return True
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini
new file mode 100644
index 0000000000..a8eaeb1f06
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini
@@ -0,0 +1,56 @@
+# 48x25G + 6x100G
+# name lanes alias
+Ethernet0 2 Ethernet0
+Ethernet4 1 Ethernet4
+Ethernet8 4 Ethernet8
+Ethernet12 3 Ethernet12
+Ethernet16 6 Ethernet16
+Ethernet20 5 Ethernet20
+Ethernet24 8 Ethernet24
+Ethernet28 7 Ethernet28
+Ethernet32 10 Ethernet32
+Ethernet36 9 Ethernet36
+Ethernet40 12 Ethernet40
+Ethernet44 11 Ethernet44
+Ethernet48 22 Ethernet48
+Ethernet52 21 Ethernet52
+Ethernet56 24 Ethernet56
+Ethernet60 23 Ethernet60
+Ethernet64 34 Ethernet64
+Ethernet68 33 Ethernet68
+Ethernet72 36 Ethernet72
+Ethernet76 35 Ethernet76
+Ethernet80 38 Ethernet80
+Ethernet84 37 Ethernet84
+Ethernet88 40 Ethernet88
+Ethernet92 39 Ethernet92
+Ethernet96 42 Ethernet96
+Ethernet100 41 Ethernet100
+Ethernet104 44 Ethernet104
+Ethernet108 43 Ethernet108
+Ethernet112 50 Ethernet112
+Ethernet116 49 Ethernet116
+Ethernet120 52 Ethernet120
+Ethernet124 51 Ethernet124
+Ethernet128 54 Ethernet128
+Ethernet132 53 Ethernet132
+Ethernet136 56 Ethernet136
+Ethernet140 55 Ethernet140
+Ethernet144 66 Ethernet144
+Ethernet148 65 Ethernet148
+Ethernet152 68 Ethernet152
+Ethernet156 67 Ethernet156
+Ethernet160 70 Ethernet160
+Ethernet164 69 Ethernet164
+Ethernet168 72 Ethernet168
+Ethernet172 71 Ethernet172
+Ethernet176 82 Ethernet176
+Ethernet180 81 Ethernet180
+Ethernet184 84 Ethernet184
+Ethernet188 83 Ethernet188
+Ethernet192 85,86,87,88 Ethernet192
+Ethernet196 97,98,99,100 Ethernet196
+Ethernet200 105,106,107,108 Ethernet200
+Ethernet204 101,102,103,104 Ethernet204
+Ethernet208 117,118,119,120 Ethernet208
+Ethernet212 109,110,111,112 Ethernet212
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile
new file mode 100644
index 0000000000..6f60cbd611
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile
@@ -0,0 +1,2 @@
+SAI_INIT_CONFIG_FILE=/etc/bcm/th-d7054q28b-48x10g-6x100g.config.bcm
+SAI_NUM_ECMP_MEMBERS=32
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf b/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf
new file mode 100644
index 0000000000..1db64ba02c
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf
@@ -0,0 +1,4 @@
+CONSOLE_PORT=0x3f8
+CONSOLE_DEV=0
+CONSOLE_SPEED=115200
+VAR_LOG_SIZE=1024
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml b/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml
new file mode 100644
index 0000000000..0e579ccbde
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml
@@ -0,0 +1,146 @@
+
+
+
+
+
+ OCPSCH0104001MS
+ 10.10.1.26
+ SONiC-Inventec-d7054
+ 10.10.1.25
+ 1
+ 10
+ 3
+
+
+ OCPSCH0104002MS
+ 10.10.2.26
+ SONiC-Inventec-d7054
+ 10.10.2.25
+ 1
+ 10
+ 3
+
+
+
+
+ 64536
+ SONiC-Inventec-d7054
+
+
+ 10.10.1.26
+
+
+
+
+ 10.10.2.26
+
+
+
+
+
+
+
+ 64542
+ OCPSCH0104001MS
+
+
+
+ 64543
+ OCPSCH0104002MS
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 100.0.0.9/32
+
+ 100.0.0.9/32
+
+
+
+
+
+
+
+ SONiC-Inventec-d7054
+
+
+
+
+
+ Ethernet0
+ 10.10.1.25/30
+
+
+
+ Ethernet4
+ 10.10.2.25/30
+
+
+
+
+
+
+
+
+
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104001MS
+ Ethernet24
+ SONiC-Inventec-d7054
+ Ethernet0
+
+
+ 40000
+ DeviceInterfaceLink
+ OCPSCH0104002MS
+ Ethernet24
+ SONiC-Inventec-d7054
+ Ethernet4
+
+
+
+
+ SONiC-Inventec-d7054
+ INVENTEC-D7054Q28B-S48-Q6
+
+
+
+
+
+
+ SONiC-Inventec-d7054
+
+
+ DhcpResources
+
+
+
+
+ NtpResources
+
+ 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org
+
+
+ SyslogResources
+
+
+
+
+
+
+
+
+ SONiC-Inventec-d7054
+ INVENTEC-D7054Q28B-S48-Q6
+
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py
new file mode 100644
index 0000000000..de5c24ba0e
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Inventec d7032q28b
+#
+# Platform and model specific eeprom subclass, inherits from the base class,
+# and provides the followings:
+# - the eeprom format definition
+# - specific encoder/decoder if there is special need
+#############################################################################
+
+try:
+ from sonic_eeprom import eeprom_tlvinfo
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0053/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py
new file mode 100755
index 0000000000..d236146e49
--- /dev/null
+++ b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py
@@ -0,0 +1,209 @@
+# sfputil.py
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
+
+try:
+ import time
+ from sonic_sfp.sfputilbase import SfpUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+class SfpUtil(SfpUtilBase):
+ """Platform-specific SfpUtil class"""
+
+ PORT_START = 0
+ PORT_END = 53
+ PORTS_IN_BLOCK = 54
+ QSFP_PORT_START = 48
+ QSFP_PORT_END = 53
+
+ _port_to_eeprom_mapping = {}
+ port_to_i2c_mapping = {
+ 0: 11,
+ 1: 10,
+ 2: 13,
+ 3: 12,
+ 4: 15,
+ 5: 14,
+ 6: 17,
+ 7: 16,
+ 8: 19,
+ 9: 18,
+ 10: 21,
+ 11: 20,
+ 12: 23,
+ 13: 22,
+ 14: 25,
+ 15: 24,
+ 16: 27,
+ 17: 26,
+ 18: 29,
+ 19: 28,
+ 20: 31,
+ 21: 30,
+ 22: 33,
+ 23: 32,
+ 24: 35,
+ 25: 34,
+ 26: 37,
+ 27: 36,
+ 28: 39,
+ 29: 38,
+ 30: 41,
+ 31: 40,
+ 32: 43,
+ 33: 42,
+ 34: 45,
+ 35: 44,
+ 36: 47,
+ 37: 46,
+ 38: 49,
+ 39: 48,
+ 40: 51,
+ 41: 50,
+ 42: 53,
+ 43: 52,
+ 44: 55,
+ 45: 54,
+ 46: 57,
+ 47: 56,
+ 48: 59,
+ 49: 58,
+ 50: 61,
+ 51: 60,
+ 52: 63,
+ 53: 62
+ }
+
+ @property
+ def port_start(self):
+ return self.PORT_START
+
+ @property
+ def port_end(self):
+ return self.PORT_END
+
+ @property
+ def qsfp_port_start(self):
+ return self.QSFP_PORT_START
+
+ @property
+ def qsfp_port_end(self):
+ return self.QSFP_PORT_END
+
+ @property
+ def qsfp_ports(self):
+ return range(0, self.PORTS_IN_BLOCK + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ def __init__(self):
+ eeprom_path = "/sys/bus/i2c/devices/{0}-0050/eeprom"
+
+ for x in range(0, self.port_end + 1):
+ port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x])
+ self.port_to_eeprom_mapping[x] = port_eeprom_path
+ SfpUtilBase.__init__(self)
+
+ def get_presence(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/present")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ if reg_value == 0:
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+ if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ if reg_value == 0:
+ return False
+
+ return True
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+ if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
+ print "\nError:SFP's don't support this property"
+ return False
+
+ try:
+ reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod", "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = int(reg_file.readline().rstrip())
+
+ # LPMode is active high; set or clear the bit accordingly
+ if lpmode is True:
+ reg_value = 1
+ else:
+ reg_value = 0
+
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ return True
+
+ def reset(self, port_num):
+ QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/class/swps/port"+str(port_num)+"/reset"
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+ if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
+ print "\nError:SFP's don't support this property"
+ return False
+
+ try:
+ reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = 0
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ # Sleep 2 second to allow it to settle
+ time.sleep(2)
+
+ # Flip the value back write back to the register to take port out of reset
+ try:
+ reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = 1
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ return True
diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk
index 2340177fd1..60305c292b 100644
--- a/platform/broadcom/one-image.mk
+++ b/platform/broadcom/one-image.mk
@@ -13,6 +13,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(INGRASYS_S8810_32Q_PLATFORM_MODULE) \
$(ACCTON_AS7712_32X_PLATFORM_MODULE) \
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
+ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
$(CEL_DX010_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)
diff --git a/platform/broadcom/platform-modules-inventec.mk b/platform/broadcom/platform-modules-inventec.mk
index 0d00fe1f73..f4a2e65e51 100755
--- a/platform/broadcom/platform-modules-inventec.mk
+++ b/platform/broadcom/platform-modules-inventec.mk
@@ -1,12 +1,17 @@
-# Inventec d7032q28b Platform modules
+# Inventec d7032q28b and d7054q28b Platform modules
-INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION = 1.0.0
+INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION = 1.1.0
+INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION = 1.1.0
export INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION
+export INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION
INVENTEC_D7032Q28B_PLATFORM_MODULE = platform-modules-d7032q28b_$(INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION)_amd64.deb
$(INVENTEC_D7032Q28B_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-inventec
$(INVENTEC_D7032Q28B_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
$(INVENTEC_D7032Q28B_PLATFORM_MODULE)_PLATFORM = x86_64-inventec_d7032q28b-r0
SONIC_DPKG_DEBS += $(INVENTEC_D7032Q28B_PLATFORM_MODULE)
-$(eval $(call add_extra_package,$(INVENTEC_D7032Q28B_PLATFORM_MODULE)))
+
+INVENTEC_D7054Q28B_PLATFORM_MODULE = platform-modules-d7054q28b_$(INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION)_amd64.deb
+$(INVENTEC_D7054Q28B_PLATFORM_MODULE)_PLATFORM = x86_64-inventec_d7054q28b-r0
+$(eval $(call add_extra_package,$(INVENTEC_D7032Q28B_PLATFORM_MODULE),$(INVENTEC_D7054Q28B_PLATFORM_MODULE)))
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf
deleted file mode 100644
index 29d4d50a4f..0000000000
--- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-# /etc/modules: kernel modules to load at boot time.
-#
-# This file contains the names of kernel modules that should be loaded
-# at boot time, one per line. Lines beginning with "#" are ignored.
-
-lpc_ich
-i2c-i801
-i2c-mux
-i2c-mux-pca954x
-i2c-dev
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile
index cdabd612a6..c43c477452 100755
--- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile
@@ -1,3 +1,7 @@
obj-m += inv_cpld.o inv_psoc.o
obj-m += inv_platform.o
+obj-m += inv_eeprom.o
+obj-m += swps.o
+swps-objs := inv_swps.o io_expander.o transceiver.o
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c
new file mode 100644
index 0000000000..b2dde612b6
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c
@@ -0,0 +1,181 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* Size of EEPROM in bytes */
+#define EEPROM_SIZE 256
+
+#define SLICE_BITS (6)
+#define SLICE_SIZE (1 << SLICE_BITS)
+#define SLICE_NUM (EEPROM_SIZE/SLICE_SIZE)
+
+/* Each client has this additional data */
+struct eeprom_data {
+ struct mutex update_lock;
+ u8 valid; /* bitfield, bit!=0 if slice is valid */
+ unsigned long last_updated[SLICE_NUM]; /* In jiffies, 8 slices */
+ u8 data[EEPROM_SIZE]; /* Register values */
+};
+
+
+static void inv_eeprom_update_client(struct i2c_client *client, u8 slice)
+{
+ struct eeprom_data *data = i2c_get_clientdata(client);
+ int i, j;
+ int ret;
+ int addr;
+
+
+ mutex_lock(&data->update_lock);
+
+ if (!(data->valid & (1 << slice)) ||
+ time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
+ dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
+
+ addr = slice << SLICE_BITS;
+
+ ret = i2c_smbus_write_byte_data(client, ((u8)addr >> 8) & 0xFF, (u8)addr & 0xFF);
+ /* select the eeprom address */
+ if (ret < 0) {
+ dev_err(&client->dev, "address set failed\n");
+ goto exit;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
+ goto exit;
+ }
+
+ for (i = slice << SLICE_BITS; i < (slice + 1) << SLICE_BITS; i+= SLICE_SIZE) {
+ for (j = i; j < (i+SLICE_SIZE); j++) {
+ int res;
+
+ res = i2c_smbus_read_byte(client);
+ if (res < 0) {
+ goto exit;
+ }
+
+ data->data[j] = res & 0xFF;
+ }
+ }
+
+ data->last_updated[slice] = jiffies;
+ data->valid |= (1 << slice);
+ }
+
+exit:
+ mutex_unlock(&data->update_lock);
+}
+
+static ssize_t inv_eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct eeprom_data *data = i2c_get_clientdata(client);
+ u8 slice;
+
+
+ if (off > EEPROM_SIZE) {
+ return 0;
+ }
+ if (off + count > EEPROM_SIZE) {
+ count = EEPROM_SIZE - off;
+ }
+ if (count == 0) {
+ return 0;
+ }
+
+ /* Only refresh slices which contain requested bytes */
+ for (slice = off >> SLICE_BITS; slice <= (off + count - 1) >> SLICE_BITS; slice++) {
+ inv_eeprom_update_client(client, slice);
+ }
+
+ memcpy(buf, &data->data[off], count);
+
+ return count;
+}
+
+static struct bin_attribute inv_eeprom_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO,
+ },
+ .size = EEPROM_SIZE,
+ .read = inv_eeprom_read,
+};
+
+static int inv_eeprom_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct eeprom_data *data;
+ int err;
+
+ if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ memset(data->data, 0xff, EEPROM_SIZE);
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* create the sysfs eeprom file */
+ err = sysfs_create_bin_file(&client->dev.kobj, &inv_eeprom_attr);
+ if (err) {
+ goto exit_kfree;
+ }
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int inv_eeprom_remove(struct i2c_client *client)
+{
+ sysfs_remove_bin_file(&client->dev.kobj, &inv_eeprom_attr);
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static const struct i2c_device_id inv_eeprom_id[] = {
+ { "inv_eeprom", 0 },
+ { }
+};
+
+static struct i2c_driver inv_eeprom_driver = {
+ .driver = {
+ .name = "inv_eeprom",
+ },
+ .probe = inv_eeprom_probe,
+ .remove = inv_eeprom_remove,
+ .id_table = inv_eeprom_id,
+};
+
+module_i2c_driver(inv_eeprom_driver);
+
+MODULE_AUTHOR("Inventec");
+MODULE_DESCRIPTION("Inventec D7032 Mother Board EEPROM driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c
index 71dda75b25..52f6a5691d 100644
--- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c
@@ -1,197 +1,198 @@
-#include
-//#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-//#include
-#define IO_EXPAND_BASE 64
-#define IO_EXPAND_NGPIO 16
-
-struct inv_i2c_board_info {
- int ch;
- int size;
- struct i2c_board_info *board_info;
-};
-
-#define bus_id(id) (id)
-static struct pca954x_platform_mode mux_modes_0[] = {
- {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),},
- {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),},
-};
-static struct pca954x_platform_mode mux_modes_0_0[] = {
- {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),},
- {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),},
- {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),},
- {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),},
-};
-
-static struct pca954x_platform_mode mux_modes_0_1[] = {
- {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),},
- {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),},
- {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),},
- {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),},
-};
-
-static struct pca954x_platform_mode mux_modes_0_2[] = {
- {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),},
- {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),},
- {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),},
- {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),},
-};
-
-static struct pca954x_platform_mode mux_modes_0_3[] = {
- {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),},
- {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),},
- {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),},
- {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),},
-};
-
-static struct pca954x_platform_data mux_data_0 = {
- .modes = mux_modes_0,
- .num_modes = 4,
-};
-static struct pca954x_platform_data mux_data_0_0 = {
- .modes = mux_modes_0_0,
- .num_modes = 8,
-};
-static struct pca954x_platform_data mux_data_0_1 = {
- .modes = mux_modes_0_1,
- .num_modes = 8,
-};
-static struct pca954x_platform_data mux_data_0_2 = {
- .modes = mux_modes_0_2,
- .num_modes = 8,
-};
-static struct pca954x_platform_data mux_data_0_3 = {
- .modes = mux_modes_0_3,
- .num_modes = 8,
-};
-
-static struct i2c_board_info i2c_device_info0[] __initdata = {
- {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc
- {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld
- {"pca9545", 0, 0x70, &mux_data_0, 0, 0},
-};
-
-static struct i2c_board_info i2c_device_info1[] __initdata = {
- {"pca9545", 0, 0x70, &mux_data_0, 0, 0},
-};
-
-static struct i2c_board_info i2c_device_info2[] __initdata = {
- {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0},
-};
-
-static struct i2c_board_info i2c_device_info3[] __initdata = {
- {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0},
-};
-
-static struct i2c_board_info i2c_device_info4[] __initdata = {
- {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0},
-};
-
-static struct i2c_board_info i2c_device_info5[] __initdata = {
- {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0},
-};
-
-
-static struct inv_i2c_board_info i2cdev_list[] = {
- {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0
- {1, ARRAY_SIZE(i2c_device_info1), i2c_device_info1 }, //smbus 1 or gpio11+12
-
- {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0
- {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1
- {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2
- {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-static struct i2c_gpio_platform_data i2c_gpio_platdata0 = {
- .scl_pin = 8,
- .sda_pin = 9,
-
- .udelay = 5, //5:100kHz
- .sda_is_open_drain = 0,
- .scl_is_open_drain = 0,
- .scl_is_output_only = 0
-};
-
-static struct i2c_gpio_platform_data i2c_gpio_platdata1 = {
- .scl_pin = 12,
- .sda_pin = 11,
-
- .udelay = 5, //5:100kHz
- .sda_is_open_drain = 0,
- .scl_is_open_drain = 0,
- .scl_is_output_only = 0
-};
-
-static struct platform_device device_i2c_gpio0 = {
- .name = "i2c-gpio",
- .id = 0, // adapter number
- .dev.platform_data = &i2c_gpio_platdata0,
-};
-
-static struct platform_device device_i2c_gpio1 = {
- .name = "i2c-gpio",
- .id = 1, // adapter number
- .dev.platform_data = &i2c_gpio_platdata1,
-};
-
-static int __init plat_redwood_x86_init(void)
-{
- struct i2c_adapter *adap = NULL;
- struct i2c_client *e = NULL;
- int ret = 0;
- int i,j;
-
- printk("el6661 plat_redwood_x86_init \n");
-
-#if 0 //disable for ICOS
- //use i2c-gpio
- //register i2c gpio
- //config gpio8,9 to gpio function
- outl( inl(0x500) | (1<<8 | 1<<9), 0x500);
-
- ret = platform_device_register(&device_i2c_gpio0);
- if (ret) {
- printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret);
- }
-
- outl( inl(0x500) | (1<<11 | 1<<12), 0x500);
- ret = platform_device_register(&device_i2c_gpio1);
- if (ret) {
- printk(KERN_ERR "i2c-gpio: device_i2c_gpio1 register fail %d\n", ret);
- }
-#endif
-
- for(i=0; i
+//#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+//#include
+#define IO_EXPAND_BASE 64
+#define IO_EXPAND_NGPIO 16
+
+struct inv_i2c_board_info {
+ int ch;
+ int size;
+ struct i2c_board_info *board_info;
+};
+
+#define bus_id(id) (id)
+static struct pca954x_platform_mode mux_modes_0[] = {
+ {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),},
+ {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),},
+};
+static struct pca954x_platform_mode mux_modes_0_0[] = {
+ {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),},
+ {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),},
+ {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),},
+ {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_1[] = {
+ {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),},
+ {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),},
+ {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),},
+ {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_2[] = {
+ {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),},
+ {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),},
+ {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),},
+ {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_3[] = {
+ {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),},
+ {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),},
+ {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),},
+ {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),},
+};
+
+static struct pca954x_platform_data mux_data_0 = {
+ .modes = mux_modes_0,
+ .num_modes = 4,
+};
+static struct pca954x_platform_data mux_data_0_0 = {
+ .modes = mux_modes_0_0,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_1 = {
+ .modes = mux_modes_0_1,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_2 = {
+ .modes = mux_modes_0_2,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_3 = {
+ .modes = mux_modes_0_3,
+ .num_modes = 8,
+};
+
+static struct i2c_board_info i2c_device_info0[] __initdata = {
+ {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc
+ {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld
+ {"pca9545", 0, 0x70, &mux_data_0, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info1[] __initdata = {
+ {"pca9545", 0, 0x70, &mux_data_0, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info2[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info3[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info4[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info5[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0},
+};
+
+
+static struct inv_i2c_board_info i2cdev_list[] = {
+ {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0
+ {1, ARRAY_SIZE(i2c_device_info1), i2c_device_info1 }, //smbus 1 or gpio11+12
+
+ {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0
+ {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1
+ {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2
+ {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+static struct i2c_gpio_platform_data i2c_gpio_platdata0 = {
+ .scl_pin = 8,
+ .sda_pin = 9,
+
+ .udelay = 5, //5:100kHz
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+ .scl_is_output_only = 0
+};
+
+static struct i2c_gpio_platform_data i2c_gpio_platdata1 = {
+ .scl_pin = 12,
+ .sda_pin = 11,
+
+ .udelay = 5, //5:100kHz
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+ .scl_is_output_only = 0
+};
+
+static struct platform_device device_i2c_gpio0 = {
+ .name = "i2c-gpio",
+ .id = 0, // adapter number
+ .dev.platform_data = &i2c_gpio_platdata0,
+};
+
+static struct platform_device device_i2c_gpio1 = {
+ .name = "i2c-gpio",
+ .id = 1, // adapter number
+ .dev.platform_data = &i2c_gpio_platdata1,
+};
+
+static int __init plat_redwood_x86_init(void)
+{
+ struct i2c_adapter *adap = NULL;
+ struct i2c_client *e = NULL;
+ int ret = 0;
+ int i,j;
+
+ printk("el6661 plat_redwood_x86_init \n");
+
+#if 0 //disable for ICOS
+ //use i2c-gpio
+ //register i2c gpio
+ //config gpio8,9 to gpio function
+ outl( inl(0x500) | (1<<8 | 1<<9), 0x500);
+
+ ret = platform_device_register(&device_i2c_gpio0);
+ if (ret) {
+ printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret);
+ }
+
+ outl( inl(0x500) | (1<<11 | 1<<12), 0x500);
+ ret = platform_device_register(&device_i2c_gpio1);
+ if (ret) {
+ printk(KERN_ERR "i2c-gpio: device_i2c_gpio1 register fail %d\n", ret);
+ }
+#endif
+
+ for(i=0; i
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "inv_swps.h"
+
+static int port_major;
+static int ioexp_total;
+static int port_total;
+static struct class *swp_class_p = NULL;
+static struct inv_platform_s *platform_p = NULL;
+static struct inv_ioexp_layout_s *ioexp_layout = NULL;
+static struct inv_port_layout_s *port_layout = NULL;
+
+static int
+__swp_match(struct device *dev,
+#ifdef SWPS_KERN_VER_AF_3_10
+
+ const void *data){
+#else
+ void *data){
+#endif
+
+ char *name = (char *)data;
+ if (strcmp(dev_name(dev), name) == 0)
+ return 1;
+ return 0;
+}
+
+
+struct device *
+get_swpdev_by_name(char *name){
+ struct device *dev = class_find_device(swp_class_p,
+ NULL,
+ name,
+ (const void *)__swp_match);
+ return dev;
+}
+
+
+static int
+sscanf_2_int(const char *buf) {
+
+ int result = -EBFONT;
+ char *hex_tag = "0x";
+
+ if (strcspn(buf, hex_tag) == 0) {
+ if (sscanf(buf,"%x",&result)) {
+ return result;
+ }
+ } else {
+ if (sscanf(buf,"%d",&result)) {
+ return result;
+ }
+ if(sscanf(buf,"-%d",&result)) {
+ return -result;
+ }
+ if (sscanf(buf,"%x",&result)) {
+ return result;
+ }
+ }
+ return -EBFONT;
+}
+
+
+static int
+sscanf_2_binary(const char *buf) {
+
+ int result = sscanf_2_int(buf);
+
+ if (result < 0){
+ return -EBFONT;
+ }
+ switch (result) {
+ case 0:
+ case 1:
+ return result;
+ default:
+ break;
+ }
+ return -EBFONT;
+}
+
+/* ========== Show functions: For I/O Expander attribute ==========
+ */
+static ssize_t
+_show_ioexp_binary_attr(struct transvr_obj_s *tobj_p,
+ int (*get_func)(struct ioexp_obj_s *ioexp_p, int voffset),
+ char *buf_p) {
+ size_t len;
+ struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ SWPS_ERR(" %s: data corruption! :%s\n", __func__, tobj_p->swp_name);
+ return -ENODATA;
+ }
+ mutex_lock(&ioexp_p->lock);
+ len = snprintf(buf_p, 8, "%d\n", get_func(ioexp_p, tobj_p->ioexp_virt_offset));
+ mutex_unlock(&ioexp_p->lock);
+ return len;
+}
+
+
+static ssize_t
+show_attr_present(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_present,
+ buf_p);
+}
+
+static ssize_t
+show_attr_reset(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_reset,
+ buf_p);
+}
+
+static ssize_t
+show_attr_lpmod(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_lpmod,
+ buf_p);
+}
+
+
+static ssize_t
+show_attr_modsel(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_modsel,
+ buf_p);
+}
+
+/* ========== Store functions: For I/O Expander (R/W) attribute ==========
+ */
+static ssize_t
+_store_ioexp_binary_attr(struct transvr_obj_s *tobj_p,
+ int (*set_func)(struct ioexp_obj_s *ioexp_p,
+ int virt_offset, int input_val),
+ const char *buf_p,
+ size_t count) {
+
+ int input, err;
+ struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ SWPS_ERR("%s: data corruption! :%s\n",
+ __func__, tobj_p->swp_name);
+ return -ENODATA;
+ }
+ input = sscanf_2_binary(buf_p);
+ if (input < 0) {
+ return -EBFONT;
+ }
+ mutex_lock(&ioexp_p->lock);
+ err = set_func(ioexp_p, tobj_p->ioexp_virt_offset, input);
+ mutex_unlock(&ioexp_p->lock);
+ if (err < 0){
+ return err;
+ }
+ return count;
+}
+
+static ssize_t
+store_attr_reset(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_reset,
+ buf_p,
+ count);
+}
+
+
+static ssize_t
+store_attr_lpmod(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_lpmod,
+ buf_p,
+ count);
+}
+
+
+static ssize_t
+store_attr_modsel(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_modsel,
+ buf_p,
+ count);
+}
+
+/* ========== IO Expander attribute: from expander ==========
+ */
+static DEVICE_ATTR(present, S_IRUGO, show_attr_present, NULL);
+static DEVICE_ATTR(reset, S_IRUGO|S_IWUSR, show_attr_reset, store_attr_reset);
+static DEVICE_ATTR(lpmod, S_IRUGO|S_IWUSR, show_attr_lpmod, store_attr_lpmod);
+static DEVICE_ATTR(modsel, S_IRUGO|S_IWUSR, show_attr_modsel, store_attr_modsel);
+
+/* ========== Functions for module handling ==========
+ */
+static void
+clean_port_obj(void){
+
+ dev_t dev_num;
+ char dev_name[32];
+ struct device *device_p;
+ struct transvr_obj_s *transvr_obj_p;
+ int minor_curr, port_id;
+
+ for (minor_curr=0; minor_curri2c_client_p);
+ kfree(transvr_obj_p);
+ }
+ dev_num = MKDEV(port_major, minor_curr);
+ device_unregister(device_p);
+ device_destroy(swp_class_p, dev_num);
+ }
+ SWPS_DEBUG("%s: done.\n", __func__);
+}
+
+
+static int
+get_platform_type(void){
+
+ char log_msg[64] = "ERROR";
+
+ platform_p = kzalloc(sizeof(struct inv_platform_s), GFP_KERNEL);
+ if (!platform_p){
+ snprintf(log_msg, sizeof(log_msg), "kzalloc fail");
+ goto err_get_platform_type_1;
+ }
+ platform_p->id = PLATFORM_SETTINGS;
+ memset(platform_p->name, 0, sizeof(platform_p->name));
+ snprintf(platform_p->name, (sizeof(platform_p->name) - 1),
+ "%s", platform_map.name);
+ snprintf(log_msg, sizeof(log_msg),
+ "User setup platform: %d (%s)",
+ platform_p->id, platform_p->name);
+ SWPS_DEBUG("%s: %s, :%d\n", __func__, log_msg, PLATFORM_SETTINGS);
+ return 0;
+
+err_get_platform_type_1:
+ SWPS_ERR("%s: %s :%d\n", __func__, log_msg, PLATFORM_SETTINGS);
+ return -1;
+}
+
+
+static int
+get_layout_info(void){
+
+ ioexp_layout = redwood_ioexp_layout;
+ port_layout = redwood_port_layout;
+ ioexp_total = ARRAY_SIZE(redwood_ioexp_layout);
+ port_total = ARRAY_SIZE(redwood_port_layout);
+
+ SWPS_INFO("Start to initial platform: %d (%s)\n",
+ platform_p->id, platform_p->name);
+ return 0;
+}
+
+/* ========== Functions for register something ==========
+ */
+
+static int
+register_ioexp_attr_qsfp_1(struct device *device_p){
+ /* Support machine type:
+ * - QSFP : Magnolia, Redwood, Hudson32i
+ * - QSFP+ : Magnolia, Redwood, Hudson32i
+ * - QSFP28: Redwood
+ */
+ char *err_attr = NULL;
+
+ if (device_create_file(device_p, &dev_attr_present) < 0) {
+ err_attr = "dev_attr_present";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_reset) < 0) {
+ err_attr = "dev_attr_reset";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_lpmod) < 0) {
+ err_attr = "dev_attr_lpmod";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_modsel) < 0) {
+ err_attr = "dev_attr_modsel";
+ goto err_ioexp_qsfp1_attr;
+ }
+ return 0;
+
+err_ioexp_qsfp1_attr:
+ SWPS_ERR("Add device attribute:%s failure! \n",err_attr);
+ return -1;
+}
+
+static int
+register_ioexp_attr(struct device *device_p,
+ struct transvr_obj_s *transvr_obj){
+
+ char *err_msg = "ERR";
+
+ switch (transvr_obj->ioexp_obj_p->ioexp_type){
+ case IOEXP_TYPE_REDWOOD_P01P08:
+ case IOEXP_TYPE_REDWOOD_P09P16:
+ if (register_ioexp_attr_qsfp_1(device_p) < 0){
+ err_msg = "register_ioexp_attr_qsfp_1 fail";
+ goto err_reg_ioexp_attr;
+ }
+ break;
+
+ default:
+ err_msg = "Unknow type";
+ goto err_reg_ioexp_attr;
+ }
+ return 0;
+
+err_reg_ioexp_attr:
+ SWPS_ERR("%s: %s :%d \n",
+ __func__, err_msg, transvr_obj->ioexp_obj_p->ioexp_type);
+ return -1;
+}
+
+
+static int
+register_port_device(char *dev_name,
+ dev_t dev_num,
+ struct transvr_obj_s *transvr_obj){
+
+ struct device *device_p = NULL;
+ device_p = device_create(swp_class_p, /* struct class *cls */
+ NULL, /* struct device *parent */
+ dev_num, /* dev_t devt */
+ transvr_obj, /* void *private_data */
+ dev_name); /* const char *fmt */
+ if (IS_ERR(device_p)){
+ goto err_regswp_create_dev;
+ }
+ if (register_ioexp_attr(device_p, transvr_obj) < 0){
+ goto err_regswp_reg_attr;
+ }
+ return 0;
+
+err_regswp_reg_attr:
+ device_unregister(device_p);
+ device_destroy(swp_class_p, dev_num);
+err_regswp_create_dev:
+ SWPS_ERR("%s fail! :%s\n", __func__, dev_name);
+ return -1;
+}
+
+
+static int
+register_swp_module(void){
+
+ dev_t port_devt = 0;
+ int dev_total = port_total + 1; /* char_dev for module control */
+
+ if (alloc_chrdev_region(&port_devt, 0, dev_total, SWP_CLS_NAME) < 0){
+ SWPS_WARN("Allocate PORT MAJOR failure! \n");
+ goto err_register_swp_module_3;
+ }
+ port_major = MAJOR(port_devt);
+
+ /* Create class object */
+ swp_class_p = class_create(THIS_MODULE, SWP_CLS_NAME);
+ if (IS_ERR(swp_class_p)) {
+ SWPS_ERR("Create class failure! \n");
+ goto err_register_swp_module_3;
+ }
+ return 0;
+
+err_register_swp_module_3:
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+ return -1;
+}
+
+
+/* ========== Module initial relate ==========
+ */
+static int
+create_ioexp_objs(void) {
+
+ int i, run_mod;
+
+ /* Clean IOEXP object */
+ clean_ioexp_objs();
+ /* Get running mode */
+ run_mod = IOEXP_MODE_DIRECT;
+ /* Create IOEXP object */
+ for(i=0; i devlen_max) {
+ snprintf(err_msg, sizeof(err_msg),
+ "SWP_DEV_PORT too long!");
+ goto err_initport_create_tranobj;
+ }
+ memset(dev_name, 0, sizeof(dev_name));
+ snprintf(dev_name, devlen_max, "%s%d", SWP_DEV_PORT, port_id);
+ /* Create transceiver object */
+ ioexp_obj_p = get_ioexp_obj(ioexp_id);
+ if (!ioexp_obj_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "IOEXP object:%d not exist", ioexp_id);
+ goto err_initport_create_tranobj;
+ }
+ transvr_obj_p = create_transvr_obj(dev_name, chan_id, ioexp_obj_p,
+ ioexp_virt_offset, transvr_type,
+ chipset_type, run_mod);
+ if (!transvr_obj_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "Create transceiver object fail :%s", dev_name);
+ goto err_initport_create_tranobj;
+ }
+ /* Setup Lane_ID mapping */
+ i = ARRAY_SIZE(port_layout[minor_curr].lane_id);
+ j = ARRAY_SIZE(transvr_obj_p->lane_id);
+ if (i != j) {
+ snprintf(err_msg, sizeof(err_msg),
+ "Lane_id size inconsistent %d/%d", i, j);
+ goto err_initport_reg_device;
+ }
+ memcpy(transvr_obj_p->lane_id, port_layout[minor_curr].lane_id, i*sizeof(int));
+ /* Create and register device object */
+ if (register_port_device(dev_name, MKDEV(port_major, minor_curr), transvr_obj_p) < 0){
+ snprintf(err_msg, sizeof(err_msg),
+ "register_port_device fail");
+ goto err_initport_reg_device;
+ }
+ /* Setup device_ptr of transvr_obj */
+ dev_p = get_swpdev_by_name(dev_name);
+ if (!dev_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "get_swpdev_by_name fail");
+ goto err_initport_reg_device;
+ }
+ transvr_obj_p->transvr_dev_p = dev_p;
+ /* Success */
+ ok_count++;
+ }
+ SWPS_INFO("%s: initialed %d port-dev",__func__, ok_count);
+ return 0;
+
+err_initport_reg_device:
+ kfree(transvr_obj_p);
+err_initport_create_tranobj:
+ clean_port_obj();
+ SWPS_ERR("%s: %s", __func__, err_msg);
+ SWPS_ERR("Dump: :%d :%d :%d :%d :%d :%d\n",
+ port_id, chan_id, ioexp_id, ioexp_virt_offset, transvr_type, run_mod);
+ return -1;
+}
+
+static int __init
+swp_module_init(void){
+
+ if (get_platform_type() < 0){
+ goto err_init_out;
+ }
+ if (get_layout_info() < 0){
+ goto err_init_out;
+ }
+ if (register_swp_module() < 0){
+ goto err_init_out;
+ }
+ if (create_ioexp_objs() < 0){
+ goto err_init_ioexp;
+ }
+ if (create_port_objs() < 0){
+ goto err_init_portobj;
+ }
+ if (init_ioexp_objs() < 0){
+ goto err_init_portobj;
+ }
+ SWPS_INFO("Inventec switch-port module V.%s initial success.\n", SWP_VERSION);
+ return 0;
+
+
+err_init_portobj:
+ clean_ioexp_objs();
+err_init_ioexp:
+ class_unregister(swp_class_p);
+ class_destroy(swp_class_p);
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+err_init_out:
+ SWPS_ERR("Inventec switch-port module V.%s initial failure.\n", SWP_VERSION);
+ return -1;
+}
+
+
+static void __exit
+swp_module_exit(void){
+ clean_port_obj();
+ clean_ioexp_objs();
+ class_unregister(swp_class_p);
+ class_destroy(swp_class_p);
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+ SWPS_INFO("Remove Inventec switch-port module success.\n");
+}
+
+
+/* Module information */
+MODULE_AUTHOR(SWP_AUTHOR);
+MODULE_DESCRIPTION(SWP_DESC);
+MODULE_VERSION(SWP_VERSION);
+MODULE_LICENSE(SWP_LICENSE);
+
+module_init(swp_module_init);
+module_exit(swp_module_exit);
+
+
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h
new file mode 100644
index 0000000000..b186c22023
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h
@@ -0,0 +1,131 @@
+#ifndef INV_SWPS_H
+#define INV_SWPS_H
+
+#include "transceiver.h"
+#include "io_expander.h"
+
+/* Module settings */
+#define SWP_CLS_NAME "swps"
+#define SWP_DEV_PORT "port"
+#define SWP_AUTOCONFIG_ENABLE (1)
+
+/* Module information */
+#define SWP_AUTHOR "Neil "
+#define SWP_DESC "Inventec port and transceiver driver"
+#define SWP_VERSION "4.2.3"
+#define SWP_LICENSE "GPL"
+
+/* Module status define */
+#define SWP_STATE_NORMAL (0)
+#define SWP_STATE_I2C_DIE (-91)
+
+/* [Note]:
+ * Functions and mechanism for auto-detect platform type is ready,
+ * But HW and BIOS not ready! We need to wait them.
+ * So, please do not use PLATFORM_TYPE_AUTO until they are ready.
+ * (2016.06.13)
+ */
+#define PLATFORM_TYPE_REDWOOD (121)
+/* Current running platfrom */
+#define PLATFORM_SETTINGS PLATFORM_TYPE_REDWOOD
+
+/* Define platform flag and kernel version */
+#if (PLATFORM_SETTINGS == PLATFORM_TYPE_REDWOOD)
+ #define SWPS_KERN_VER_BF_3_8 (1)
+#endif
+
+struct inv_platform_s {
+ int id;
+ char name[64];
+};
+
+struct inv_ioexp_layout_s {
+ int ioexp_id;
+ int ioexp_type;
+ struct ioexp_addr_s addr[4];
+};
+
+struct inv_port_layout_s {
+ int port_id;
+ int chan_id;
+ int ioexp_id;
+ int ioexp_offset;
+ int transvr_type;
+ int chipset_type;
+ int lane_id[8];
+};
+
+/* ==========================================
+ * Inventec Platform Settings
+ * ==========================================
+ */
+struct inv_platform_s platform_map = {PLATFORM_TYPE_REDWOOD, "D7032Q28B" };
+
+/* ==========================================
+ * Redwood Layout configuration
+ * ==========================================
+ */
+struct inv_ioexp_layout_s redwood_ioexp_layout[] = {
+ /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */
+ {0, IOEXP_TYPE_REDWOOD_P01P08, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */
+ {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */
+ {0, 0x25, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */
+ },
+ {1, IOEXP_TYPE_REDWOOD_P09P16, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */
+ {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */
+ {0, 0x25, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */
+ },
+ {2, IOEXP_TYPE_REDWOOD_P01P08, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */
+ {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */
+ {0, 0x24, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */
+ },
+ {3, IOEXP_TYPE_REDWOOD_P09P16, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */
+ {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */
+ {0, 0x24, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */
+ },
+};
+
+struct inv_port_layout_s redwood_port_layout[] = {
+ /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */
+ { 0, 22, 0, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 1, 2, 3, 4} },
+ { 1, 23, 0, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 5, 6, 7, 8} },
+ { 2, 24, 0, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 9, 10, 11, 12} },
+ { 3, 25, 0, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 13, 14, 15, 16} },
+ { 4, 26, 0, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 17, 18, 19, 20} },
+ { 5, 27, 0, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 21, 22, 23, 24} },
+ { 6, 28, 0, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 25, 26, 27, 28} },
+ { 7, 29, 0, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 29, 30, 31, 32} },
+ { 8, 30, 1, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 33, 34, 35, 36} },
+ { 9, 31, 1, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 37, 38, 39, 40} },
+ {10, 32, 1, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 41, 42, 43, 44} },
+ {11, 33, 1, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 45, 46, 47, 48} },
+ {12, 34, 1, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 49, 50, 51, 52} },
+ {13, 35, 1, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 53, 54, 55, 56} },
+ {14, 36, 1, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 57, 58, 59, 60} },
+ {15, 37, 1, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 61, 62, 63, 64} },
+ {16, 6, 2, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 65, 66, 67, 68} },
+ {17, 7, 2, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 69, 70, 71, 72} },
+ {18, 8, 2, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 73, 74, 75, 76} },
+ {19, 9, 2, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 77, 78, 79, 80} },
+ {20, 10, 2, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 81, 82, 83, 84} },
+ {21, 11, 2, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 85, 86, 87, 88} },
+ {22, 12, 2, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 89, 90, 91, 92} },
+ {23, 13, 2, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 93, 94, 95, 96} },
+ {24, 14, 3, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 97, 98, 99,100} },
+ {25, 15, 3, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {101,102,103,104} },
+ {26, 16, 3, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {105,106,107,108} },
+ {27, 17, 3, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {109,110,111,112} },
+ {28, 18, 3, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {113,114,115,116} },
+ {29, 19, 3, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {117,118,119,120} },
+ {30, 20, 3, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {121,122,123,124} },
+ {31, 21, 3, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {125,126,127,128} },
+};
+
+#endif /* INV_SWPS_H */
+
+
+
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c
new file mode 100644
index 0000000000..7c9f8a66ae
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c
@@ -0,0 +1,887 @@
+#include
+#include
+#include
+#include "io_expander.h"
+
+static struct ioexp_obj_s *ioexp_head_p = NULL;
+static struct ioexp_obj_s *ioexp_tail_p = NULL;
+
+struct ioexp_map_s ioexp_map_redwood_p01p08_p17p24 = {
+
+ .chip_amount = 3,
+ .data_width = 2,
+
+ .map_present = { {2, 0, 0}, /* map_present[0] = MOD_ABS_PORT(X) */
+ {2, 0, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */
+ {2, 0, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */
+ {2, 0, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */
+ {2, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */
+ {2, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */
+ {2, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */
+ {2, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */
+ },
+ .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP28_N_P(X) */
+ {0, 0, 1}, /* map_reset[1] = QRESET_QSFP28_N_P(X+1) */
+ {0, 0, 2}, /* map_reset[2] = QRESET_QSFP28_N_P(X+2) */
+ {0, 0, 3}, /* map_reset[3] = QRESET_QSFP28_N_P(X+3) */
+ {1, 0, 0}, /* map_reset[4] = QRESET_QSFP28_N_P(X+4) */
+ {1, 0, 1}, /* map_reset[5] = QRESET_QSFP28_N_P(X+5) */
+ {1, 0, 2}, /* map_reset[6] = QRESET_QSFP28_N_P(X+6) */
+ {1, 0, 3}, /* map_reset[7] = QRESET_QSFP28_N_P(X+7) */
+ },
+ .map_lpmod = { {0, 0, 4}, /* map_lpmod[0] = LPMODE_QSFP28_P(X) */
+ {0, 0, 5}, /* map_lpmod[1] = LPMODE_QSFP28_P(X+1) */
+ {0, 0, 6}, /* map_lpmod[2] = LPMODE_QSFP28_P(X+2) */
+ {0, 0, 7}, /* map_lpmod[3] = LPMODE_QSFP28_P(X+3) */
+ {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP28_P(X+4) */
+ {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP28_P(X+5) */
+ {1, 0, 6}, /* map_lpmod[6] = LPMODE_QSFP28_P(X+6) */
+ {1, 0, 7}, /* map_lpmod[7] = LPMODE_QSFP28_P(X+7) */
+ },
+ .map_modsel = { {0, 1, 4}, /* map_modsel[0] = MODSEL_QSFP28_N_P(X) */
+ {0, 1, 5}, /* map_modsel[1] = MODSEL_QSFP28_N_P(X+1) */
+ {0, 1, 6}, /* map_modsel[2] = MODSEL_QSFP28_N_P(X+2) */
+ {0, 1, 7}, /* map_modsel[3] = MODSEL_QSFP28_N_P(X+3) */
+ {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP28_N_P(X+4) */
+ {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP28_N_P(X+5) */
+ {1, 1, 6}, /* map_modsel[6] = MODSEL_QSFP28_N_P(X+6) */
+ {1, 1, 7}, /* map_modsel[7] = MODSEL_QSFP28_N_P(X+7) */
+ },
+};
+
+
+struct ioexp_map_s ioexp_map_redwood_p09p16_p25p32 = {
+
+ .chip_amount = 3,
+ .data_width = 2,
+
+ .map_present = { {2, 1, 0}, /* map_present[0] = MOD_ABS_PORT(X) */
+ {2, 1, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */
+ {2, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */
+ {2, 1, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */
+ {2, 1, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */
+ {2, 1, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */
+ {2, 1, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */
+ {2, 1, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */
+ },
+ .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP28_N_P(X) */
+ {0, 0, 1}, /* map_reset[1] = QRESET_QSFP28_N_P(X+1) */
+ {0, 0, 2}, /* map_reset[2] = QRESET_QSFP28_N_P(X+2) */
+ {0, 0, 3}, /* map_reset[3] = QRESET_QSFP28_N_P(X+3) */
+ {1, 0, 0}, /* map_reset[4] = QRESET_QSFP28_N_P(X+4) */
+ {1, 0, 1}, /* map_reset[5] = QRESET_QSFP28_N_P(X+5) */
+ {1, 0, 2}, /* map_reset[6] = QRESET_QSFP28_N_P(X+6) */
+ {1, 0, 3}, /* map_reset[7] = QRESET_QSFP28_N_P(X+7) */
+ },
+ .map_lpmod = { {0, 0, 4}, /* map_lpmod[0] = LPMODE_QSFP28_P(X) */
+ {0, 0, 5}, /* map_lpmod[1] = LPMODE_QSFP28_P(X+1) */
+ {0, 0, 6}, /* map_lpmod[2] = LPMODE_QSFP28_P(X+2) */
+ {0, 0, 7}, /* map_lpmod[3] = LPMODE_QSFP28_P(X+3) */
+ {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP28_P(X+4) */
+ {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP28_P(X+5) */
+ {1, 0, 6}, /* map_lpmod[6] = LPMODE_QSFP28_P(X+6) */
+ {1, 0, 7}, /* map_lpmod[7] = LPMODE_QSFP28_P(X+7) */
+ },
+ .map_modsel = { {0, 1, 4}, /* map_modsel[0] = MODSEL_QSFP28_N_P(X) */
+ {0, 1, 5}, /* map_modsel[1] = MODSEL_QSFP28_N_P(X+1) */
+ {0, 1, 6}, /* map_modsel[2] = MODSEL_QSFP28_N_P(X+2) */
+ {0, 1, 7}, /* map_modsel[3] = MODSEL_QSFP28_N_P(X+3) */
+ {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP28_N_P(X+4) */
+ {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP28_N_P(X+5) */
+ {1, 1, 6}, /* map_modsel[6] = MODSEL_QSFP28_N_P(X+6) */
+ {1, 1, 7}, /* map_modsel[7] = MODSEL_QSFP28_N_P(X+7) */
+ },
+};
+
+/* ========== Private functions ==========
+ */
+int check_channel_tier_1(void);
+
+struct i2c_client *
+_get_i2c_client(struct ioexp_obj_s *self,
+ int chip_id){
+
+ struct ioexp_i2c_s *i2c_curr_p = self->i2c_head_p;
+
+ if (!(i2c_curr_p)){
+ SWPS_ERR("%s: i2c_curr_p is NULL\n", __func__);
+ return NULL;
+ }
+ while (i2c_curr_p){
+ if ((i2c_curr_p->chip_id) == chip_id){
+ return i2c_curr_p->i2c_client_p;
+ }
+ i2c_curr_p = i2c_curr_p->next;
+ }
+ SWPS_ERR("%s: not exist! :%d\n", __func__, chip_id);
+ return NULL;
+}
+
+
+static int
+_common_ioexp_update_one(struct ioexp_obj_s *self,
+ struct ioexp_addr_s *ioexp_addr,
+ int chip_id,
+ int data_width,
+ int show_err,
+ char *caller_name) {
+ int buf = 0;
+ int err = 0;
+ int data_id = 0;
+ int r_offset = 0;
+
+ for(data_id=0; data_idread_offset[data_id];
+ buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), r_offset);
+ /* Check error */
+ if (buf < 0) {
+ err = 1;
+ if (show_err) {
+ SWPS_INFO("IOEXP-%d read fail! :%d \n", self->ioexp_id, buf);
+ SWPS_INFO("Dump: :%d :0x%02x :%d, :%s\n",
+ ioexp_addr->chan_id, ioexp_addr->chip_addr,
+ ioexp_addr->read_offset[data_id], caller_name);
+ }
+ continue;
+ }
+ /* Update IOEXP object */
+ self->chip_data[chip_id].data[data_id] = (uint8_t)buf;
+ }
+ if (err) {
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+
+static int
+common_ioexp_update_all(struct ioexp_obj_s *self,
+ int show_err,
+ char *caller_name){
+
+ int err = 0;
+ int chip_id = 0;
+ int chip_amount = self->ioexp_map_p->chip_amount;
+
+ for (chip_id=0; chip_idioexp_map_p->map_addr[chip_id]),
+ chip_id,
+ self->ioexp_map_p->data_width,
+ show_err,
+ caller_name) < 0) {
+ err = 1;
+ }
+ }
+ if (err) {
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+static int
+_common_get_bit(struct ioexp_obj_s *self,
+ struct ioexp_bitmap_s *bitmap_obj_p,
+ char *func_mane){
+ uint8_t buf;
+ int err_code;
+
+ /* Get address */
+ err_code = self->fsm_4_direct(self);
+ if (err_code < 0){
+ return err_code;
+ }
+
+ if (!bitmap_obj_p){
+ SWPS_ERR("Layout config incorrect! :%d :%s\n",
+ self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADCONF;
+ }
+ /* Get data form cache */
+ buf = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset];
+ return (int)(buf >> bitmap_obj_p->bit_shift & 0x01);
+}
+
+
+static int
+_common_set_bit(struct ioexp_obj_s *self,
+ struct ioexp_bitmap_s *bitmap_obj_p,
+ int input_val,
+ char *func_mane){
+ int err_code, target_offset;
+ uint8_t origin_byte;
+ uint8_t modify_byte;
+
+ /* Get address */
+ err_code = self->fsm_4_direct(self);
+ if (err_code < 0){
+ return err_code;
+ }
+ if (!bitmap_obj_p){
+ SWPS_ERR("Layout config incorrect! :%d :%s\n",
+ self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADCONF;
+ }
+ /* Prepare write date */
+ origin_byte = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset];
+ switch (input_val) {
+ case 0:
+ modify_byte = origin_byte;
+ SWP_BIT_CLEAR(modify_byte, bitmap_obj_p->bit_shift);
+ break;
+ case 1:
+ modify_byte = origin_byte;
+ SWP_BIT_SET(modify_byte, bitmap_obj_p->bit_shift);
+ break;
+ default:
+ SWPS_ERR("Input value incorrect! :%d :%d :%s\n",
+ input_val, self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADINPUT;
+ }
+ /* Setup i2c client */
+ target_offset = self->ioexp_map_p->map_addr[bitmap_obj_p->chip_id].write_offset[bitmap_obj_p->ioexp_voffset];
+ /* Write byte to chip via I2C */
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, bitmap_obj_p->chip_id),
+ target_offset,
+ modify_byte);
+ /* Update or bollback object */
+ if (err_code < 0){
+ self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = origin_byte;
+ SWPS_ERR("I2C write fail! :%d :%d :%s :%d\n",
+ input_val, self->ioexp_id, func_mane, err_code);
+ return err_code;
+ }
+ self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = modify_byte;
+ return 0;
+}
+
+
+/* ========== Object public functions ==========
+ */
+int
+common_get_present(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ int UNPLUG = 1;
+ int retval = ERR_IOEXP_UNEXCPT;
+
+ retval = _common_get_bit(self,
+ &(self->ioexp_map_p->map_present[virt_offset]),
+ "common_get_present");
+ if (retval < 0) {
+ /* [Note]
+ * => Transceiver object does not need to handle IOEXP layer issues.
+ */
+ return UNPLUG;
+ }
+ return retval;
+}
+
+
+int
+common_get_reset(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_reset[virt_offset]),
+ "common_get_reset");
+}
+
+
+int
+common_get_lpmod(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_lpmod[virt_offset]),
+ "common_get_lpmod");
+}
+
+
+int
+common_get_modsel(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_modsel[virt_offset]),
+ "common_get_modsel");
+}
+
+int
+common_set_reset(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_reset[virt_offset]),
+ input_val,
+ "common_set_reset");
+}
+
+
+int
+common_set_lpmod(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_lpmod[virt_offset]),
+ input_val,
+ "common_set_lpmod");
+}
+
+
+int
+common_set_modsel(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_modsel[virt_offset]),
+ input_val,
+ "common_set_modsel");
+}
+
+int
+ioexp_get_not_support(struct ioexp_obj_s *self,
+ int virt_offset){
+ return ERR_IOEXP_NOTSUPPORT;
+}
+
+
+int
+ioexp_set_not_support(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+ return ERR_IOEXP_NOTSUPPORT;
+}
+
+/* ========== Initial functions for IO Expander ==========
+ */
+int
+common_ioexp_init(struct ioexp_obj_s *self) {
+
+ int chip_id, offset, err_code;
+ struct ioexp_addr_s *addr_p;
+
+ if (self->mode == IOEXP_MODE_DIRECT) { ///important
+ goto update_common_ioexp_init;
+ }
+ /* Setup default value to each physical IO Expander */
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ /* Get address mapping */
+ addr_p = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!addr_p){
+ SWPS_ERR("%s: IOEXP config incorrect! :%d \n",
+ __func__, chip_id);
+ return -1;
+ }
+ /* Setup default value */
+ for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id),
+ addr_p->write_offset[offset],
+ addr_p->data_default[offset]);
+ if (err_code < 0){
+ SWPS_ERR("%s: set default fail! :%d \n",
+ __func__, err_code);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ }
+ }
+
+update_common_ioexp_init:
+ /* Check and update info to object */
+ err_code = self->update_all(self, 1, "common_ioexp_init");
+ if (err_code < 0) {
+ SWPS_ERR("%s: update_all() fail! :%d \n",
+ __func__, err_code);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+
+/* ========== Object functions for Final State Machine ==========
+ */
+int
+_is_channel_ready(struct ioexp_obj_s *self){
+
+ int buf = 0;
+ int chip_id = 0; /* Use first chip which be registered */
+ int data_id = 0; /* Use first byte which be registered */
+ struct ioexp_addr_s *ioexp_addr = NULL;
+
+ ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!ioexp_addr){
+ SWPS_ERR("%s: config incorrect!\n", __func__);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id),
+ ioexp_addr->read_offset[data_id]);
+ if (buf >= 0){
+ return 1;
+ }
+ return 0;
+}
+
+int
+_ioexp_init_handler(struct ioexp_obj_s *self){
+
+ int return_val;
+
+ switch (self->mode) {
+ case IOEXP_MODE_DIRECT:
+ return_val = self->init(self);
+ if (return_val < 0){
+ self->state = STATE_IOEXP_ABNORMAL;
+ } else {
+ self->state = STATE_IOEXP_NORMAL;
+ }
+ return return_val;
+ default:
+ break;
+ }
+ SWPS_ERR("%s: exception occur :%d\n", __func__, self->mode);
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+int
+common_ioexp_fsm_4_direct(struct ioexp_obj_s *self){
+
+ int result_val;
+ int show_err = 1;
+ char *func_mane = "common_ioexp_fsm_4_direct";
+
+ switch (self->state){
+ case STATE_IOEXP_INIT:
+ result_val = _ioexp_init_handler(self);
+ /* Exception case: terminate initial procedure */
+ if(result_val < 0){
+ /* Initial fail */
+ return result_val;
+ }
+ if(self->state == STATE_IOEXP_INIT){
+ /* Keep in INIT state, and return error */
+ return ERR_IOEXP_UNINIT;
+ }
+ /* Case: Initial done */
+ return 0;
+
+ case STATE_IOEXP_NORMAL:
+ result_val = self->update_all(self, show_err, func_mane);
+ if (result_val < 0){
+ SWPS_INFO("%s: NORMAL -> ABNORMAL :%d\n",
+ __func__, result_val);
+ self->state = STATE_IOEXP_ABNORMAL;
+ return result_val;
+ }
+ self->state = STATE_IOEXP_NORMAL;
+ return 0;
+
+ case STATE_IOEXP_ABNORMAL:
+ result_val = self->update_all(self, show_err, func_mane);
+ if (result_val < 0){
+ self->state = STATE_IOEXP_ABNORMAL;
+ return result_val;
+ }
+ SWPS_DEBUG("%s: ABNORMAL -> NORMAL :%d\n",
+ __func__, result_val);
+ self->state = STATE_IOEXP_NORMAL;
+ return 0;
+
+ default:
+ break;
+ }
+ SWPS_ERR("%s: Exception occurs :%d\n",
+ __func__, self->state);
+ return ERR_IOEXP_UNEXCPT;
+}
+
+/* ========== Functions for Factory pattern ==========
+ */
+static struct ioexp_map_s *
+get_ioexp_map(int ioexp_type){
+ switch (ioexp_type){
+ case IOEXP_TYPE_REDWOOD_P01P08:
+ return &ioexp_map_redwood_p01p08_p17p24;
+ case IOEXP_TYPE_REDWOOD_P09P16:
+ return &ioexp_map_redwood_p09p16_p25p32;
+ default:
+ return NULL;
+ }
+}
+
+
+int
+setup_ioexp_ssize_attr(struct ioexp_obj_s *self,
+ struct ioexp_map_s *ioexp_map_p,
+ int ioexp_id,
+ int ioexp_type,
+ int run_mode){
+ switch (run_mode){
+ case IOEXP_MODE_DIRECT: /* Direct access device mode */
+ self->mode = run_mode;
+ break;
+ default:
+ SWPS_ERR("%s: non-defined run_mode:%d\n",
+ __func__, run_mode);
+ self->mode = ERR_IOEXP_UNEXCPT;
+ return ERR_IOEXP_UNEXCPT;
+ }
+ self->ioexp_id = ioexp_id;
+ self->ioexp_type = ioexp_type;
+ self->ioexp_map_p = ioexp_map_p;
+ self->state = STATE_IOEXP_INIT;
+ mutex_init(&self->lock);
+ return 0;
+}
+
+
+static int
+setup_addr_mapping(struct ioexp_obj_s *self,
+ struct ioexp_addr_s *addr_map_p){
+ if (!addr_map_p){
+ SWPS_ERR("%s: map is null\n", __func__);
+ return -1;
+ }
+ self->ioexp_map_p->map_addr = addr_map_p;
+ return 0;
+}
+
+
+static int
+setup_ioexp_public_cb(struct ioexp_obj_s *self,
+ int ioexp_type){
+ switch (ioexp_type){
+ case IOEXP_TYPE_REDWOOD_P01P08:
+ case IOEXP_TYPE_REDWOOD_P09P16:
+ self->get_present = common_get_present;
+ self->get_reset = common_get_reset;
+ self->get_lpmod = common_get_lpmod;
+ self->get_modsel = common_get_modsel;
+ self->set_reset = common_set_reset;
+ self->set_lpmod = common_set_lpmod;
+ self->set_modsel = common_set_modsel;
+ return 0;
+ default:
+ SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type);
+ break;
+ }
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+static int
+setup_ioexp_private_cb(struct ioexp_obj_s *self,
+ int ioexp_type){
+
+ switch (ioexp_type){
+ case IOEXP_TYPE_REDWOOD_P01P08:
+ case IOEXP_TYPE_REDWOOD_P09P16:
+
+ self->init = common_ioexp_init;
+ self->update_all = common_ioexp_update_all;
+ self->fsm_4_direct = common_ioexp_fsm_4_direct;
+ return 0;
+
+ default:
+ SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type);
+ break;
+ }
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+static int
+setup_i2c_client_one(struct ioexp_obj_s *self,
+ int chip_id){
+
+ char *err_msg = "ERROR";
+ struct i2c_adapter *adap = NULL;
+ struct i2c_client *client = NULL;
+ struct ioexp_i2c_s *i2c_obj_p = NULL;
+ struct ioexp_i2c_s *i2c_curr_p = NULL;
+
+ int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id;
+ adap = i2c_get_adapter(chan_id);
+ if(!adap){
+ err_msg = "Can not get adap!";
+ goto err_ioexp_setup_i2c_1;
+ }
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client){
+ err_msg = "Can not kzalloc client!";
+ goto err_ioexp_setup_i2c_1;
+ }
+ i2c_obj_p = kzalloc(sizeof(*i2c_obj_p), GFP_KERNEL);
+ if (!i2c_obj_p){
+ err_msg = "Can not kzalloc i2c_obj_p!";
+ goto err_ioexp_setup_i2c_2;
+ }
+ client->adapter = adap;
+ client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr;
+ i2c_obj_p->i2c_client_p = client;
+ i2c_obj_p->chip_id = chip_id;
+ i2c_obj_p->next = NULL;
+ if (!self->i2c_head_p){
+ self->i2c_head_p = i2c_obj_p;
+ } else {
+ i2c_curr_p = self->i2c_head_p;
+ while (i2c_curr_p->next){
+ i2c_curr_p = i2c_curr_p->next;
+ }
+ i2c_curr_p->next = i2c_obj_p;
+ }
+ return 0;
+
+err_ioexp_setup_i2c_2:
+ kfree(client);
+err_ioexp_setup_i2c_1:
+ SWPS_ERR("%s: %s :%d\n", __func__, err_msg, chan_id);
+ return -1;
+}
+
+
+static int
+setup_i2c_client(struct ioexp_obj_s* self){
+
+ int result;
+ int chip_id = 0;
+
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ result = setup_i2c_client_one(self, chip_id);
+ if (result < 0){
+ SWPS_ERR("%s fail! :%d\n", __func__, chip_id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+setup_ioexp_config(struct ioexp_obj_s *self) {
+
+ int chip_id, offset, err_code;
+ struct ioexp_addr_s *addr_p;
+
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ addr_p = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!addr_p){
+ SWPS_ERR("IOEXP config incorrect! :%d \n",chip_id);
+ return -1;
+ }
+ for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){
+
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id),
+ addr_p->conf_offset[offset],
+ addr_p->conf_default[offset]);
+
+ if (err_code < 0){
+ SWPS_INFO("%s: set conf fail! :%d \n", __func__, err_code);
+ return -2;
+ }
+ }
+ }
+ return 0;
+}
+
+struct ioexp_obj_s *
+_create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode){
+
+ struct ioexp_map_s* ioexp_map_p;
+ struct ioexp_obj_s* result_p;
+ struct ioexp_i2c_s *i2c_curr_p;
+ struct ioexp_i2c_s *i2c_next_p;
+
+ /* Get layout */
+ ioexp_map_p = get_ioexp_map(ioexp_type);
+ if (!ioexp_map_p){
+ SWPS_ERR("%s: Invalid ioexp_type\n", __func__);
+ goto err_create_ioexp_fail;
+ }
+ /* Prepare IOEXP object */
+ result_p = kzalloc(sizeof(*result_p), GFP_KERNEL);
+ if (!result_p){
+ SWPS_ERR("%s: kzalloc failure!\n", __func__);
+ goto err_create_ioexp_fail;
+ }
+ /* Prepare static size attributes */
+ if (setup_ioexp_ssize_attr(result_p,
+ ioexp_map_p,
+ ioexp_id,
+ ioexp_type,
+ run_mode) < 0){
+ goto err_create_ioexp_setup_attr_fail;
+ }
+ /* Prepare address mapping */
+ if (setup_addr_mapping(result_p, addr_map_p) < 0){
+ goto err_create_ioexp_setup_attr_fail;
+ }
+ if (setup_i2c_client(result_p) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ /* Prepare call back functions of object */
+ if (setup_ioexp_public_cb(result_p, ioexp_type) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ if (setup_ioexp_private_cb(result_p, ioexp_type) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ return result_p;
+
+err_create_ioexp_setup_i2c_fail:
+ i2c_curr_p = result_p->i2c_head_p;
+ i2c_next_p = result_p->i2c_head_p;
+ while (i2c_curr_p){
+ i2c_next_p = i2c_curr_p->next;
+ kfree(i2c_curr_p->i2c_client_p);
+ kfree(i2c_curr_p);
+ i2c_curr_p = i2c_next_p;
+ }
+err_create_ioexp_setup_attr_fail:
+ kfree(result_p);
+err_create_ioexp_fail:
+ SWPS_ERR("%s: fail! :%d :%d \n",
+ __func__, ioexp_id, ioexp_type);
+ return NULL;
+}
+
+
+int
+create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode){
+
+ struct ioexp_obj_s *ioexp_p = NULL;
+
+ ioexp_p = _create_ioexp_obj(ioexp_id, ioexp_type,
+ addr_map_p, run_mode);
+ if (!ioexp_p){
+ return -1;
+ }
+ if (ioexp_head_p == NULL){
+ ioexp_head_p = ioexp_p;
+ ioexp_tail_p = ioexp_p;
+ return 0;
+ }
+ ioexp_tail_p->next = ioexp_p;
+ ioexp_tail_p = ioexp_p;
+ return 0;
+}
+
+static int
+_init_ioexp_obj(struct ioexp_obj_s* self) {
+
+ char *err_msg = "ERR";
+ char *func_name = "_init_ioexp_obj";
+
+ /* Setup IOEXP configure byte */
+ if (setup_ioexp_config(self) < 0){
+ err_msg = "setup_ioexp_config fail";
+ goto err_init_ioexp_obj;
+ }
+ /* Setup default data */
+ if (_ioexp_init_handler(self) < 0){
+ err_msg = "_ioexp_init_handler fail";
+ goto err_init_ioexp_obj;
+ }
+ /* Update all */
+ if (self->state == STATE_IOEXP_NORMAL){
+ if (self->update_all(self, 1, func_name) < 0){
+ err_msg = "update_all() fail";
+ goto err_init_ioexp_obj;
+ }
+ }
+ return 0;
+
+err_init_ioexp_obj:
+ SWPS_DEBUG("%s: %s\n", __func__, err_msg);
+ return -1;
+}
+
+int
+init_ioexp_objs(void){
+ /* Return value:
+ * 0: Success
+ * -1: Detect topology error
+ * -2: SWPS internal error
+ */
+
+ struct ioexp_obj_s *curr_p = ioexp_head_p;
+
+ if (!curr_p) {
+ SWPS_ERR("%s: ioexp_head_p is NULL\n", __func__);
+ return -2;
+ }
+ while (curr_p) {
+ if (_init_ioexp_obj(curr_p) < 0) {
+ SWPS_DEBUG("%s: _init_ioexp_obj() fail\n", __func__);
+ return -1;
+ }
+ curr_p = curr_p->next;
+ }
+ SWPS_DEBUG("%s: done.\n", __func__);
+ return 0;
+}
+
+void
+clean_ioexp_objs(void){
+
+ struct ioexp_i2c_s *i2c_curr_p = NULL;
+ struct ioexp_i2c_s *i2c_next_p = NULL;
+ struct ioexp_obj_s *ioexp_next_p = NULL;
+ struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p;
+
+ if (ioexp_head_p == NULL){
+ ioexp_tail_p = NULL;
+ return;
+ }
+ while(ioexp_curr_p){
+ ioexp_next_p = ioexp_curr_p->next;
+ i2c_curr_p = ioexp_curr_p->i2c_head_p;
+ while (i2c_curr_p) {
+ i2c_next_p = i2c_curr_p->next;
+ kfree(i2c_curr_p->i2c_client_p);
+ kfree(i2c_curr_p);
+ i2c_curr_p = i2c_next_p;
+ }
+ kfree(ioexp_curr_p);
+ ioexp_curr_p = ioexp_next_p;
+ }
+ ioexp_tail_p = NULL;
+ SWPS_DEBUG("%s: done.\n", __func__);
+}
+
+struct ioexp_obj_s *
+get_ioexp_obj(int ioexp_id){
+
+ struct ioexp_obj_s *result_p = NULL;
+ struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p;
+
+ while(ioexp_curr_p){
+ if (ioexp_curr_p->ioexp_id == ioexp_id){
+ result_p = ioexp_curr_p;
+ break;
+ }
+ ioexp_curr_p = ioexp_curr_p->next;
+ }
+ return result_p;
+}
+int
+check_channel_tier_1(void) {
+
+ if ( (!_is_channel_ready(ioexp_head_p)) &&
+ (!_is_channel_ready(ioexp_tail_p)) ){
+ return -1;
+ }
+ return 0;
+}
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h
new file mode 100644
index 0000000000..8c51b4f6d9
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h
@@ -0,0 +1,136 @@
+#ifndef IO_EXPANDER_H
+#define IO_EXPANDER_H
+
+#include
+
+/* IOEXP type define (QSFP series) */
+#define IOEXP_TYPE_REDWOOD_P01P08 (10202)
+#define IOEXP_TYPE_REDWOOD_P09P16 (10203)
+
+/* IOEXP mode define */
+#define IOEXP_MODE_DIRECT (19001)
+
+/* IOEXP state define */
+#define STATE_IOEXP_NORMAL (0)
+#define STATE_IOEXP_INIT (-1)
+#define STATE_IOEXP_ABNORMAL (-2)
+
+/* IOEXP error code define */
+#define ERR_IOEXP_NOTSUPPORT (-100)
+#define ERR_IOEXP_UNINIT (-101)
+#define ERR_IOEXP_BADCONF (-102)
+#define ERR_IOEXP_BADINPUT (-105)
+#define ERR_IOEXP_UNEXCPT (-199)
+
+
+#define SWPS_INFO(fmt, args...) printk( KERN_INFO "[SWPS] " fmt, ##args)
+#define SWPS_WARN(fmt, args...) printk( KERN_WARNING "[SWPS] " fmt, ##args)
+#define SWPS_ERR(fmt, args...) printk( KERN_ERR "[SWPS] " fmt, ##args)
+
+#ifdef DEBUG_SWPS
+# define SWPS_DEBUG(fmt, args...) printk( KERN_DEBUG "[SWPS] " fmt, ##args)
+#else
+# define SWPS_DEBUG(fmt, args...)
+#endif
+
+
+struct ioexp_addr_s {
+ int chan_id;
+ int chip_addr;
+ int read_offset[8];
+ int write_offset[8];
+ int conf_offset[8];
+ uint8_t data_default[8];
+ uint8_t conf_default[8];
+};
+
+struct ioexp_i2c_s {
+ int chip_id;
+ struct i2c_client *i2c_client_p;
+ struct ioexp_i2c_s *next;
+};
+
+
+struct ioexp_bitmap_s {
+ int chip_id; /* IOEXP chip id */
+ int ioexp_voffset; /* IOEXP virtual offset */
+ int bit_shift;
+};
+
+struct ioexp_map_s {
+ int chip_amount; /* Number of chips that IOEXP object content */
+ int data_width; /* Number of (Read/Write/Config) bytes */
+ struct ioexp_addr_s *map_addr; /* Chip address info */
+ struct ioexp_bitmap_s map_present[8]; /* IOEXP for SFP / QSFP */
+ struct ioexp_bitmap_s map_reset[8]; /* IOEXP for QSFP */
+ struct ioexp_bitmap_s map_lpmod[8]; /* IOEXP for QSFP */
+ struct ioexp_bitmap_s map_modsel[8]; /* IOEXP for QSFP */
+};
+
+struct ioexp_data_s {
+ uint8_t data[8];
+};
+
+struct ioexp_obj_s {
+
+ /* ============================
+ * Object public property
+ * ============================
+ */
+ int ioexp_id;
+ int ioexp_type;
+
+ /* ============================
+ * Object private property
+ * ============================
+ */
+ struct ioexp_data_s chip_data[16]; /* Max: 8-ioexp in one virt-ioexp(ioexp_obj) */
+ struct ioexp_map_s *ioexp_map_p;
+ struct ioexp_obj_s *next;
+ struct ioexp_i2c_s *i2c_head_p;
+ struct mutex lock;
+ int mode;
+ int state;
+
+ /* ===========================================
+ * Object public functions
+ * ===========================================
+ */
+ int (*get_present)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_reset)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_lpmod)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_modsel)(struct ioexp_obj_s *self, int virt_offset);
+ int (*set_reset)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+ int (*set_lpmod)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+ int (*set_modsel)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+
+ /* ===========================================
+ * Object private functions
+ * ===========================================
+ */
+ int (*init)(struct ioexp_obj_s *self);
+ int (*update_all)(struct ioexp_obj_s *self, int show_err, char *caller_name);
+ int (*fsm_4_direct)(struct ioexp_obj_s* self);
+};
+
+
+struct ioexp_obj_s* get_ioexp_obj(int ioexp_id);
+int create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode);
+int init_ioexp_objs(void);
+void clean_ioexp_objs(void);
+
+int check_channel_tier_1(void);
+
+/* Macro for bit control */
+#define SWP_BIT_SET(byte_val,bit_shift) ((byte_val) |= (1<<(bit_shift)))
+#define SWP_BIT_CLEAR(byte_val,bit_shift) ((byte_val) &= ~(1<<(bit_shift)))
+
+
+#endif /* IO_EXPANDER_H */
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c
new file mode 100644
index 0000000000..36ccc45a92
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c
@@ -0,0 +1,898 @@
+#include
+#include
+#include
+#include
+#include "io_expander.h"
+#include "transceiver.h"
+
+
+/* ========== Register EEPROM address mapping ==========
+ */
+struct eeprom_map_s eeprom_map_qsfp = {
+ .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1,
+ .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1,
+ .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1,
+};
+
+struct eeprom_map_s eeprom_map_qsfp28 = {
+ .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1,
+ .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1,
+ .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1,
+};
+
+
+/* ========== Utility Functions ==========
+ */
+void
+alarm_msg_2_user(struct transvr_obj_s *self,
+ char *emsg) {
+
+ SWPS_ERR("%s on %s.\n", emsg, self->swp_name);
+}
+
+
+/* ========== Private functions ==========
+ */
+static int
+_reload_transvr_obj(struct transvr_obj_s *self,int new_type);
+
+static int
+reload_transvr_obj(struct transvr_obj_s *self,int new_type);
+
+static int
+_transvr_init_handler(struct transvr_obj_s *self);
+
+static void
+_transvr_clean_retry(struct transvr_obj_s *self) {
+ self->retry = 0;
+}
+
+
+static int
+_transvr_handle_retry(struct transvr_obj_s *self, int retry) {
+ /* Return: 0: keep retry
+ * -1: stop retry
+ */
+ if (self->retry == 0) {
+ self->retry = retry;
+ }
+ self->retry -= 1;
+ if (self->retry <= 0) {
+ _transvr_clean_retry(self);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_common_setup_page(struct transvr_obj_s *self,
+ int addr,
+ int page,
+ int offset,
+ int len,
+ int show_e) {
+ /* return:
+ * 0 : OK
+ * -1 : EEPROM settings incorrect
+ * -2 : I2C R/W failure
+ * -3 : Undefined case
+ */
+ int retval = DEBUG_TRANSVR_INT_VAL;
+ char *emsg = DEBUG_TRANSVR_STR_VAL;
+
+ /* Check */
+ if ((addr < 0) || (offset < 0) || (len < 0)) {
+ emsg = "EEPROM settings incorrect";
+ retval = -1;
+ goto err_common_setup_page;
+ }
+ /* Case1: continue access */
+ if ((self->i2c_client_p->addr == addr) &&
+ (self->curr_page == page)) {
+ return 0;
+ }
+ self->i2c_client_p->addr = addr;
+ /* Case2: select lower page */
+ if (page == -1) {
+ self->curr_page = page;
+ return 0;
+ }
+ /* Case3: select upper page */
+ if (page >= 0) {
+ goto upper_common_setup_page;
+ }
+ /* Unexpected case */
+ show_e = 1;
+ emsg = "Unexpected case";
+ retval = -3;
+ goto err_common_setup_page;
+
+upper_common_setup_page:
+ if (i2c_smbus_write_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_PAGE_SELECT_OFFSET,
+ page) < 0) {
+ emsg = "I2C R/W failure";
+ retval = -2;
+ goto err_common_setup_page;
+ }
+ self->curr_page = page;
+ mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY);
+ return 0;
+
+err_common_setup_page:
+ if (show_e) {
+ SWPS_INFO("%s: %s", __func__, emsg);
+ SWPS_INFO("%s: :0x%02x :%d :%d :%d\n",
+ __func__, addr, page, offset, len);
+ }
+ return retval;
+}
+
+/* ========== Object functions for Final State Machine ==========
+ */
+int
+is_plugged(struct transvr_obj_s *self){
+
+ int limit = 63;
+ int present = DEBUG_TRANSVR_INT_VAL;
+ char emsg[64] = DEBUG_TRANSVR_STR_VAL;
+ struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ snprintf(emsg, limit, "ioexp_p is null!");
+ goto err_is_plugged_1;
+ }
+ present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset);
+ switch (present){
+ case 0:
+ return 1;
+ case 1:
+ return 0;
+ case ERR_IOEXP_UNINIT:
+ snprintf(emsg, limit, "ioexp_p not ready!");
+ goto err_is_plugged_1;
+ default:
+ if (ioexp_p->state == STATE_IOEXP_INIT){
+ snprintf(emsg, limit, "ioexp_p not ready!");
+ goto err_is_plugged_1;
+ }
+ break;
+ }
+ SWPS_INFO("%s: Exception case! :%d :%d\n",
+ __func__, present, ioexp_p->state);
+ return 0;
+
+err_is_plugged_1:
+ SWPS_DEBUG("%s: %s\n", __func__, emsg);
+ return 0;
+}
+
+
+static int
+detect_transvr_type(struct transvr_obj_s* self){
+
+ int type = TRANSVR_TYPE_ERROR;
+
+ self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
+ type = i2c_smbus_read_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_COMID_OFFSET);
+
+ /* Case: 1. Wait transceiver I2C module.
+ * 2. Transceiver I2C module failure.
+ * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there
+ * are exist some case that we need to wait transceiver.
+ * For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than
+ * state machine will keep trace with it.
+ * 2. There exist some I2C failure case we need to handle. Such as user
+ * insert the failure transceiver, or any reason cause it abnormal.
+ */
+ if (type < 0){
+ switch (type) {
+ case -EIO:
+ SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n",
+ __func__, self->swp_name);
+ return TRANSVR_TYPE_UNPLUGGED;
+ case -ENXIO:
+ SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n",
+ __func__, self->swp_name);
+ return TRANSVR_TYPE_UNPLUGGED;
+ default:
+ break;
+ }
+ SWPS_INFO("%s: %s unexpected smbus return:%d \n",
+ __func__, self->swp_name, type);
+ return TRANSVR_TYPE_ERROR;
+ }
+ /* Identify valid transceiver type */
+ switch (type){
+ case TRANSVR_TYPE_SFP:
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ break;
+ case TRANSVR_TYPE_UNKNOW_1:
+ case TRANSVR_TYPE_UNKNOW_2:
+ type = TRANSVR_TYPE_UNKNOW_2;
+ break;
+ default:
+ SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type);
+ type = TRANSVR_TYPE_ERROR;
+ break;
+ }
+ return type;
+}
+
+
+static int
+detect_transvr_state(struct transvr_obj_s *self,
+ int result[2]){
+ /* [return] [result-0] [result-1]
+ * 0 STATE_TRANSVR_CONNECTED TRANSVR_TYPE_FAKE
+ * 0 STATE_TRANSVR_DISCONNECTED TRANSVR_TYPE_UNPLUGGED
+ * 0 STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR
+ * 0 STATE_TRANSVR_INIT /
+ * 0 STATE_TRANSVR_SWAPPED
+ * 0 STATE_TRANSVR_CONNECTED
+ * ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR
+ * ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR
+ * ERR_TRANSVR_UNEXCPT STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_UNKNOW_1/2
+ */
+ result[0] = STATE_TRANSVR_UNEXCEPTED; /* For return state */
+ result[1] = TRANSVR_TYPE_ERROR; /* For return type */
+
+ /* Case1: Fake type */
+ if (self->type == TRANSVR_TYPE_FAKE){
+ result[0] = STATE_TRANSVR_CONNECTED;
+ result[1] = TRANSVR_TYPE_FAKE;
+ return 0;
+ }
+ /* Case2: Transceiver unplugged */
+ if (!is_plugged(self)){
+ result[0] = STATE_TRANSVR_DISCONNECTED;
+ result[1] = TRANSVR_TYPE_UNPLUGGED;
+ return 0;
+ }
+ /* Case3: Transceiver be isolated */
+ if (self->state == STATE_TRANSVR_ISOLATED){
+ result[0] = STATE_TRANSVR_ISOLATED;
+ result[1] = TRANSVR_TYPE_ERROR;
+ return ERR_TRNASVR_BE_ISOLATED;
+ }
+ /* Case4: Transceiver plugged */
+ result[1] = detect_transvr_type(self);
+ /* Case4.1: I2C topology crash
+ * Note : There are some I2C issues cause by transceiver/cables.
+ * We need to check topology status when user insert it.
+ * But in this step, we can't not ensure this is the issues
+ * port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper
+ * layer will diagnostic I2C topology.
+ */
+ if (check_channel_tier_1() < 0) {
+ SWPS_INFO("%s: %s detect I2C crash :%d\n",
+ __func__, self->swp_name, self->state);
+ result[0] = STATE_TRANSVR_UNEXCEPTED;
+ result[1] = TRANSVR_TYPE_ERROR;
+ return ERR_TRANSVR_I2C_CRASH;
+ }
+ /* Case4.2: System initial not ready,
+ * Note : Sometime i2c channel or transceiver EEPROM will delay that will
+ * cause system in inconsistent state between EEPROM and IOEXP.
+ * In this case, SWP transceiver object keep state at LINK_DOWN
+ * to wait system ready.
+ * By the way, State Machine will handle these case.
+ */
+ if (result[1] == TRANSVR_TYPE_UNPLUGGED){
+ result[0] = STATE_TRANSVR_DISCONNECTED;
+ return 0;
+ }
+ /* Case4.3: Error transceiver type */
+ if (result[1] == TRANSVR_TYPE_ERROR){
+ result[0] = STATE_TRANSVR_ISOLATED;
+ SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name);
+ alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!");
+ return ERR_TRNASVR_BE_ISOLATED;
+ }
+ /* Case3.3: Unknow transceiver type */
+ if ((result[1] == TRANSVR_TYPE_UNKNOW_1) ||
+ (result[1] == TRANSVR_TYPE_UNKNOW_2) ){
+ result[0] = STATE_TRANSVR_UNEXCEPTED;
+ return ERR_TRANSVR_UNEXCPT;
+ }
+ /* Case3.4: During initial process */
+ if (self->state == STATE_TRANSVR_INIT){
+ result[0] = STATE_TRANSVR_INIT;
+ return 0;
+ }
+ /* Case3.5: Transceiver be swapped */
+ if (self->type != result[1]){
+ result[0] = STATE_TRANSVR_SWAPPED;
+ return 0;
+ }
+ /* Case3.6: Link up state */
+ result[0] = STATE_TRANSVR_CONNECTED;
+ return 0;
+}
+int
+common_fsm_4_direct_mode(struct transvr_obj_s* self,
+ char *caller_name){
+
+ int err;
+ int detect_result[2];
+ int current_state = STATE_TRANSVR_UNEXCEPTED;
+ int current_type = TRANSVR_TYPE_ERROR;
+
+ if (self->state == STATE_TRANSVR_NEW) {
+ if (_transvr_init_handler(self) < 0){
+ return ERR_TRANSVR_INIT_FAIL;
+ }
+ }
+ err = detect_transvr_state(self, detect_result);
+ if (err < 0) {
+ return err;
+ }
+ /* In Direct mode, driver only detect transceiver when user call driver interface
+ * which on sysfs. So it only need consider the state of Transceiver.
+ */
+ current_state = detect_result[0];
+ current_type = detect_result[1];
+
+ switch (current_state){
+
+ case STATE_TRANSVR_DISCONNECTED: /* Transceiver is not plugged */
+ self->state = current_state;
+ self->type = current_type;
+ return ERR_TRANSVR_UNPLUGGED;
+
+ case STATE_TRANSVR_INIT: /* Transceiver is plugged, system not ready */
+ return ERR_TRANSVR_UNINIT;
+
+ case STATE_TRANSVR_ISOLATED: /* Transceiver is plugged, but has some issues */
+ return ERR_TRNASVR_BE_ISOLATED;
+
+ case STATE_TRANSVR_CONNECTED: /* Transceiver is plugged, system is ready */
+ self->state = current_state;
+ self->type = current_type;
+ return 0;
+
+ case STATE_TRANSVR_SWAPPED: /* Transceiver is plugged, system detect user changed */
+ self->type = current_type;
+ if (reload_transvr_obj(self, current_type) < 0){
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ return ERR_TRANSVR_UNEXCPT;
+ }
+ self->state = current_state;
+ return 0;
+
+ case STATE_TRANSVR_UNEXCEPTED: /* Transceiver type or state is unexpected case */
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ self->type = TRANSVR_TYPE_ERROR;
+ return ERR_TRANSVR_UNEXCPT;
+
+ default:
+ SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state);
+ break;
+ }
+ return ERR_TRANSVR_UNEXCPT;
+}
+
+int
+fake_fsm_4_direct_mode(struct transvr_obj_s* self,
+ char *caller_name){
+ self->state = STATE_TRANSVR_CONNECTED;
+ self->type = TRANSVR_TYPE_FAKE;
+ return 0;
+}
+
+/* ========== Object Initial handler ==========
+ */
+static int
+_is_transvr_valid(struct transvr_obj_s *self,
+ int type,
+ int state) {
+ /* [Return]
+ * 0 : OK, inserted
+ * EVENT_TRANSVR_INIT_DOWN : OK, removed
+ * EVENT_TRANSVR_INIT_FAIL : Outside error, type doesn't supported
+ * EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined
+ */
+ switch (type) {
+ case TRANSVR_TYPE_SFP:
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ case TRANSVR_TYPE_UNPLUGGED:
+ case TRANSVR_TYPE_FAKE:
+ break;
+ default:
+ SWPS_INFO("detect undefined type:0x%02x on %s\n",
+ type, self->swp_name);
+ return EVENT_TRANSVR_INIT_FAIL;
+ }
+ switch (state) {
+ case STATE_TRANSVR_DISCONNECTED:
+ return EVENT_TRANSVR_INIT_DOWN;
+ case STATE_TRANSVR_INIT:
+ case STATE_TRANSVR_CONNECTED:
+ case STATE_TRANSVR_SWAPPED:
+ break;
+ default:
+ SWPS_INFO("detect undefined state:%d on %s\n",
+ state, self->swp_name);
+ return EVENT_TRANSVR_EXCEP_INIT;
+ }
+ return 0;
+}
+
+
+static int
+_is_transvr_hw_ready(struct transvr_obj_s *self,
+ int type){
+ /* [Return]
+ * EVENT_TRANSVR_TASK_DONE : Ready
+ * EVENT_TRANSVR_TASK_WAIT : Not ready
+ * EVENT_TRANSVR_INIT_FAIL : Error
+ */
+ int addr = DEBUG_TRANSVR_INT_VAL;
+ int page = DEBUG_TRANSVR_INT_VAL;
+ int offs = DEBUG_TRANSVR_INT_VAL;
+ int bit = DEBUG_TRANSVR_INT_VAL;
+ int ready = DEBUG_TRANSVR_INT_VAL;
+ int err = DEBUG_TRANSVR_INT_VAL;
+ char *emsg = DEBUG_TRANSVR_STR_VAL;
+ uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL;
+
+ switch (type) {
+ case TRANSVR_TYPE_SFP:
+ addr = VAL_TRANSVR_8472_READY_ADDR;
+ page = VAL_TRANSVR_8472_READY_PAGE;
+ offs = VAL_TRANSVR_8472_READY_OFFSET;
+ bit = VAL_TRANSVR_8472_READY_BIT;
+ ready = VAL_TRANSVR_8472_READY_VALUE;
+ ab_val = VAL_TRANSVR_8472_READY_ABNORMAL;
+ break;
+
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ addr = VAL_TRANSVR_8436_READY_ADDR;
+ page = VAL_TRANSVR_8436_READY_PAGE;
+ offs = VAL_TRANSVR_8436_READY_OFFSET;
+ bit = VAL_TRANSVR_8436_READY_BIT;
+ ready = VAL_TRANSVR_8436_READY_VALUE;
+ ab_val = VAL_TRANSVR_8436_READY_ABNORMAL;
+ break;
+
+ case TRANSVR_TYPE_UNPLUGGED:
+ case TRANSVR_TYPE_FAKE:
+ return EVENT_TRANSVR_TASK_DONE;
+
+ default:
+ emsg = "unexpected case";
+ goto err_is_transvr_hw_ready;
+ }
+ /* Select target page */
+ err = _common_setup_page(self, addr, page, offs, 1, 0);
+ if (err < 0) {
+ emsg = "setup page fail";
+ goto err_is_transvr_hw_ready;
+ }
+ /* Check feature supported
+ * [Note]
+ * Some of transceiver/cables doesn't support "Status Indicators"
+ * (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the
+ * step of checking Status Indicators, then state machine will take
+ * the following handle procedure.
+ */
+ err = i2c_smbus_read_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_COMID_OFFSET);
+ if (err < 0) {
+ emsg = "doesn't support Status Indicators";
+ goto bypass_is_transvr_hw_ready;
+ }
+ /* Filter abnormal case */
+ if (err == ab_val) {
+ emsg = "detect using unusual definition.";
+ goto bypass_is_transvr_hw_ready;
+ }
+ /* Get Status Indicators */
+ err = i2c_smbus_read_byte_data(self->i2c_client_p, offs);
+ if (err < 0) {
+ emsg = "detect current value fail";
+ goto err_is_transvr_hw_ready;
+ }
+ if ((err & (1<:%d\n", __func__, emsg, type);
+ return EVENT_TRANSVR_TASK_DONE;
+
+err_is_transvr_hw_ready:
+ SWPS_DEBUG("%s: %s :%d\n", __func__, emsg, type);
+ return EVENT_TRANSVR_INIT_FAIL;
+}
+
+static int
+_transvr_init_handler(struct transvr_obj_s *self){
+
+ int detect[2];
+ int d_state = STATE_TRANSVR_UNEXCEPTED;
+ int d_type = TRANSVR_TYPE_ERROR;
+ int result = ERR_TRANSVR_UNINIT;
+ int retry = 6; /* (6+1) x 0.3 = 2.1s > spec:2.0s */
+ int elimit = 63;
+ char emsg[64] = DEBUG_TRANSVR_STR_VAL;
+
+ /* Clean and check callback */
+ self->state = STATE_TRANSVR_INIT;
+ if (self->init == NULL) {
+ snprintf(emsg, elimit, "init() is null");
+ goto initer_err_case_unexcept_0;
+ }
+ /* Detect transceiver information */
+ result = detect_transvr_state(self, detect);
+ if (result < 0) {
+ snprintf(emsg, elimit, "detect_transvr_state() fail");
+ switch (result) {
+ case ERR_TRANSVR_I2C_CRASH:
+ goto initer_err_case_i2c_ceash;
+ case ERR_TRNASVR_BE_ISOLATED:
+ goto initer_err_case_be_isolated;
+
+ case ERR_TRANSVR_UNEXCPT:
+ default:
+ break;
+ }
+ goto initer_err_case_retry_1;
+ }
+ d_state = detect[0];
+ d_type = detect[1];
+
+ /* Verify transceiver type and state */
+ switch (_is_transvr_valid(self, d_type, d_state)) {
+ case 0:
+ break;
+ case EVENT_TRANSVR_INIT_DOWN:
+ goto initer_ok_case_down;;
+ case EVENT_TRANSVR_INIT_FAIL:
+ snprintf(emsg, elimit, "transceiver type doesn't support");
+ goto initer_err_case_alarm_to_user;
+ case EVENT_TRANSVR_EXCEP_INIT:
+ default:
+ goto initer_err_case_unexcept_0;
+ }
+
+ /* Handle reload case */
+ if (self->type != d_type){
+ /* This is the protect mechanism. Normally, This case will not happen.
+ * When State machine detect swap event during initial, It will trigger
+ * reload function to ensure type correct. */
+ if (_reload_transvr_obj(self, d_type) < 0){
+ snprintf(emsg, elimit, "reload object fail");
+ goto initer_err_case_unexcept_0;
+ }
+ }
+
+ /* Check transceiver HW initial ready */
+ switch (_is_transvr_hw_ready(self, d_type)) {
+ case EVENT_TRANSVR_TASK_DONE:
+ break;
+ case EVENT_TRANSVR_TASK_WAIT:
+ goto initer_err_case_retry_1;
+ case EVENT_TRANSVR_INIT_FAIL:
+ default:
+ goto initer_err_case_unexcept_0;
+ }
+
+ /* Try to update all and check */
+ if (self->update_all(self, 1) < 0){
+ /* For some transceiver, EEPROME has lag issues during initial stage.
+ * In this case, we set status back to STATE_TRANSVR_NEW, than it will
+ * be checked in next polling cycle. */
+ goto initer_err_case_retry_1;
+ }
+
+ /* Execute init() call back */
+ result = self->init(self);
+ switch (result) {
+ case EVENT_TRANSVR_TASK_DONE:
+ break;
+ case EVENT_TRANSVR_TASK_WAIT:
+ goto initer_ok_case_wait;
+
+ default:
+ snprintf(emsg, elimit, "undefined init() return:%d\n", result);
+ goto initer_err_case_unexcept_0;
+ }
+ goto initer_ok_case_up;
+
+
+initer_ok_case_wait:
+ return EVENT_TRANSVR_TASK_WAIT;
+
+initer_ok_case_up:
+ self->state = STATE_TRANSVR_CONNECTED;
+ self->temp = 0;
+ return EVENT_TRANSVR_INIT_UP;
+
+initer_ok_case_down:
+ self->temp = 0;
+ self->state = STATE_TRANSVR_DISCONNECTED;
+ return EVENT_TRANSVR_INIT_DOWN;
+
+initer_err_case_i2c_ceash:
+ SWPS_DEBUG("%s: %s :%s :I2C crash\n",
+ __func__, emsg, self->swp_name);
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ return EVENT_TRANSVR_I2C_CRASH;
+
+initer_err_case_be_isolated:
+ SWPS_DEBUG("%s: %s :%s :isolated\n",
+ __func__, emsg, self->swp_name);
+ self->state = STATE_TRANSVR_ISOLATED;
+ return EVENT_TRANSVR_EXCEP_ISOLATED;
+
+initer_err_case_retry_1:
+ SWPS_DEBUG("%s: %s :%s :retry\n",
+ __func__, emsg, self->swp_name);
+ if (_transvr_handle_retry(self, retry) == 0) {
+ self->state = STATE_TRANSVR_NEW;
+ return EVENT_TRANSVR_INIT_REINIT;
+ }
+ goto initer_err_case_alarm_to_user;
+
+initer_err_case_unexcept_0:
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ return EVENT_TRANSVR_INIT_FAIL;
+
+initer_err_case_alarm_to_user:
+ SWPS_DEBUG("%s: %s :%s :alarm_to_user\n",
+ __func__, emsg, self->swp_name);
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard");
+ return EVENT_TRANSVR_INIT_FAIL;
+}
+
+static int
+setup_transvr_private_cb(struct transvr_obj_s *self,
+ int transvr_type){
+ switch (transvr_type){
+ case TRANSVR_TYPE_SFP:
+ self->fsm_4_direct = common_fsm_4_direct_mode;
+ return 0;
+
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ self->fsm_4_direct = common_fsm_4_direct_mode;
+ return 0;
+
+ case TRANSVR_TYPE_QSFP_28:
+ self->fsm_4_direct = common_fsm_4_direct_mode;
+ return 0;
+
+ case TRANSVR_TYPE_FAKE:
+ self->fsm_4_direct = fake_fsm_4_direct_mode;
+ return 0;
+
+ default:
+ break;
+ }
+ SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type);
+ return ERR_TRANSVR_UNEXCPT;
+}
+
+
+static struct eeprom_map_s *
+get_eeprom_map(int transvr_type){
+
+ switch (transvr_type){
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ return &eeprom_map_qsfp;
+ case TRANSVR_TYPE_QSFP_28:
+ return &eeprom_map_qsfp28;
+
+ default:
+ break;
+ }
+ SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type);
+ return NULL;
+}
+
+
+static int
+setup_transvr_ssize_attr(char *swp_name,
+ struct transvr_obj_s *self,
+ struct eeprom_map_s *map_p,
+ struct ioexp_obj_s *ioexp_obj_p,
+ int ioexp_virt_offset,
+ int transvr_type,
+ int chipset_type,
+ int chan_id,
+ int run_mode){
+ switch (run_mode){
+ case TRANSVR_MODE_DIRECT: /* Direct access device mode */
+ self->mode = run_mode;
+ break;
+ default:
+ SWPS_ERR("%s: non-defined run_mode:%d\n",
+ __func__, run_mode);
+ self->mode = DEBUG_TRANSVR_INT_VAL;
+ return -1;
+ }
+ self->eeprom_map_p = map_p;
+ self->ioexp_obj_p = ioexp_obj_p;
+ self->ioexp_virt_offset = ioexp_virt_offset;
+ self->chan_id = chan_id;
+ self->layout = transvr_type;
+ self->type = transvr_type;
+ self->chipset_type = chipset_type;
+ self->state = STATE_TRANSVR_NEW;
+ self->info = STATE_TRANSVR_NEW;
+ self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE;
+ strncpy(self->swp_name, swp_name, 32);
+ mutex_init(&self->lock);
+ return 0;
+}
+
+
+
+static int
+setup_i2c_client(struct transvr_obj_s *self){
+
+ struct i2c_adapter *adap = NULL;
+ struct i2c_client *client = NULL;
+ char err_msg[64] = DEBUG_TRANSVR_STR_VAL;
+
+ adap = i2c_get_adapter(self->chan_id);
+ if(!adap){
+ snprintf(err_msg, sizeof(err_msg),
+ "can not get adap:%d", self->chan_id);
+ goto err_setup_i2c_client;
+ }
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client){
+ snprintf(err_msg, sizeof(err_msg),
+ "can not kzalloc client:%d", self->chan_id);
+ goto err_setup_i2c_client;
+ }
+ client->adapter = adap;
+ self->i2c_client_p = client;
+ self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
+ return 0;
+
+err_setup_i2c_client:
+ SWPS_ERR("%s: %s\n", __func__, err_msg);
+ return ERR_TRANSVR_UNEXCPT;
+}
+
+
+struct transvr_obj_s *
+create_transvr_obj(char *swp_name,
+ int chan_id,
+ struct ioexp_obj_s *ioexp_obj_p,
+ int ioexp_virt_offset,
+ int transvr_type,
+ int chipset_type,
+ int run_mode){
+
+ struct transvr_obj_s *result_p;
+ struct eeprom_map_s *map_p;
+ char err_msg[64] = DEBUG_TRANSVR_STR_VAL;
+
+ /* Allocate transceiver object */
+ map_p = get_eeprom_map(transvr_type);
+ if (!map_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "Invalid transvr_type:%d", transvr_type);
+ goto err_create_transvr_fail;
+ }
+ result_p = kzalloc(sizeof(*result_p), GFP_KERNEL);
+ if (!result_p){
+ snprintf(err_msg, sizeof(err_msg), "kzalloc fail");
+ goto err_create_transvr_fail;
+ }
+ /* Prepare static size attributes */
+ if (setup_transvr_ssize_attr(swp_name,
+ result_p,
+ map_p,
+ ioexp_obj_p,
+ ioexp_virt_offset,
+ transvr_type,
+ chipset_type,
+ chan_id,
+ run_mode) < 0){
+ goto err_create_transvr_sattr_fail;
+ }
+
+ /* Prepare call back functions of object */
+ if (setup_transvr_private_cb(result_p, transvr_type) < 0){
+ goto err_create_transvr_sattr_fail;
+ }
+ /* Prepare i2c client object */
+ if (setup_i2c_client(result_p) < 0){
+ goto err_create_transvr_sattr_fail;
+ }
+ return result_p;
+err_create_transvr_sattr_fail:
+ kfree(result_p);
+err_create_transvr_fail:
+ SWPS_ERR("%s: %s :%d :%d :%d\n",
+ __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type);
+ return NULL;
+}
+
+
+static int
+_reload_transvr_obj(struct transvr_obj_s *self,
+ int new_type){
+
+ struct eeprom_map_s *new_map_p;
+ struct eeprom_map_s *old_map_p = self->eeprom_map_p;
+ struct i2c_client *old_i2c_p = self->i2c_client_p;
+ int old_type = self->type;
+
+ /* Change state to STATE_TRANSVR_INIT */
+ self->state = STATE_TRANSVR_INIT;
+ self->type = new_type;
+ /* Replace EEPROME map */
+ new_map_p = get_eeprom_map(new_type);
+ if (!new_map_p){
+ goto err_private_reload_func_1;
+ }
+ self->eeprom_map_p = new_map_p;
+ /* Reload i2c client */
+ if (setup_i2c_client(self) < 0){
+ goto err_private_reload_func_2;
+ }
+ if (setup_transvr_private_cb(self, new_type) < 0){
+ goto err_private_reload_func_3;
+ }
+ kfree(old_i2c_p);
+ return 0;
+
+err_private_reload_func_3:
+ SWPS_INFO("%s: init() fail!\n", __func__);
+ kfree(old_i2c_p);
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ self->type = TRANSVR_TYPE_ERROR;
+ return -2;
+
+err_private_reload_func_2:
+ self->eeprom_map_p = old_map_p;
+ self->i2c_client_p = old_i2c_p;
+err_private_reload_func_1:
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ self->type = old_type;
+ SWPS_INFO("%s fail! :0x%02x\n", __func__, new_type);
+ return -1;
+}
+
+
+static int
+reload_transvr_obj(struct transvr_obj_s *self,
+ int new_type){
+
+ int result_val = ERR_TRANSVR_UNEXCPT;
+
+ /* Reload phase */
+ result_val = _reload_transvr_obj(self, new_type);
+ if (result_val < 0){
+ SWPS_INFO("%s: reload phase fail! :%d\n",
+ __func__, result_val);
+ return EVENT_TRANSVR_RELOAD_FAIL;
+ }
+ /* Initial phase */
+ result_val = _transvr_init_handler(self);
+ if (result_val < 0){
+ SWPS_INFO("%s: initial phase fail! :%d\n",
+ __func__, result_val);
+ }
+ return result_val;
+}
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h
new file mode 100644
index 0000000000..487fcdd767
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h
@@ -0,0 +1,167 @@
+#ifndef TRANSCEIVER_H
+#define TRANSCEIVER_H
+
+#include
+
+/* Transceiver type define */
+#define TRANSVR_TYPE_UNKNOW_1 (0x00)
+#define TRANSVR_TYPE_UNKNOW_2 (0xff)
+#define TRANSVR_TYPE_SFP (0x03) /* Define for SFP, SFP+, SFP28 */
+#define TRANSVR_TYPE_QSFP (0x0c)
+#define TRANSVR_TYPE_QSFP_PLUS (0x0d)
+#define TRANSVR_TYPE_QSFP_28 (0x11)
+#define TRANSVR_TYPE_UNPLUGGED (0xfa) /* Define for ERROR handle */
+#define TRANSVR_TYPE_FAKE (0xfc) /* Define for ERROR handle */
+#define TRANSVR_TYPE_INCONSISTENT (0xfd) /* Define for ERROR handle */
+#define TRANSVR_TYPE_ERROR (0xfe) /* Define for ERROR handle */
+
+/* Transceiver mode define */
+#define TRANSVR_MODE_DIRECT (21000)
+
+/* Transceiver state define
+ * [Note]
+ * 1. State is used to represent the state of "Transceiver" and "Object".
+ * 2. State for different target has different means. The description as following:
+ */
+#define STATE_TRANSVR_CONNECTED (0) /* [Transvr]:Be plugged in. [Obj]:Link up, and work normally. */
+#define STATE_TRANSVR_NEW (-100) /* [Transvr]:(Not used) [Obj]:Create */
+#define STATE_TRANSVR_INIT (-101) /* [Transvr]:Be plugged in. [Obj]:Link up, and in initial process. */
+#define STATE_TRANSVR_ISOLATED (-102) /* [Transvr]:Be plugged in. [Obj]:Isolate, and not provide service. */
+#define STATE_TRANSVR_SWAPPED (-200) /* [Transvr]:Be plugged in. [Obj]:(Not used) */
+#define STATE_TRANSVR_DISCONNECTED (-300) /* [Transvr]:Un-plugged. [Obj]:Link down, and not provide service. */
+#define STATE_TRANSVR_UNEXCEPTED (-901) /* [Transvr]:Any [Obj]:Any, and not in expect case. */
+
+/* Event for task handling */
+#define EVENT_TRANSVR_TASK_WAIT (2101)
+#define EVENT_TRANSVR_TASK_DONE (0)
+#define EVENT_TRANSVR_TASK_FAIL (-2101)
+/* Event for initial handling */
+#define EVENT_TRANSVR_INIT_UP (2201)
+#define EVENT_TRANSVR_INIT_DOWN (1)
+#define EVENT_TRANSVR_INIT_REINIT (-2201)
+#define EVENT_TRANSVR_INIT_FAIL (-2202)
+/* Event for others */
+#define EVENT_TRANSVR_RELOAD_FAIL (-2301)
+#define EVENT_TRANSVR_EXCEP_INIT (-2401)
+#define EVENT_TRANSVR_EXCEP_UP (-2402)
+#define EVENT_TRANSVR_EXCEP_DOWN (-2403)
+#define EVENT_TRANSVR_EXCEP_SWAP (-2404)
+#define EVENT_TRANSVR_EXCEP_EXCEP (-2405)
+#define EVENT_TRANSVR_EXCEP_ISOLATED (-2406)
+#define EVENT_TRANSVR_I2C_CRASH (-2501)
+
+/* Transceiver error code define */
+#define ERR_TRANSVR_UNINIT (-201)
+#define ERR_TRANSVR_UNPLUGGED (-202)
+#define ERR_TRANSVR_ABNORMAL (-203)
+#define ERR_TRANSVR_NOSTATE (-204)
+#define ERR_TRANSVR_NOTSUPPORT (-205)
+#define ERR_TRANSVR_BADINPUT (-206)
+#define ERR_TRANSVR_UPDATE_FAIL (-207)
+#define ERR_TRANSVR_RELOAD_FAIL (-208)
+#define ERR_TRANSVR_INIT_FAIL (-209)
+#define ERR_TRANSVR_UNDEFINED (-210)
+#define ERR_TRANSVR_TASK_FAIL (-211)
+#define ERR_TRANSVR_TASK_BUSY (-212)
+#define ERR_TRANSVR_FUNC_DISABLE (-214)
+#define ERR_TRANSVR_I2C_CRASH (-297)
+#define ERR_TRNASVR_BE_ISOLATED (-298)
+#define ERR_TRANSVR_UNEXCPT (-299)
+
+/* For debug */
+#define DEBUG_TRANSVR_INT_VAL (-99)
+#define DEBUG_TRANSVR_HEX_VAL (0xfe)
+#define DEBUG_TRANSVR_STR_VAL "ERROR"
+
+/* For system internal */
+#define VAL_TRANSVR_COMID_ARREESS (0x50)
+#define VAL_TRANSVR_COMID_OFFSET (0x00)
+#define VAL_TRANSVR_8472_READY_ADDR (0x51)
+#define VAL_TRANSVR_8472_READY_PAGE (-1)
+#define VAL_TRANSVR_8472_READY_OFFSET (110)
+#define VAL_TRANSVR_8472_READY_BIT (0)
+#define VAL_TRANSVR_8472_READY_VALUE (0)
+#define VAL_TRANSVR_8472_READY_ABNORMAL (0xff)
+#define VAL_TRANSVR_8436_READY_ADDR (0x50)
+#define VAL_TRANSVR_8436_READY_PAGE (-1)
+#define VAL_TRANSVR_8436_READY_OFFSET (2)
+#define VAL_TRANSVR_8436_READY_BIT (0)
+#define VAL_TRANSVR_8436_READY_VALUE (0)
+#define VAL_TRANSVR_8436_READY_ABNORMAL (0xff)
+#define VAL_TRANSVR_8436_PWD_ADDR (0x50)
+#define VAL_TRANSVR_8436_PWD_PAGE (-1)
+#define VAL_TRANSVR_8436_PWD_OFFSET (123)
+#define VAL_TRANSVR_PAGE_FREE (-99)
+#define VAL_TRANSVR_PAGE_SELECT_OFFSET (127)
+#define VAL_TRANSVR_PAGE_SELECT_DELAY (5)
+#define VAL_TRANSVR_TASK_RETRY_FOREVER (-999)
+#define VAL_TRANSVR_FUNCTION_DISABLE (-1)
+#define STR_TRANSVR_QSFP "QSFP"
+#define STR_TRANSVR_QSFP_PLUS "QSFP+"
+#define STR_TRANSVR_QSFP28 "QSFP28"
+
+/* BCM chip type define */
+#define BCM_CHIP_TYPE_TOMAHAWK (31002) /* Redwood, Cypress */
+
+/* Info from transceiver EEPROM */
+struct eeprom_map_s {
+ int addr_rx_los; int page_rx_los; int offset_rx_los; int length_rx_los;
+ int addr_tx_disable; int page_tx_disable; int offset_tx_disable; int length_tx_disable;
+ int addr_tx_fault; int page_tx_fault; int offset_tx_fault; int length_tx_fault;
+};
+
+/* Class of transceiver object */
+struct transvr_obj_s {
+ /* ========== Object private property ==========
+ */
+ struct device *transvr_dev_p;
+ struct eeprom_map_s *eeprom_map_p;
+ struct i2c_client *i2c_client_p;
+ struct ioexp_obj_s *ioexp_obj_p;
+ struct mutex lock;
+ char swp_name[32];
+ int auto_tx_disable;
+ int chan_id;
+ int chipset_type;
+ int curr_page;
+ int info;
+ int ioexp_virt_offset;
+ int lane_id[8];
+ int layout;
+ int mode;
+ int retry;
+ int state;
+ int temp;
+ int type;
+
+ /* ========== Object private functions ==========
+ */
+ int (*init)(struct transvr_obj_s *self);
+ int (*update_all)(struct transvr_obj_s *self, int show_err);
+ int (*fsm_4_direct)(struct transvr_obj_s* self, char *caller_name);
+};
+
+
+/* For AVL Mapping */
+struct transvr_avl_s {
+ char vendor_name[32];
+ char vendor_pn[32];
+ int (*init)(struct transvr_obj_s *self);
+};
+
+struct transvr_obj_s *
+create_transvr_obj(char *swp_name,
+ int chan_id,
+ struct ioexp_obj_s *ioexp_obj_p,
+ int ioexp_virt_offset,
+ int transvr_type,
+ int chipset_type,
+ int run_mode);
+
+void alarm_msg_2_user(struct transvr_obj_s *self, char *emsg);
+
+#endif /* TRANSCEIVER_H */
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py
new file mode 100755
index 0000000000..f6f5e46c55
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Inventec, Inc.
+#
+# 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 3 of the License, 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, see .
+
+"""
+Usage: %(scriptName)s [options] command object
+
+options:
+ -h | --help : this help message
+ -d | --debug : run with debug mode
+ -f | --force : ignore error during installation or clean
+command:
+ install : install drivers and generate related sysfs nodes
+ clean : uninstall drivers and remove related sysfs nodes
+"""
+
+import os
+import commands
+import sys, getopt
+import logging
+import re
+import time
+from collections import namedtuple
+
+DEBUG = False
+args = []
+FORCE = 0
+i2c_prefix = '/sys/bus/i2c/devices/'
+
+
+if DEBUG == True:
+ print sys.argv[0]
+ print 'ARGV :', sys.argv[1:]
+
+
+def main():
+ global DEBUG
+ global args
+ global FORCE
+
+ if len(sys.argv)<2:
+ show_help()
+
+ options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
+ 'debug',
+ 'force',
+ ])
+ if DEBUG == True:
+ print options
+ print args
+ print len(sys.argv)
+
+ for opt, arg in options:
+ if opt in ('-h', '--help'):
+ show_help()
+ elif opt in ('-d', '--debug'):
+ DEBUG = True
+ logging.basicConfig(level=logging.INFO)
+ elif opt in ('-f', '--force'):
+ FORCE = 1
+ else:
+ logging.info('no option')
+ for arg in args:
+ if arg == 'install':
+ install()
+ elif arg == 'clean':
+ uninstall()
+ else:
+ show_help()
+
+
+ return 0
+
+def show_help():
+ print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
+ sys.exit(0)
+
+def show_log(txt):
+ if DEBUG == True:
+ print "[D7032]"+txt
+ return
+
+def exec_cmd(cmd, show):
+ logging.info('Run :'+cmd)
+ status, output = commands.getstatusoutput(cmd)
+ show_log (cmd +"with result:" + str(status))
+ show_log (" output:"+output)
+ if status:
+ logging.info('Failed :'+cmd)
+ if show:
+ print('Failed :'+cmd)
+ return status, output
+
+instantiate =[
+#'echo pca9545 0x70> /sys/bus/i2c/devices/i2c-0/new_device',
+#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-1/new_device',
+#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-2/new_device',
+#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-3/new_device',
+#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-4/new_device',
+#'echo inv_psoc 0x66> /sys/bus/i2c/devices/i2c-5/new_device',
+#'echo inv_cpld 0x55> /sys/bus/i2c/devices/i2c-5/new_device',
+'echo inv_eeprom 0x53> /sys/bus/i2c/devices/i2c-0/new_device']
+
+drivers =[
+'lpc_ich',
+'i2c-i801',
+'i2c-mux',
+'i2c-mux-pca954x',
+'i2c-dev',
+'inv_eeprom',
+'inv_platform',
+'inv_psoc',
+'inv_cpld',
+'swps']
+
+
+
+def system_install():
+ global FORCE
+
+ #remove default drivers to avoid modprobe order conflicts
+ status, output = exec_cmd("rmmod i2c_ismt ", 1)
+ status, output = exec_cmd("rmmod i2c-i801 ", 1)
+ #install drivers
+ for i in range(0,len(drivers)):
+ status, output = exec_cmd("modprobe "+drivers[i], 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ #instantiate devices
+ for i in range(0,len(instantiate)):
+ time.sleep(1)
+ status, output = exec_cmd(instantiate[i], 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ for i in range(22,30):
+ status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-4/i2c-"+str(i)+"/new_device", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ for i in range(30,38):
+ status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-5/i2c-"+str(i)+"/new_device", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ for i in range(6,14):
+ status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-2/i2c-"+str(i)+"/new_device", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ for i in range(14,22):
+ status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-3/i2c-"+str(i)+"/new_device", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ return
+
+
+def system_ready():
+ if not device_found():
+ return False
+ return True
+
+def install():
+ if not device_found():
+ print "No device, installing...."
+ status = system_install()
+ if status:
+ if FORCE == 0:
+ return status
+ else:
+ print " D7032 devices detected...."
+ return
+
+def uninstall():
+ global FORCE
+ #uninstall drivers
+ for i in range(len(drivers)-1,-1,-1):
+ status, output = exec_cmd("rmmod "+drivers[i], 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ return
+
+def device_found():
+ ret1, log = exec_cmd("ls "+i2c_prefix+"*0072", 0)
+ ret2, log = exec_cmd("ls "+i2c_prefix+"i2c-2", 0)
+ return not(ret1 or ret2)
+
+if __name__ == "__main__":
+ main()
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom
deleted file mode 100755
index b8e3ba26a5..0000000000
Binary files a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom and /dev/null differ
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile
new file mode 100755
index 0000000000..aeffa43765
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile
@@ -0,0 +1,6 @@
+obj-m += inv_cpld.o inv_psoc.o
+obj-m += inv_platform.o
+obj-m += inv_eeprom.o
+obj-m += swps.o
+swps-objs := inv_swps.o io_expander.o transceiver.o
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c
new file mode 100644
index 0000000000..683ffa0ff3
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c
@@ -0,0 +1,415 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#include "I2CHostCommunication.h"
+
+#define USE_SMBUS 1
+
+/* definition */
+#define CPLD_INFO_OFFSET 0x00
+#define CPLD_PSU_OFFSET 0x08
+#define CPLD_LED_OFFSET 0x0E
+#define CPLD_LED_STATU_OFFSET 0x0D
+#define CPLD_CTL_OFFSET 0x0C
+
+
+
+/* Each client has this additional data */
+struct cpld_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+};
+
+/*-----------------------------------------------------------------------*/
+
+static ssize_t cpld_i2c_read(struct i2c_client *client, u8 *buf, u8 offset, size_t count)
+{
+#if USE_SMBUS
+ int i;
+
+ for(i=0; iaddr;
+ msg[0].buf = msgbuf;
+ msg[0].len = 1;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ status = i2c_transfer(client->adapter, msg, 2);
+
+ if(status == 2)
+ status = count;
+
+ return status;
+#endif
+}
+
+static ssize_t cpld_i2c_write(struct i2c_client *client, char *buf, unsigned offset, size_t count)
+{
+#if USE_SMBUS
+ int i;
+
+ for(i=0; iaddr;
+ msg.flags = 0;
+
+ /* msg.buf is u8 and casts will mask the values */
+ msg.buf = writebuf;
+
+ msg.buf[i++] = offset;
+ memcpy(&msg.buf[i], buf, count);
+ msg.len = i + count;
+
+ status = i2c_transfer(client->adapter, &msg, 1);
+ if (status == 1)
+ status = count;
+
+ return status;
+#endif
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t show_info(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u32 status;
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+ u8 b[4];
+
+ memset(b, 0, 4);
+
+ mutex_lock(&data->update_lock);
+ status = cpld_i2c_read(client, b, CPLD_INFO_OFFSET, 4);
+ mutex_unlock(&data->update_lock);
+
+ if(status != 4) return sprintf(buf, "read cpld info fail\n");
+
+ status = sprintf (buf, "The CPLD release date is %02d/%02d/%d.\n", b[2] & 0xf, (b[3] & 0x1f), 2014+(b[2] >> 4)); /* mm/dd/yyyy*/
+ status = sprintf (buf, "%sThe PCB version is %X%X\n", buf, b[0]>>4, b[0]&0xf);
+ status = sprintf (buf, "%sThe CPLD version is %d.%d\n", buf, b[1]>>4, b[1]&0xf);
+
+ return strlen(buf);
+}
+
+
+static ssize_t show_ctl(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u32 status;
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+ u8 b[1];
+
+ mutex_lock(&data->update_lock);
+
+ status = cpld_i2c_read(client, b, CPLD_CTL_OFFSET, 1);
+
+ mutex_unlock(&data->update_lock);
+
+ if(status != 1) return sprintf(buf, "read cpld ctl fail\n");
+
+
+ status = sprintf (buf, "0x%X\n", b[0]);
+
+ return strlen(buf);
+}
+
+static ssize_t set_ctl(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+ u8 byte;
+
+ u8 temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ cpld_i2c_read(client, &byte, CPLD_CTL_OFFSET, 1);
+ if(temp) byte |= (1<<0);
+ else byte &= ~(1<<0);
+ cpld_i2c_write(client, &byte, CPLD_CTL_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+
+static char* led_str[] = {
+ "OFF", //000
+ "0.5 Hz", //001
+ "1 Hz", //010
+ "2 Hz", //011
+ "NA", //100
+ "NA", //101
+ "NA", //110
+ "ON", //111
+};
+
+static ssize_t show_led(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u32 status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+ u8 byte;
+ int shift = (attr->index == 0)?3:0;
+
+ mutex_lock(&data->update_lock);
+ status = cpld_i2c_read(client, &byte, CPLD_LED_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ if(status != 1) return sprintf(buf, "read cpld offset 0x%x\n", CPLD_LED_OFFSET);
+
+ byte = (byte >> shift) & 0x7;
+
+ /*
+ 0: off
+ 1: 0.5hz
+ 2: 1 hz
+ 3: 2 hz
+ 4~6: not define
+ 7: on
+ */
+
+ status = sprintf (buf, "%d: %s\n", byte, led_str[byte]);
+
+ return strlen(buf);
+}
+
+static ssize_t set_led(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+
+ u8 temp = simple_strtol(buf, NULL, 16);
+ u8 byte;
+ int shift = (attr->index == 0)?3:0;
+
+ temp &= 0x7;
+ //validate temp value: 0,1,2,3,7, TBD
+
+ mutex_lock(&data->update_lock);
+ cpld_i2c_read(client, &byte, CPLD_LED_OFFSET, 1);
+ byte &= ~(0x7<update_lock);
+
+ return count;
+}
+
+/*
+CPLD report the PSU0 status
+000 = PSU normal operation
+100 = PSU fault
+010 = PSU unpowered
+111 = PSU not installed
+
+7 6 | 5 4 3 | 2 1 0
+----------------------
+ | psu0 | psu1
+*/
+static char* psu_str[] = {
+ "normal", //000
+ "NA", //001
+ "unpowered", //010
+ "NA", //011
+ "fault", //100
+ "NA", //101
+ "NA", //110
+ "not installed", //111
+};
+
+static ssize_t show_psu(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u32 status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpld_data *data = i2c_get_clientdata(client);
+ u8 byte;
+ int shift = (attr->index == 1)?0:3;
+
+ mutex_lock(&data->update_lock);
+ status = cpld_i2c_read(client, &byte, CPLD_PSU_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ byte = (byte >> shift) & 0x7;
+
+ status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]);
+
+ return strlen(buf);
+}
+
+
+static SENSOR_DEVICE_ATTR(info, S_IRUGO, show_info, 0, 0);
+static SENSOR_DEVICE_ATTR(ctl, S_IWUSR|S_IRUGO, show_ctl, set_ctl, 0);
+
+static SENSOR_DEVICE_ATTR(grn_led, S_IWUSR|S_IRUGO, show_led, set_led, 0);
+static SENSOR_DEVICE_ATTR(red_led, S_IWUSR|S_IRUGO, show_led, set_led, 1);
+
+static SENSOR_DEVICE_ATTR(psu0, S_IRUGO, show_psu, 0, 0);
+static SENSOR_DEVICE_ATTR(psu1, S_IRUGO, show_psu, 0, 1);
+
+static struct attribute *cpld_attributes[] = {
+ //info
+ &sensor_dev_attr_info.dev_attr.attr,
+ &sensor_dev_attr_ctl.dev_attr.attr,
+
+ &sensor_dev_attr_grn_led.dev_attr.attr,
+ &sensor_dev_attr_red_led.dev_attr.attr,
+
+ &sensor_dev_attr_psu0.dev_attr.attr,
+ &sensor_dev_attr_psu1.dev_attr.attr,
+
+ NULL
+};
+
+static const struct attribute_group cpld_group = {
+ .attrs = cpld_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int
+cpld_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct cpld_data *data;
+ int status;
+
+ printk("+%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ return -EIO;
+
+ data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Register sysfs hooks */
+ status = sysfs_create_group(&client->dev.kobj, &cpld_group);
+ if (status)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ status = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&client->dev, "%s: sensor '%s'\n",
+ dev_name(data->hwmon_dev), client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &cpld_group);
+exit_free:
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return status;
+}
+
+static int cpld_remove(struct i2c_client *client)
+{
+ struct cpld_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &cpld_group);
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return 0;
+}
+
+static const struct i2c_device_id cpld_ids[] = {
+ { "inv_cpld", 0, },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, cpld_ids);
+
+static struct i2c_driver cpld_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "inv_cpld",
+ },
+ .probe = cpld_probe,
+ .remove = cpld_remove,
+ .id_table = cpld_ids,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* module glue */
+
+static int __init inv_cpld_init(void)
+{
+ return i2c_add_driver(&cpld_driver);
+}
+
+static void __exit inv_cpld_exit(void)
+{
+ i2c_del_driver(&cpld_driver);
+}
+
+MODULE_AUTHOR("eddie.lan ");
+MODULE_DESCRIPTION("inv cpld driver");
+MODULE_LICENSE("GPL");
+
+module_init(inv_cpld_init);
+module_exit(inv_cpld_exit);
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c
new file mode 100644
index 0000000000..3d13f3b047
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c
@@ -0,0 +1,181 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* Size of EEPROM in bytes */
+#define EEPROM_SIZE 256
+
+#define SLICE_BITS (6)
+#define SLICE_SIZE (1 << SLICE_BITS)
+#define SLICE_NUM (EEPROM_SIZE/SLICE_SIZE)
+
+/* Each client has this additional data */
+struct eeprom_data {
+ struct mutex update_lock;
+ u8 valid; /* bitfield, bit!=0 if slice is valid */
+ unsigned long last_updated[SLICE_NUM]; /* In jiffies, 8 slices */
+ u8 data[EEPROM_SIZE]; /* Register values */
+};
+
+
+static void inv_eeprom_update_client(struct i2c_client *client, u8 slice)
+{
+ struct eeprom_data *data = i2c_get_clientdata(client);
+ int i, j;
+ int ret;
+ int addr;
+
+
+ mutex_lock(&data->update_lock);
+
+ if (!(data->valid & (1 << slice)) ||
+ time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
+ dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
+
+ addr = slice << SLICE_BITS;
+
+ ret = i2c_smbus_write_byte_data(client, ((u8)addr >> 8) & 0xFF, (u8)addr & 0xFF);
+ /* select the eeprom address */
+ if (ret < 0) {
+ dev_err(&client->dev, "address set failed\n");
+ goto exit;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
+ goto exit;
+ }
+
+ for (i = slice << SLICE_BITS; i < (slice + 1) << SLICE_BITS; i+= SLICE_SIZE) {
+ for (j = i; j < (i+SLICE_SIZE); j++) {
+ int res;
+
+ res = i2c_smbus_read_byte(client);
+ if (res < 0) {
+ goto exit;
+ }
+
+ data->data[j] = res & 0xFF;
+ }
+ }
+
+ data->last_updated[slice] = jiffies;
+ data->valid |= (1 << slice);
+ }
+
+exit:
+ mutex_unlock(&data->update_lock);
+}
+
+static ssize_t inv_eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
+ struct eeprom_data *data = i2c_get_clientdata(client);
+ u8 slice;
+
+
+ if (off > EEPROM_SIZE) {
+ return 0;
+ }
+ if (off + count > EEPROM_SIZE) {
+ count = EEPROM_SIZE - off;
+ }
+ if (count == 0) {
+ return 0;
+ }
+
+ /* Only refresh slices which contain requested bytes */
+ for (slice = off >> SLICE_BITS; slice <= (off + count - 1) >> SLICE_BITS; slice++) {
+ inv_eeprom_update_client(client, slice);
+ }
+
+ memcpy(buf, &data->data[off], count);
+
+ return count;
+}
+
+static struct bin_attribute inv_eeprom_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO,
+ },
+ .size = EEPROM_SIZE,
+ .read = inv_eeprom_read,
+};
+
+static int inv_eeprom_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct eeprom_data *data;
+ int err;
+
+ if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ memset(data->data, 0xff, EEPROM_SIZE);
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* create the sysfs eeprom file */
+ err = sysfs_create_bin_file(&client->dev.kobj, &inv_eeprom_attr);
+ if (err) {
+ goto exit_kfree;
+ }
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int inv_eeprom_remove(struct i2c_client *client)
+{
+ sysfs_remove_bin_file(&client->dev.kobj, &inv_eeprom_attr);
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static const struct i2c_device_id inv_eeprom_id[] = {
+ { "inv_eeprom", 0 },
+ { }
+};
+
+static struct i2c_driver inv_eeprom_driver = {
+ .driver = {
+ .name = "inv_eeprom",
+ },
+ .probe = inv_eeprom_probe,
+ .remove = inv_eeprom_remove,
+ .id_table = inv_eeprom_id,
+};
+
+module_i2c_driver(inv_eeprom_driver);
+
+MODULE_AUTHOR("Inventec");
+MODULE_DESCRIPTION("Inventec D7054 Mother Board EEPROM driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c
new file mode 100644
index 0000000000..ea26970075
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c
@@ -0,0 +1,219 @@
+#include
+//#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+//#include
+//#include
+
+//#include
+//#define IO_EXPAND_BASE 64
+//#define IO_EXPAND_NGPIO 16
+
+struct inv_i2c_board_info {
+ int ch;
+ int size;
+ struct i2c_board_info *board_info;
+};
+
+#define bus_id(id) (id)
+static struct pca954x_platform_mode mux_modes_0[] = {
+ {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),},
+ {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),},
+ {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),},
+ {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),},
+};
+static struct pca954x_platform_mode mux_modes_0_0[] = {
+ {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),},
+ {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),},
+ {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),},
+ {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_1[] = {
+ {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),},
+ {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),},
+ {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),},
+ {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_2[] = {
+ {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),},
+ {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),},
+ {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),},
+ {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_3[] = {
+ {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),},
+ {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),},
+ {.adap_id = bus_id(38),}, {.adap_id = bus_id(39),},
+ {.adap_id = bus_id(40),}, {.adap_id = bus_id(41),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_4[] = {
+ {.adap_id = bus_id(42),}, {.adap_id = bus_id(43),},
+ {.adap_id = bus_id(44),}, {.adap_id = bus_id(45),},
+ {.adap_id = bus_id(46),}, {.adap_id = bus_id(47),},
+ {.adap_id = bus_id(48),}, {.adap_id = bus_id(49),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_5[] = {
+ {.adap_id = bus_id(50),}, {.adap_id = bus_id(51),},
+ {.adap_id = bus_id(52),}, {.adap_id = bus_id(53),},
+ {.adap_id = bus_id(54),}, {.adap_id = bus_id(55),},
+ {.adap_id = bus_id(56),}, {.adap_id = bus_id(57),},
+};
+
+static struct pca954x_platform_mode mux_modes_0_6[] = {
+ {.adap_id = bus_id(58),}, {.adap_id = bus_id(59),},
+ {.adap_id = bus_id(60),}, {.adap_id = bus_id(61),},
+ {.adap_id = bus_id(62),}, {.adap_id = bus_id(63),},
+ {.adap_id = bus_id(64),}, {.adap_id = bus_id(65),},
+};
+
+//no i2c device driver attach to mux 7
+
+
+static struct pca954x_platform_data mux_data_0 = {
+ .modes = mux_modes_0,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_0 = {
+ .modes = mux_modes_0_0,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_1 = {
+ .modes = mux_modes_0_1,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_2 = {
+ .modes = mux_modes_0_2,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_3 = {
+ .modes = mux_modes_0_3,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_4 = {
+ .modes = mux_modes_0_4,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_5 = {
+ .modes = mux_modes_0_5,
+ .num_modes = 8,
+};
+static struct pca954x_platform_data mux_data_0_6 = {
+ .modes = mux_modes_0_6,
+ .num_modes = 8,
+};
+
+static struct i2c_board_info i2c_device_info0[] __initdata = {
+ {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc
+ {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld
+ {"pca9548", 0, 0x71, &mux_data_0, 0, 0},
+};
+
+static struct i2c_board_info i2c_device_info2[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0},
+};
+static struct i2c_board_info i2c_device_info3[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0},
+};
+static struct i2c_board_info i2c_device_info4[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0},
+};
+static struct i2c_board_info i2c_device_info5[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0},
+};
+static struct i2c_board_info i2c_device_info6[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_4, 0, 0},
+};
+static struct i2c_board_info i2c_device_info7[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_5, 0, 0},
+};
+static struct i2c_board_info i2c_device_info8[] __initdata = {
+ {"pca9548", 0, 0x72, &mux_data_0_6, 0, 0},
+};
+
+
+static struct inv_i2c_board_info i2cdev_list[] = {
+ {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0
+
+ {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0
+ {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1
+ {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2
+ {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3
+ {bus_id(6), ARRAY_SIZE(i2c_device_info6), i2c_device_info6 }, //mux 4
+ {bus_id(7), ARRAY_SIZE(i2c_device_info7), i2c_device_info7 }, //mux 5
+ {bus_id(8), ARRAY_SIZE(i2c_device_info8), i2c_device_info8 }, //mux 6
+
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+#if 0
+static struct i2c_gpio_platform_data i2c_gpio_platdata0 = {
+ .scl_pin = 58,
+ .sda_pin = 75,
+
+ .udelay = 5, //5:100kHz
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+ .scl_is_output_only = 0
+};
+
+static struct platform_device device_i2c_gpio0 = {
+ .name = "i2c-gpio",
+ .id = 0, // adapter number
+ .dev.platform_data = &i2c_gpio_platdata0,
+};
+#endif
+static int __init inv_platform_init(void)
+{
+ struct i2c_adapter *adap = NULL;
+ struct i2c_client *e = NULL;
+ int ret = 0;
+ int i,j;
+
+ printk("%s \n", __func__);
+
+#if 0
+ //use i2c-gpio
+ //register i2c gpio
+ //config gpio58,75 to gpio function 58=32+3*8+2 75=32*2+8*1+3
+ outl( inl(0x533) | (1<<2), 0x533);
+ outl( inl(0x541) | (1<<3), 0x541);
+
+ ret = platform_device_register(&device_i2c_gpio0);
+ if (ret) {
+ printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret);
+ }
+ #endif
+ for(i=0; i
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#include "I2CHostCommunication.h"
+
+#define IMPLEMENT_IPMI_CODE 1
+int USE_IPMI=0;
+//=================================
+#if IMPLEMENT_IPMI_CODE
+#include
+#include
+#include
+#include
+
+#define IPMI_MAX_INTF (4)
+#define NETFN_OEM 0x30
+#define CMD_GETDATA 0x31
+#define CMD_SETDATA 0x32
+
+struct mutex ipmi_mutex;
+
+static void msg_handler(struct ipmi_recv_msg *msg,void* handler_data);
+static ipmi_user_t ipmi_mh_user = NULL;
+static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = msg_handler,};
+
+static atomic_t dummy_count = ATOMIC_INIT(0);
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+ atomic_dec(&dummy_count);
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+ atomic_dec(&dummy_count);
+}
+static struct ipmi_smi_msg halt_smi_msg = {
+ .done = dummy_smi_free
+};
+static struct ipmi_recv_msg halt_recv_msg = {
+ .done = dummy_recv_free
+};
+#endif
+//=================================
+
+#define USE_SMBUS 1
+
+#define FAN_NUM 4
+#define PSU_NUM 2
+
+struct __attribute__ ((__packed__)) psoc_psu_layout {
+ u16 psu1_iin;
+ u16 psu2_iin;
+ u16 psu1_iout;
+ u16 psu2_iout;
+
+ u16 psu1_pin;
+ u16 psu2_pin;
+ u16 psu1_pout;
+ u16 psu2_pout;
+
+ u16 psu1_vin;
+ u16 psu2_vin;
+ u16 psu1_vout;
+ u16 psu2_vout;
+};
+
+struct __attribute__ ((__packed__)) psoc_layout {
+ u8 ctl; //offset: 0
+ u16 switch_temp; //offset: 1
+ u8 reserve0; //offset: 3
+
+ u8 fw_upgrade; //offset: 4
+
+ //i2c bridge
+ u8 i2c_st; //offset: 5
+ u8 i2c_ctl; //offset: 6
+ u8 i2c_addr; //offset: 7
+ u8 i2c_data[0x20]; //offset: 8
+
+ //gpo
+ u8 led_ctl; //offset: 28
+
+ u8 gpio; //offset: 29
+
+ //pwm duty
+ u8 pwm[FAN_NUM]; //offset: 2a
+ u8 pwm_psu[PSU_NUM]; //offset: 2e
+
+ //fan rpm
+ u16 fan[FAN_NUM*2]; //offset: 30
+
+ u8 reserve1[4]; //offset: 40
+
+ //gpi
+ u8 gpi_fan; //offset: 44
+
+ //psu state
+ u8 psu_state; //offset: 45
+
+ //temperature
+ u16 temp[5]; //offset: 46
+ u16 temp_psu[PSU_NUM]; //offset: 50
+
+ //version
+ u8 version[2]; //offset: 54
+
+ u8 reserve2[4]; //offset: 56
+ struct psoc_psu_layout psu_info; //offset: 5a
+};
+
+/* definition */
+/* definition */
+#define PSOC_OFF(m) offsetof(struct psoc_layout, m)
+#define PSOC_PSU_OFF(m) offsetof(struct psoc_psu_layout, m)
+
+#define SWITCH_TMP_OFFSET PSOC_OFF(switch_temp)
+#define PWM_OFFSET PSOC_OFF(pwm)
+#define THERMAL_OFFSET PSOC_OFF(temp)
+#define RPM_OFFSET PSOC_OFF(fan)
+#define DIAG_FLAG_OFFSET PSOC_OFF(ctl)
+#define FAN_LED_OFFSET PSOC_OFF(led_ctl)
+#define FAN_GPI_OFFSET PSOC_OFF(gpi_fan)
+#define PSOC_PSU_OFFSET PSOC_OFF(psu_state)
+#define VERSION_OFFSET PSOC_OFF(version)
+#define PSU_INFO_OFFSET PSOC_OFF(psu_info)
+
+/* Each client has this additional data */
+struct psoc_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ u32 diag;
+};
+
+/*-----------------------------------------------------------------------*/
+#if IMPLEMENT_IPMI_CODE
+static void msg_handler(struct ipmi_recv_msg *recv_msg,void* handler_data)
+{
+ struct completion *comp = recv_msg->user_msg_data;
+ if (comp)
+ complete(comp);
+ else
+ ipmi_free_recv_msg(recv_msg);
+ return;
+}
+
+int ipmi_command(char NetFn, char cmd,char *data,int data_length, char* result, int* result_length)
+{
+ int rv=0,i;
+ struct ipmi_system_interface_addr addr;
+ uint8_t _data[data_length];
+ struct kernel_ipmi_msg msg;
+ struct completion comp;
+
+ if(!mutex_trylock(&ipmi_mutex)) return 0;
+
+// for (i=0,rv=1; iaddr;
+ msg[0].buf = msgbuf;
+ msg[0].len = 1;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ status = i2c_transfer(client->adapter, msg, 2);
+
+ if(status == 2)
+ status = count;
+
+ return status;
+#endif
+}
+
+static ssize_t psoc_i2c_write(struct i2c_client *client, char *buf, unsigned offset, size_t count)
+{
+#if USE_SMBUS
+if(USE_IPMI==0)
+{
+ int i;
+
+ for(i=0; iaddr;
+ msg.flags = 0;
+
+ /* msg.buf is u8 and casts will mask the values */
+ msg.buf = writebuf;
+
+ msg.buf[i++] = offset;
+ memcpy(&msg.buf[i], buf, count);
+ msg.len = i + count;
+
+ status = i2c_transfer(client->adapter, &msg, 1);
+ if (status == 1)
+ status = count;
+
+ return status;
+#endif
+}
+
+#if 0
+static u32 psoc_read32(struct i2c_client *client, u8 offset)
+{
+ u32 value = 0;
+ u8 buf[4];
+
+ if( psoc_i2c_read(client, buf, offset, 4) == 4)
+ value = (buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]);
+
+ return value;
+}
+#endif
+
+static u16 psoc_read16(struct i2c_client *client, u8 offset)
+{
+ u16 value = 0;
+ u8 buf[2];
+
+ if(psoc_i2c_read(client, buf, offset, 2) == 2)
+ value = (buf[0]<<8 | buf[1]<<0);
+
+ return value;
+}
+
+static u8 psoc_read8(struct i2c_client *client, u8 offset)
+{
+ u8 value = 0;
+ u8 buf = 0;
+
+ if(psoc_i2c_read(client, &buf, offset, 1) == 1)
+ value = buf;
+
+ return value;
+}
+
+//PSOC i2c bridge regsters
+#define PSOC_I2C_STATUS 0x05
+#define PSOC_I2C_CNTRL 0x06
+#define PSOC_I2C_ADDR 0x07
+#define PSOC_I2C_DATA 0x08
+
+//status bit definition
+#define PSOC_I2C_START (1 << 0)
+#define PSOC_PMB_SEL (1 << 7)
+
+//addr bits definition
+#define PSOC_I2C_READ (1 << 0)
+
+//PMBUS registers definition
+#define PMBUS_READ_VIN (0x88)
+#define PMBUS_READ_IIN (0x89)
+#define PMBUS_READ_VOUT (0x8B)
+#define PMBUS_READ_IOUT (0x8C)
+#define PMBUS_READ_POUT (0x96)
+#define PMBUS_READ_PIN (0x97)
+
+/*
+CPLD report the PSU0 status
+000 = PSU normal operation
+100 = PSU fault
+010 = PSU unpowered
+111 = PSU not installed
+
+7 6 | 5 4 3 | 2 1 0
+----------------------
+ | psu1 | psu0
+*/
+static char* psu_str[] = {
+ "normal", //000
+ "NA", //001
+ "unpowered", //010
+ "NA", //011
+ "fault", //100
+ "NA", //101
+ "NA", //110
+ "not installed", //111
+};
+
+static ssize_t show_psu_st(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u32 status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 byte;
+ int shift = (attr->index == 0)?3:0;
+
+ mutex_lock(&data->update_lock);
+ status = psoc_i2c_read(client, &byte, PSOC_PSU_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ byte = (byte >> shift) & 0x7;
+
+ status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]);
+
+ return strlen(buf);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+#define PSU1 0x5800
+#define PSU2 0x5900
+#define BMC_I2cBus 3 //BMC's I2C-1
+#define PMBus_Vender 0x99
+#define PMBus_Serial 0x9E
+#define PMBus_Temp2 0x8E
+#define PMBus_Version 0x9B
+#define MaxLeng_Result 0x20
+#define MaxLog
+static long pmbus_reg2data_linear(int data, int linear16);
+
+
+static ssize_t show_ipmi_i2c(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ uint8_t data[4],result[MaxLeng_Result];
+ int result_len;
+
+ data[0] = BMC_I2cBus;
+ data[1] = (attr->index & 0xFF00 ) >>7;
+ data[3] = attr->index & 0xff;
+ if(data[3]==PMBus_Temp2)
+ data[2]=2;
+ else
+ data[2]=MaxLeng_Result;
+
+ if(ipmi_command(0x06, 0x52,data,4, result, &result_len)==0)
+ {
+ if(data[3]==PMBus_Temp2)
+ {
+ return sprintf(buf, "%ld \n", pmbus_reg2data_linear(result[0] | (result[1]<<8), 0 ));
+ }
+ result[result[0]+1]='\0';
+
+ return sprintf(buf, "%s\n",&result[1] );
+ }
+ else
+ return 0;
+}
+
+static ssize_t show_ipmi_sollog(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ uint8_t data[5],result[256];
+ int result_len;
+ uint32_t i;
+
+ for(i=0;i<0xffffff;i+=255)
+ {
+ data[0] = attr->index;
+ data[1] = (i & 0x0000ff);
+ data[2] = (i & 0x00ff00)>>8;
+ data[3] = (i & 0xff0000)>>16;
+ data[4] = 0;
+
+ result_len=0;
+
+ if(ipmi_command(0x32, 0xFE, data, 5, result, &result_len)==0)
+ {
+ if(result_len==0) break;
+ result[result_len+1]='\0';
+ printk("%s",result);
+ }
+ else break;
+
+ if(result_len==0) break;
+ }
+
+ return 0;
+}
+
+static ssize_t show_thermal(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u16 status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index * 2 + THERMAL_OFFSET;
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read16(client, offset);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n",
+ (s8)(status>>8) * 1000 );
+}
+
+
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ int status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index + PWM_OFFSET;
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read8(client, offset);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n",
+ status);
+}
+
+static ssize_t set_pwm(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index + PWM_OFFSET;
+
+ u8 pwm = simple_strtol(buf, NULL, 10);
+ if(pwm > 255) pwm = 255;
+
+ if(data->diag) {
+ mutex_lock(&data->update_lock);
+ psoc_i2c_write(client, &pwm, offset, 1);
+ mutex_unlock(&data->update_lock);
+ }
+
+ return count;
+}
+
+
+static ssize_t show_rpm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ int status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index*2 + RPM_OFFSET;
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read16(client, offset);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n",
+ status);
+}
+
+static ssize_t show_switch_tmp(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u16 status;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u16 temp = 0;
+
+ mutex_lock(&data->update_lock);
+ status = psoc_i2c_read(client, (u8*)&temp, SWITCH_TMP_OFFSET, 2);
+ mutex_unlock(&data->update_lock);
+
+ status = sprintf (buf, "%d\n", (s8)(temp>>8) * 1000 );
+
+ return strlen(buf);
+}
+
+static ssize_t set_switch_tmp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+
+ long temp = simple_strtol(buf, NULL, 10);
+ u16 temp2 = ( (temp/1000) <<8 ) & 0xFF00 ;
+
+ //printk("set_switch_tmp temp=%d, temp2=0x%x (%x,%x)\n", temp, temp2, ( ( (temp/1000) <<8 ) & 0xFF00 ), (( (temp%1000) / 10 ) & 0xFF));
+
+ mutex_lock(&data->update_lock);
+ psoc_i2c_write(client, (u8*)&temp2, SWITCH_TMP_OFFSET, 2);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_diag(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u16 status;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 diag_flag = 0;
+
+ mutex_lock(&data->update_lock);
+ status = psoc_i2c_read(client, (u8*)&diag_flag, DIAG_FLAG_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ data->diag = (diag_flag & 0x80)?1:0;
+ status = sprintf (buf, "%d\n", data->diag);
+
+ return strlen(buf);
+}
+
+static ssize_t set_diag(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 value = 0;
+ u8 diag = simple_strtol(buf, NULL, 10);
+
+ diag = diag?1:0;
+ data->diag = diag;
+
+ mutex_lock(&data->update_lock);
+ psoc_i2c_read(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
+ if(diag) value |= (1<<7);
+ else value &= ~(1<<7);
+ psoc_i2c_write(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_version(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u16 status;
+ //struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read16(client, VERSION_OFFSET);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "ver: %x.%x\n", (status & 0xFF00)>>8, (status & 0xFF) );
+}
+
+
+static ssize_t show_fan_led(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ int status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 bit = attr->index;
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read8(client, FAN_LED_OFFSET);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n",
+ (status & (1<index;
+ u8 led_state = 0;
+
+ u8 v = simple_strtol(buf, NULL, 10);
+
+ if(data->diag) {
+ mutex_lock(&data->update_lock);
+ led_state = psoc_read8(client, FAN_LED_OFFSET);
+ if(v) led_state |= (1<update_lock);
+ }
+
+ return count;
+}
+
+static ssize_t show_value8(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ int status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index;
+
+ mutex_lock(&data->update_lock);
+
+ status = psoc_read8(client, offset);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "0x%02X\n", status );
+}
+
+static long pmbus_reg2data_linear(int data, int linear16)
+{
+ s16 exponent;
+ s32 mantissa;
+ long val;
+
+ if (linear16) { /* LINEAR16 */
+ exponent = -9;
+ mantissa = (u16) data;
+ } else { /* LINEAR11 */
+ exponent = ((s16)data) >> 11;
+ exponent = ((s16)( data & 0xF800) ) >> 11;
+ mantissa = ((s32)((data & 0x7ff) << 5)) >> 5;
+ }
+
+ //printk("data=%d, m=%d, e=%d\n", data, exponent, mantissa);
+ val = mantissa;
+
+ /* scale result to micro-units for power sensors */
+ val = val * 1000L;
+
+ if (exponent >= 0)
+ val <<= exponent;
+ else
+ val >>= -exponent;
+
+ return val;
+}
+
+static ssize_t show_psu_psoc(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ u16 status;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct psoc_data *data = i2c_get_clientdata(client);
+ u8 offset = attr->index + PSU_INFO_OFFSET;
+
+ mutex_lock(&data->update_lock);
+ status = psoc_read16(client, offset);
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%ld \n", pmbus_reg2data_linear(status, strstr(attr->dev_attr.attr.name, "vout")? 1:0 ));
+}
+
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_thermal, 0, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_thermal, 0, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_thermal, 0, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_thermal, 0, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_thermal, 0, 4);
+static SENSOR_DEVICE_ATTR(thermal_psu1, S_IRUGO, show_thermal, 0, 5);
+static SENSOR_DEVICE_ATTR(thermal_psu2, S_IRUGO, show_thermal, 0, 6);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm_psu1, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 4);
+static SENSOR_DEVICE_ATTR(pwm_psu2, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 5);
+
+static SENSOR_DEVICE_ATTR(psu0, S_IRUGO, show_psu_st, 0, 0);
+static SENSOR_DEVICE_ATTR(psu1, S_IRUGO, show_psu_st, 0, 1);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, 0, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_rpm, 0, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_rpm, 0, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_rpm, 0, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_rpm, 0, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_rpm, 0, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_rpm, 0, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_rpm, 0, 7);
+static SENSOR_DEVICE_ATTR(rpm_psu1, S_IRUGO, show_rpm, 0, 8);
+static SENSOR_DEVICE_ATTR(rpm_psu2, S_IRUGO, show_rpm, 0, 9);
+
+static SENSOR_DEVICE_ATTR(switch_tmp, S_IWUSR|S_IRUGO, show_switch_tmp, set_switch_tmp, 0);
+
+static SENSOR_DEVICE_ATTR(diag, S_IWUSR|S_IRUGO, show_diag, set_diag, 0);
+static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, 0, 0);
+
+static SENSOR_DEVICE_ATTR(fan_led_grn1, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 0);
+static SENSOR_DEVICE_ATTR(fan_led_grn2, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 1);
+static SENSOR_DEVICE_ATTR(fan_led_grn3, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 2);
+static SENSOR_DEVICE_ATTR(fan_led_grn4, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 3);
+static SENSOR_DEVICE_ATTR(fan_led_red1, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 4);
+static SENSOR_DEVICE_ATTR(fan_led_red2, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 5);
+static SENSOR_DEVICE_ATTR(fan_led_red3, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 6);
+static SENSOR_DEVICE_ATTR(fan_led_red4, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 7);
+
+static SENSOR_DEVICE_ATTR(fan_gpi, S_IRUGO, show_value8, 0, FAN_GPI_OFFSET);
+static SENSOR_DEVICE_ATTR(psoc_psu1_vin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vin));
+static SENSOR_DEVICE_ATTR(psoc_psu1_vout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vout));
+static SENSOR_DEVICE_ATTR(psoc_psu1_iin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iin));
+static SENSOR_DEVICE_ATTR(psoc_psu1_iout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iout));
+static SENSOR_DEVICE_ATTR(psoc_psu1_pin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pin));
+static SENSOR_DEVICE_ATTR(psoc_psu1_pout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pout));
+
+
+static SENSOR_DEVICE_ATTR(psoc_psu2_vin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vin));
+static SENSOR_DEVICE_ATTR(psoc_psu2_vout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vout));
+static SENSOR_DEVICE_ATTR(psoc_psu2_iin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iin));
+static SENSOR_DEVICE_ATTR(psoc_psu2_iout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iout));
+static SENSOR_DEVICE_ATTR(psoc_psu2_pin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pin));
+static SENSOR_DEVICE_ATTR(psoc_psu2_pout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pout));
+
+//IPMI
+static SENSOR_DEVICE_ATTR(thermal2_psu1, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Temp2);
+static SENSOR_DEVICE_ATTR(psoc_psu1_vender, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Vender);
+static SENSOR_DEVICE_ATTR(psoc_psu1_serial, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Serial);
+static SENSOR_DEVICE_ATTR(psoc_psu1_version, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Version);
+
+static SENSOR_DEVICE_ATTR(thermal2_psu2, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Temp2);
+static SENSOR_DEVICE_ATTR(psoc_psu2_vender, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Vender);
+static SENSOR_DEVICE_ATTR(psoc_psu2_serial, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Serial);
+static SENSOR_DEVICE_ATTR(psoc_psu2_version, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Version);
+
+static SENSOR_DEVICE_ATTR(sollog1, S_IRUGO, show_ipmi_sollog, 0, 1);
+static SENSOR_DEVICE_ATTR(sollog2, S_IRUGO, show_ipmi_sollog, 0, 2);
+
+static struct attribute *psoc_attributes[] = {
+ //thermal
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+
+ &sensor_dev_attr_thermal_psu1.dev_attr.attr,
+ &sensor_dev_attr_thermal_psu2.dev_attr.attr,
+
+
+ //pwm
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm_psu1.dev_attr.attr,
+ &sensor_dev_attr_pwm_psu2.dev_attr.attr,
+
+ //rpm
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan8_input.dev_attr.attr,
+
+ &sensor_dev_attr_rpm_psu1.dev_attr.attr,
+ &sensor_dev_attr_rpm_psu2.dev_attr.attr,
+
+ //switch temperature
+ &sensor_dev_attr_switch_tmp.dev_attr.attr,
+
+ //diag flag
+ &sensor_dev_attr_diag.dev_attr.attr,
+
+ //version
+ &sensor_dev_attr_version.dev_attr.attr,
+
+ //fan led
+ &sensor_dev_attr_fan_led_grn1.dev_attr.attr,
+ &sensor_dev_attr_fan_led_grn2.dev_attr.attr,
+ &sensor_dev_attr_fan_led_grn3.dev_attr.attr,
+ &sensor_dev_attr_fan_led_grn4.dev_attr.attr,
+ &sensor_dev_attr_fan_led_red1.dev_attr.attr,
+ &sensor_dev_attr_fan_led_red2.dev_attr.attr,
+ &sensor_dev_attr_fan_led_red3.dev_attr.attr,
+ &sensor_dev_attr_fan_led_red4.dev_attr.attr,
+
+ //fan GPI
+ &sensor_dev_attr_fan_gpi.dev_attr.attr,
+ &sensor_dev_attr_psu0.dev_attr.attr,
+ &sensor_dev_attr_psu1.dev_attr.attr,
+
+
+ //psu_psoc, new added on psoc 1.9
+ &sensor_dev_attr_psoc_psu1_vin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_vout.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_iin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_iout.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_pin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_pout.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_vin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_vout.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_iin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_iout.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_pin.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_pout.dev_attr.attr,
+
+ //ipmi_command
+ &sensor_dev_attr_thermal2_psu1.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_vender.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_serial.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu1_version.dev_attr.attr,
+
+ &sensor_dev_attr_thermal2_psu2.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_vender.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_serial.dev_attr.attr,
+ &sensor_dev_attr_psoc_psu2_version.dev_attr.attr,
+
+ &sensor_dev_attr_sollog1.dev_attr.attr,
+ &sensor_dev_attr_sollog2.dev_attr.attr,
+
+ NULL
+};
+
+static const struct attribute_group psoc_group = {
+ .attrs = psoc_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int
+psoc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct psoc_data *data;
+ int status,i,rv;
+
+ printk("+%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ return -EIO;
+
+ data = kzalloc(sizeof(struct psoc_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+ data->diag = 0;
+
+#if IMPLEMENT_IPMI_CODE
+ for (i=0,rv=1; idev.kobj, &psoc_group);
+ if (status)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ status = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&client->dev, "%s: sensor '%s'\n",
+ dev_name(data->hwmon_dev), client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &psoc_group);
+exit_free:
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return status;
+}
+
+static int psoc_remove(struct i2c_client *client)
+{
+ struct psoc_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &psoc_group);
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return 0;
+}
+
+static const struct i2c_device_id psoc_ids[] = {
+ { "inv_psoc", 0, },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, psoc_ids);
+
+static struct i2c_driver psoc_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "inv_psoc",
+ },
+ .probe = psoc_probe,
+ .remove = psoc_remove,
+ .id_table = psoc_ids,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* module glue */
+
+static int __init inv_psoc_init(void)
+{
+ return i2c_add_driver(&psoc_driver);
+}
+
+static void __exit inv_psoc_exit(void)
+{
+ i2c_del_driver(&psoc_driver);
+}
+
+MODULE_AUTHOR("eddie.lan ");
+MODULE_DESCRIPTION("inv psoc driver");
+MODULE_LICENSE("GPL");
+
+module_init(inv_psoc_init);
+module_exit(inv_psoc_exit);
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c
new file mode 100644
index 0000000000..08bd490e63
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c
@@ -0,0 +1,730 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "inv_swps.h"
+
+static int port_major;
+static int ioexp_total;
+static int port_total;
+static struct class *swp_class_p = NULL;
+static struct inv_platform_s *platform_p = NULL;
+static struct inv_ioexp_layout_s *ioexp_layout = NULL;
+static struct inv_port_layout_s *port_layout = NULL;
+
+static int
+__swp_match(struct device *dev,
+#ifdef SWPS_KERN_VER_AF_3_10
+
+ const void *data){
+#else
+ void *data){
+#endif
+
+ char *name = (char *)data;
+ if (strcmp(dev_name(dev), name) == 0)
+ return 1;
+ return 0;
+}
+
+
+struct device *
+get_swpdev_by_name(char *name){
+ struct device *dev = class_find_device(swp_class_p,
+ NULL,
+ name,
+ (const void *)__swp_match);
+ return dev;
+}
+
+
+static int
+sscanf_2_int(const char *buf) {
+
+ int result = -EBFONT;
+ char *hex_tag = "0x";
+
+ if (strcspn(buf, hex_tag) == 0) {
+ if (sscanf(buf,"%x",&result)) {
+ return result;
+ }
+ } else {
+ if (sscanf(buf,"%d",&result)) {
+ return result;
+ }
+ if(sscanf(buf,"-%d",&result)) {
+ return -result;
+ }
+ if (sscanf(buf,"%x",&result)) {
+ return result;
+ }
+ }
+ return -EBFONT;
+}
+
+
+static int
+sscanf_2_binary(const char *buf) {
+
+ int result = sscanf_2_int(buf);
+
+ if (result < 0){
+ return -EBFONT;
+ }
+ switch (result) {
+ case 0:
+ case 1:
+ return result;
+ default:
+ break;
+ }
+ return -EBFONT;
+}
+
+/* ========== Show functions: For I/O Expander attribute ==========
+ */
+static ssize_t
+_show_ioexp_binary_attr(struct transvr_obj_s *tobj_p,
+ int (*get_func)(struct ioexp_obj_s *ioexp_p, int voffset),
+ char *buf_p) {
+ size_t len;
+ struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ SWPS_ERR(" %s: data corruption! :%s\n", __func__, tobj_p->swp_name);
+ return -ENODATA;
+ }
+ mutex_lock(&ioexp_p->lock);
+ len = snprintf(buf_p, 8, "%d\n", get_func(ioexp_p, tobj_p->ioexp_virt_offset));
+ mutex_unlock(&ioexp_p->lock);
+ return len;
+}
+
+
+static ssize_t
+show_attr_present(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_present,
+ buf_p);
+}
+
+static ssize_t
+show_attr_tx_fault(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_tx_fault,
+ buf_p);
+}
+
+static ssize_t
+show_attr_rxlos(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_rxlos,
+ buf_p);
+}
+
+static ssize_t
+show_attr_tx_disable(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_tx_disable,
+ buf_p);
+}
+
+static ssize_t
+show_attr_reset(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_reset,
+ buf_p);
+}
+
+static ssize_t
+show_attr_lpmod(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_lpmod,
+ buf_p);
+}
+
+
+static ssize_t
+show_attr_modsel(struct device *dev_p,
+ struct device_attribute *attr_p,
+ char *buf_p){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p){
+ return -ENODEV;
+ }
+ return _show_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->get_modsel,
+ buf_p);
+}
+
+/* ========== Store functions: For I/O Expander (R/W) attribute ==========
+ */
+static ssize_t
+_store_ioexp_binary_attr(struct transvr_obj_s *tobj_p,
+ int (*set_func)(struct ioexp_obj_s *ioexp_p,
+ int virt_offset, int input_val),
+ const char *buf_p,
+ size_t count) {
+
+ int input, err;
+ struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ SWPS_ERR("%s: data corruption! :%s\n",
+ __func__, tobj_p->swp_name);
+ return -ENODATA;
+ }
+ input = sscanf_2_binary(buf_p);
+ if (input < 0) {
+ return -EBFONT;
+ }
+ mutex_lock(&ioexp_p->lock);
+ err = set_func(ioexp_p, tobj_p->ioexp_virt_offset, input);
+ mutex_unlock(&ioexp_p->lock);
+ if (err < 0){
+ return err;
+ }
+ return count;
+}
+
+static ssize_t
+store_attr_tx_disable(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_tx_disable,
+ buf_p,
+ count);
+}
+
+static ssize_t
+store_attr_reset(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_reset,
+ buf_p,
+ count);
+}
+
+
+static ssize_t
+store_attr_lpmod(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_lpmod,
+ buf_p,
+ count);
+}
+
+
+static ssize_t
+store_attr_modsel(struct device *dev_p,
+ struct device_attribute *attr_p,
+ const char *buf_p,
+ size_t count){
+
+ struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p);
+ if (!tobj_p) {
+ return -ENODEV;
+ }
+ return _store_ioexp_binary_attr(tobj_p,
+ tobj_p->ioexp_obj_p->set_modsel,
+ buf_p,
+ count);
+}
+
+/* ========== IO Expander attribute: from expander ==========
+ */
+static DEVICE_ATTR(present, S_IRUGO, show_attr_present, NULL);
+static DEVICE_ATTR(tx_fault, S_IRUGO, show_attr_tx_fault, NULL);
+static DEVICE_ATTR(rxlos, S_IRUGO, show_attr_rxlos, NULL);
+static DEVICE_ATTR(tx_disable, S_IRUGO|S_IWUSR, show_attr_tx_disable, store_attr_tx_disable);
+static DEVICE_ATTR(reset, S_IRUGO|S_IWUSR, show_attr_reset, store_attr_reset);
+static DEVICE_ATTR(lpmod, S_IRUGO|S_IWUSR, show_attr_lpmod, store_attr_lpmod);
+static DEVICE_ATTR(modsel, S_IRUGO|S_IWUSR, show_attr_modsel, store_attr_modsel);
+
+/* ========== Functions for module handling ==========
+ */
+static void
+clean_port_obj(void){
+
+ dev_t dev_num;
+ char dev_name[32];
+ struct device *device_p;
+ struct transvr_obj_s *transvr_obj_p;
+ int minor_curr, port_id;
+
+ for (minor_curr=0; minor_curri2c_client_p);
+ kfree(transvr_obj_p);
+ }
+ dev_num = MKDEV(port_major, minor_curr);
+ device_unregister(device_p);
+ device_destroy(swp_class_p, dev_num);
+ }
+ SWPS_DEBUG("%s: done.\n", __func__);
+}
+
+
+static int
+get_platform_type(void){
+
+ char log_msg[64] = "ERROR";
+
+ platform_p = kzalloc(sizeof(struct inv_platform_s), GFP_KERNEL);
+ if (!platform_p){
+ snprintf(log_msg, sizeof(log_msg), "kzalloc fail");
+ goto err_get_platform_type_1;
+ }
+ platform_p->id = PLATFORM_SETTINGS;
+ memset(platform_p->name, 0, sizeof(platform_p->name));
+ snprintf(platform_p->name, (sizeof(platform_p->name) - 1),
+ "%s", platform_map.name);
+ snprintf(log_msg, sizeof(log_msg),
+ "User setup platform: %d (%s)",
+ platform_p->id, platform_p->name);
+ SWPS_DEBUG("%s: %s, :%d\n", __func__, log_msg, PLATFORM_SETTINGS);
+ return 0;
+
+err_get_platform_type_1:
+ SWPS_ERR("%s: %s :%d\n", __func__, log_msg, PLATFORM_SETTINGS);
+ return -1;
+}
+
+
+static int
+get_layout_info(void){
+ ioexp_layout = cypress_ga2_ioexp_layout;
+ port_layout = cypress_ga2_port_layout;
+ ioexp_total = ARRAY_SIZE(cypress_ga2_ioexp_layout);
+ port_total = ARRAY_SIZE(cypress_ga2_port_layout);
+
+ SWPS_INFO("Start to initial platform: %d (%s)\n",
+ platform_p->id, platform_p->name);
+ return 0;
+}
+
+/* ========== Functions for register something ==========
+ */
+
+static int
+register_ioexp_attr_sfp_1(struct device *device_p){
+ /* Support machine type:
+ * - SFP : Magnolia
+ */
+ char *err_attr = NULL;
+
+ if (device_create_file(device_p, &dev_attr_present) < 0) {
+ err_attr = "dev_attr_present";
+ goto err_ioexp_sfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_tx_fault) < 0) {
+ err_attr = "dev_attr_tx_fault";
+ goto err_ioexp_sfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_rxlos) < 0) {
+ err_attr = "dev_attr_rxlos";
+ goto err_ioexp_sfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_tx_disable) < 0) {
+ err_attr = "dev_attr_tx_disable";
+ goto err_ioexp_sfp1_attr;
+ }
+ return 0;
+
+err_ioexp_sfp1_attr:
+ SWPS_ERR("Add device attribute:%s failure! \n",err_attr);
+ return -1;
+}
+
+static int
+register_ioexp_attr_sfp_2(struct device *device_p){
+ /* Support machine type:
+ * - SFP28 : Cypress
+ */
+ char *err_attr = NULL;
+
+ if (register_ioexp_attr_sfp_1(device_p) < 0){
+ goto err_ioexp_sfp2_attr;
+ }
+ return 0;
+
+err_ioexp_sfp2_attr:
+ SWPS_ERR("Add device attribute:%s failure! \n",err_attr);
+ return -1;
+}
+
+static int
+register_ioexp_attr_qsfp_1(struct device *device_p){
+ /* Support machine type:
+ * - QSFP : Magnolia, Redwood, Hudson32i
+ * - QSFP+ : Magnolia, Redwood, Hudson32i
+ * - QSFP28: Redwood
+ */
+ char *err_attr = NULL;
+
+ if (device_create_file(device_p, &dev_attr_present) < 0) {
+ err_attr = "dev_attr_present";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_reset) < 0) {
+ err_attr = "dev_attr_reset";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_lpmod) < 0) {
+ err_attr = "dev_attr_lpmod";
+ goto err_ioexp_qsfp1_attr;
+ }
+ if (device_create_file(device_p, &dev_attr_modsel) < 0) {
+ err_attr = "dev_attr_modsel";
+ goto err_ioexp_qsfp1_attr;
+ }
+ return 0;
+
+err_ioexp_qsfp1_attr:
+ SWPS_ERR("Add device attribute:%s failure! \n",err_attr);
+ return -1;
+}
+
+static int
+register_ioexp_attr(struct device *device_p,
+ struct transvr_obj_s *transvr_obj){
+
+ char *err_msg = "ERR";
+
+ switch (transvr_obj->ioexp_obj_p->ioexp_type){
+ case IOEXP_TYPE_CYPRESS_NABC:
+ if (register_ioexp_attr_sfp_2(device_p) < 0){
+ err_msg = "register_ioexp_attr_sfp_2 fail";
+ goto err_reg_ioexp_attr;
+ }
+ break;
+ case IOEXP_TYPE_CYPRESS_7ABC:
+ if (register_ioexp_attr_qsfp_1(device_p) < 0){
+ err_msg = "register_ioexp_attr_qsfp_1 fail";
+ goto err_reg_ioexp_attr;
+ }
+ break;
+
+ default:
+ err_msg = "Unknow type";
+ goto err_reg_ioexp_attr;
+ }
+ return 0;
+
+err_reg_ioexp_attr:
+ SWPS_ERR("%s: %s :%d \n",
+ __func__, err_msg, transvr_obj->ioexp_obj_p->ioexp_type);
+ return -1;
+}
+
+
+static int
+register_port_device(char *dev_name,
+ dev_t dev_num,
+ struct transvr_obj_s *transvr_obj){
+
+ struct device *device_p = NULL;
+ device_p = device_create(swp_class_p, /* struct class *cls */
+ NULL, /* struct device *parent */
+ dev_num, /* dev_t devt */
+ transvr_obj, /* void *private_data */
+ dev_name); /* const char *fmt */
+ if (IS_ERR(device_p)){
+ goto err_regswp_create_dev;
+ }
+ if (register_ioexp_attr(device_p, transvr_obj) < 0){
+ goto err_regswp_reg_attr;
+ }
+ return 0;
+
+err_regswp_reg_attr:
+ device_unregister(device_p);
+ device_destroy(swp_class_p, dev_num);
+err_regswp_create_dev:
+ SWPS_ERR("%s fail! :%s\n", __func__, dev_name);
+ return -1;
+}
+
+
+static int
+register_swp_module(void){
+
+ dev_t port_devt = 0;
+ int dev_total = port_total + 1; /* char_dev for module control */
+
+ if (alloc_chrdev_region(&port_devt, 0, dev_total, SWP_CLS_NAME) < 0){
+ SWPS_WARN("Allocate PORT MAJOR failure! \n");
+ goto err_register_swp_module_3;
+ }
+ port_major = MAJOR(port_devt);
+
+ /* Create class object */
+ swp_class_p = class_create(THIS_MODULE, SWP_CLS_NAME);
+ if (IS_ERR(swp_class_p)) {
+ SWPS_ERR("Create class failure! \n");
+ goto err_register_swp_module_3;
+ }
+ return 0;
+
+err_register_swp_module_3:
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+ return -1;
+}
+
+
+/* ========== Module initial relate ==========
+ */
+static int
+create_ioexp_objs(void) {
+
+ int i, run_mod;
+
+ /* Clean IOEXP object */
+ clean_ioexp_objs();
+ /* Get running mode */
+ run_mod = IOEXP_MODE_DIRECT;
+ /* Create IOEXP object */
+ for(i=0; i devlen_max) {
+ snprintf(err_msg, sizeof(err_msg),
+ "SWP_DEV_PORT too long!");
+ goto err_initport_create_tranobj;
+ }
+ memset(dev_name, 0, sizeof(dev_name));
+ snprintf(dev_name, devlen_max, "%s%d", SWP_DEV_PORT, port_id);
+ /* Create transceiver object */
+ ioexp_obj_p = get_ioexp_obj(ioexp_id);
+ if (!ioexp_obj_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "IOEXP object:%d not exist", ioexp_id);
+ goto err_initport_create_tranobj;
+ }
+ transvr_obj_p = create_transvr_obj(dev_name, chan_id, ioexp_obj_p,
+ ioexp_virt_offset, transvr_type,
+ chipset_type, run_mod);
+ if (!transvr_obj_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "Create transceiver object fail :%s", dev_name);
+ goto err_initport_create_tranobj;
+ }
+ /* Setup Lane_ID mapping */
+ i = ARRAY_SIZE(port_layout[minor_curr].lane_id);
+ j = ARRAY_SIZE(transvr_obj_p->lane_id);
+ if (i != j) {
+ snprintf(err_msg, sizeof(err_msg),
+ "Lane_id size inconsistent %d/%d", i, j);
+ goto err_initport_reg_device;
+ }
+ memcpy(transvr_obj_p->lane_id, port_layout[minor_curr].lane_id, i*sizeof(int));
+ /* Create and register device object */
+ if (register_port_device(dev_name, MKDEV(port_major, minor_curr), transvr_obj_p) < 0){
+ snprintf(err_msg, sizeof(err_msg),
+ "register_port_device fail");
+ goto err_initport_reg_device;
+ }
+ /* Setup device_ptr of transvr_obj */
+ dev_p = get_swpdev_by_name(dev_name);
+ if (!dev_p){
+ snprintf(err_msg, sizeof(err_msg),
+ "get_swpdev_by_name fail");
+ goto err_initport_reg_device;
+ }
+ transvr_obj_p->transvr_dev_p = dev_p;
+ /* Success */
+ ok_count++;
+ }
+ SWPS_INFO("%s: initialed %d port-dev",__func__, ok_count);
+ return 0;
+
+err_initport_reg_device:
+ kfree(transvr_obj_p);
+err_initport_create_tranobj:
+ clean_port_obj();
+ SWPS_ERR("%s: %s", __func__, err_msg);
+ SWPS_ERR("Dump: :%d :%d :%d :%d :%d :%d\n",
+ port_id, chan_id, ioexp_id, ioexp_virt_offset, transvr_type, run_mod);
+ return -1;
+}
+
+static int __init
+swp_module_init(void){
+
+ if (get_platform_type() < 0){
+ goto err_init_out;
+ }
+ if (get_layout_info() < 0){
+ goto err_init_out;
+ }
+ if (register_swp_module() < 0){
+ goto err_init_out;
+ }
+ if (create_ioexp_objs() < 0){
+ goto err_init_ioexp;
+ }
+ if (create_port_objs() < 0){
+ goto err_init_portobj;
+ }
+ if (init_ioexp_objs() < 0){
+ goto err_init_portobj;
+ }
+ SWPS_INFO("Inventec switch-port module V.%s initial success.\n", SWP_VERSION);
+ return 0;
+
+
+err_init_portobj:
+ clean_ioexp_objs();
+err_init_ioexp:
+ class_unregister(swp_class_p);
+ class_destroy(swp_class_p);
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+err_init_out:
+ SWPS_ERR("Inventec switch-port module V.%s initial failure.\n", SWP_VERSION);
+ return -1;
+}
+
+
+static void __exit
+swp_module_exit(void){
+ clean_port_obj();
+ clean_ioexp_objs();
+ class_unregister(swp_class_p);
+ class_destroy(swp_class_p);
+ unregister_chrdev_region(MKDEV(port_major, 0), port_total);
+ SWPS_INFO("Remove Inventec switch-port module success.\n");
+}
+
+
+/* Module information */
+MODULE_AUTHOR(SWP_AUTHOR);
+MODULE_DESCRIPTION(SWP_DESC);
+MODULE_VERSION(SWP_VERSION);
+MODULE_LICENSE(SWP_LICENSE);
+
+module_init(swp_module_init);
+module_exit(swp_module_exit);
+
+
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h
new file mode 100644
index 0000000000..f37fd387e4
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h
@@ -0,0 +1,170 @@
+#ifndef INV_SWPS_H
+#define INV_SWPS_H
+
+#include "transceiver.h"
+#include "io_expander.h"
+
+/* Module settings */
+#define SWP_CLS_NAME "swps"
+#define SWP_DEV_PORT "port"
+#define SWP_AUTOCONFIG_ENABLE (1)
+
+/* Module information */
+#define SWP_AUTHOR "Neil "
+#define SWP_DESC "Inventec port and transceiver driver"
+#define SWP_VERSION "4.2.3"
+#define SWP_LICENSE "GPL"
+
+/* Module status define */
+#define SWP_STATE_NORMAL (0)
+#define SWP_STATE_I2C_DIE (-91)
+
+/* [Note]:
+ * Functions and mechanism for auto-detect platform type is ready,
+ * But HW and BIOS not ready! We need to wait them.
+ * So, please do not use PLATFORM_TYPE_AUTO until they are ready.
+ * (2016.06.13)
+ */
+#define PLATFORM_TYPE_CYPRESS_GA2 (152) /* Down -> Up */
+#define PLATFORM_TYPE_CYPRESS_BAI (153) /* Down -> Up */
+
+/* Current running platfrom */
+#define PLATFORM_SETTINGS PLATFORM_TYPE_CYPRESS_GA2
+
+/* Define platform flag and kernel version */
+#if (PLATFORM_SETTINGS == PLATFORM_TYPE_CYPRESS_GA2)
+ #define SWPS_KERN_VER_BF_3_8 (1)
+#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_CYPRESS_BAI)
+ #define SWPS_KERN_VER_AF_3_10 (1)
+#endif
+
+
+struct inv_platform_s {
+ int id;
+ char name[64];
+};
+
+struct inv_ioexp_layout_s {
+ int ioexp_id;
+ int ioexp_type;
+ struct ioexp_addr_s addr[4];
+};
+
+struct inv_port_layout_s {
+ int port_id;
+ int chan_id;
+ int ioexp_id;
+ int ioexp_offset;
+ int transvr_type;
+ int chipset_type;
+ int lane_id[8];
+};
+
+/* ==========================================
+ * Inventec Platform Settings
+ * ==========================================
+ */
+struct inv_platform_s platform_map = {PLATFORM_TYPE_CYPRESS_GA2, "D7054Q28B" };
+
+/* ==========================================
+ * Cypress Layout configuration (Inventec version [Down->Up])
+ * ==========================================
+ */
+struct inv_ioexp_layout_s cypress_ga2_ioexp_layout[] = {
+ /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */
+ {0, IOEXP_TYPE_CYPRESS_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {1, IOEXP_TYPE_CYPRESS_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {2, IOEXP_TYPE_CYPRESS_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {3, IOEXP_TYPE_CYPRESS_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {4, IOEXP_TYPE_CYPRESS_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {5, IOEXP_TYPE_CYPRESS_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */
+ {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */
+ {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */
+ },
+ {6, IOEXP_TYPE_CYPRESS_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */
+ {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xc0}, {0xff, 0xc0}, }, /* addr[1] = I/O Expander 7 B */
+ {8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 7 C */
+ },
+};
+
+struct inv_port_layout_s cypress_ga2_port_layout[] = {
+ /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */
+ { 0, 11, 0, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 2} },
+ { 1, 10, 0, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 1} },
+ { 2, 13, 0, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 4} },
+ { 3, 12, 0, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 3} },
+ { 4, 15, 0, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 6} },
+ { 5, 14, 0, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 5} },
+ { 6, 17, 0, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 8} },
+ { 7, 16, 0, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 7} },
+ { 8, 19, 1, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 10} },
+ { 9, 18, 1, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 9} },
+ {10, 21, 1, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 12} },
+ {11, 20, 1, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 11} },
+ {12, 23, 1, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 22} },
+ {13, 22, 1, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 21} },
+ {14, 25, 1, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 24} },
+ {15, 24, 1, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 23} },
+ {16, 27, 2, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 34} },
+ {17, 26, 2, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 33} },
+ {18, 29, 2, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 36} },
+ {19, 28, 2, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 35} },
+ {20, 31, 2, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 38} },
+ {21, 30, 2, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 37} },
+ {22, 33, 2, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 40} },
+ {23, 32, 2, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 39} },
+ {24, 35, 3, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 42} },
+ {25, 34, 3, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 41} },
+ {26, 37, 3, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 44} },
+ {27, 36, 3, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 43} },
+ {28, 39, 3, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 50} },
+ {29, 38, 3, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 49} },
+ {30, 41, 3, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 52} },
+ {31, 40, 3, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 51} },
+ {32, 43, 4, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 54} },
+ {33, 42, 4, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 53} },
+ {34, 45, 4, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 56} },
+ {35, 44, 4, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 55} },
+ {36, 47, 4, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 66} },
+ {37, 46, 4, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 65} },
+ {38, 49, 4, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 68} },
+ {39, 48, 4, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 67} },
+ {40, 51, 5, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 70} },
+ {41, 50, 5, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 69} },
+ {42, 53, 5, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 72} },
+ {43, 52, 5, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 71} },
+ {44, 55, 5, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 82} },
+ {45, 54, 5, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 81} },
+ {46, 57, 5, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 84} },
+ {47, 56, 5, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 83} },
+ {48, 59, 6, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 85, 86, 87, 88} },
+ {49, 58, 6, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 97, 98, 99,100} },
+ {50, 61, 6, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {105,106,107,108} },
+ {51, 60, 6, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {101,102,103,104} },
+ {52, 63, 6, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {117,118,119,120} },
+ {53, 62, 6, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {109,110,111,112} },
+};
+
+
+#endif /* SFP_DRIVER_H */
+
+
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c
new file mode 100644
index 0000000000..057995e455
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c
@@ -0,0 +1,944 @@
+#include
+#include
+#include "io_expander.h"
+
+static struct ioexp_obj_s *ioexp_head_p = NULL;
+static struct ioexp_obj_s *ioexp_tail_p = NULL;
+
+struct ioexp_map_s ioexp_map_cypress_nabc = {
+
+ .chip_amount = 3,
+ .data_width = 2,
+
+ .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */
+ {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */
+ {0, 0, 6}, /* map_present[2] = MOD_ABS_PORT(X+2) */
+ {0, 0, 7}, /* map_present[3] = MOD_ABS_PORT(X+3) */
+ {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */
+ {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */
+ {1, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */
+ {1, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */
+ },
+ .map_tx_disable = { {0, 1, 0}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */
+ {0, 1, 1}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */
+ {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */
+ {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */
+ {1, 1, 0}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */
+ {1, 1, 1}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */
+ {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */
+ {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */
+ },
+ .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */
+ {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */
+ {0, 0, 2}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */
+ {0, 0, 3}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */
+ {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */
+ {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */
+ {1, 0, 2}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */
+ {1, 0, 3}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */
+ },
+ .map_rxlos = { {0, 1, 4}, /* map_rxlos[0] = OPRXLOS_PORT(X) */
+ {0, 1, 5}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */
+ {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */
+ {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */
+ {1, 1, 4}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */
+ {1, 1, 5}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */
+ {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */
+ {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */
+ },
+};
+
+struct ioexp_map_s ioexp_map_cypress_7abc = {
+
+ .chip_amount = 3,
+ .data_width = 2,
+
+ .map_present = { {2, 0, 0}, /* map_present[0] = MOD_ABS_PORT(X) */
+ {2, 0, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */
+ {2, 0, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */
+ {2, 0, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */
+ {2, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */
+ {2, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */
+ },
+ .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP_N_P(X) */
+ {0, 0, 1}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */
+ {0, 0, 2}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */
+ {0, 0, 3}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */
+ {0, 0, 4}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */
+ {0, 0, 5}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */
+ },
+ .map_lpmod = { {0, 1, 0}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */
+ {0, 1, 1}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */
+ {0, 1, 2}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */
+ {0, 1, 3}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */
+ {0, 1, 4}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */
+ {0, 1, 5}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */
+ },
+ .map_modsel = { {1, 1, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */
+ {1, 1, 1}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */
+ {1, 1, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */
+ {1, 1, 3}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */
+ {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */
+ {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */
+ },
+};
+
+
+
+/* ========== Private functions ==========
+ */
+int check_channel_tier_1(void);
+
+struct i2c_client *
+_get_i2c_client(struct ioexp_obj_s *self,
+ int chip_id){
+
+ struct ioexp_i2c_s *i2c_curr_p = self->i2c_head_p;
+
+ if (!(i2c_curr_p)){
+ SWPS_ERR("%s: i2c_curr_p is NULL\n", __func__);
+ return NULL;
+ }
+ while (i2c_curr_p){
+ if ((i2c_curr_p->chip_id) == chip_id){
+ return i2c_curr_p->i2c_client_p;
+ }
+ i2c_curr_p = i2c_curr_p->next;
+ }
+ SWPS_ERR("%s: not exist! :%d\n", __func__, chip_id);
+ return NULL;
+}
+
+
+static int
+_common_ioexp_update_one(struct ioexp_obj_s *self,
+ struct ioexp_addr_s *ioexp_addr,
+ int chip_id,
+ int data_width,
+ int show_err,
+ char *caller_name) {
+ int buf = 0;
+ int err = 0;
+ int data_id = 0;
+ int r_offset = 0;
+
+ for(data_id=0; data_idread_offset[data_id];
+ buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), r_offset);
+ /* Check error */
+ if (buf < 0) {
+ err = 1;
+ if (show_err) {
+ SWPS_INFO("IOEXP-%d read fail! :%d \n", self->ioexp_id, buf);
+ SWPS_INFO("Dump: :%d :0x%02x :%d, :%s\n",
+ ioexp_addr->chan_id, ioexp_addr->chip_addr,
+ ioexp_addr->read_offset[data_id], caller_name);
+ }
+ continue;
+ }
+ /* Update IOEXP object */
+ self->chip_data[chip_id].data[data_id] = (uint8_t)buf;
+ }
+ if (err) {
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+
+static int
+common_ioexp_update_all(struct ioexp_obj_s *self,
+ int show_err,
+ char *caller_name){
+
+ int err = 0;
+ int chip_id = 0;
+ int chip_amount = self->ioexp_map_p->chip_amount;
+
+ for (chip_id=0; chip_idioexp_map_p->map_addr[chip_id]),
+ chip_id,
+ self->ioexp_map_p->data_width,
+ show_err,
+ caller_name) < 0) {
+ err = 1;
+ }
+ }
+ if (err) {
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+static int
+_common_get_bit(struct ioexp_obj_s *self,
+ struct ioexp_bitmap_s *bitmap_obj_p,
+ char *func_mane){
+ uint8_t buf;
+ int err_code;
+
+ /* Get address */
+ err_code = self->fsm_4_direct(self);
+ if (err_code < 0){
+ return err_code;
+ }
+
+ if (!bitmap_obj_p){
+ SWPS_ERR("Layout config incorrect! :%d :%s\n",
+ self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADCONF;
+ }
+ /* Get data form cache */
+ buf = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset];
+ return (int)(buf >> bitmap_obj_p->bit_shift & 0x01);
+}
+
+
+static int
+_common_set_bit(struct ioexp_obj_s *self,
+ struct ioexp_bitmap_s *bitmap_obj_p,
+ int input_val,
+ char *func_mane){
+ int err_code, target_offset;
+ uint8_t origin_byte;
+ uint8_t modify_byte;
+
+ /* Get address */
+ err_code = self->fsm_4_direct(self);
+ if (err_code < 0){
+ return err_code;
+ }
+ if (!bitmap_obj_p){
+ SWPS_ERR("Layout config incorrect! :%d :%s\n",
+ self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADCONF;
+ }
+ /* Prepare write date */
+ origin_byte = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset];
+ switch (input_val) {
+ case 0:
+ modify_byte = origin_byte;
+ SWP_BIT_CLEAR(modify_byte, bitmap_obj_p->bit_shift);
+ break;
+ case 1:
+ modify_byte = origin_byte;
+ SWP_BIT_SET(modify_byte, bitmap_obj_p->bit_shift);
+ break;
+ default:
+ SWPS_ERR("Input value incorrect! :%d :%d :%s\n",
+ input_val, self->ioexp_id, func_mane);
+ return ERR_IOEXP_BADINPUT;
+ }
+ /* Setup i2c client */
+ target_offset = self->ioexp_map_p->map_addr[bitmap_obj_p->chip_id].write_offset[bitmap_obj_p->ioexp_voffset];
+ /* Write byte to chip via I2C */
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, bitmap_obj_p->chip_id),
+ target_offset,
+ modify_byte);
+ /* Update or bollback object */
+ if (err_code < 0){
+ self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = origin_byte;
+ SWPS_ERR("I2C write fail! :%d :%d :%s :%d\n",
+ input_val, self->ioexp_id, func_mane, err_code);
+ return err_code;
+ }
+ self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = modify_byte;
+ return 0;
+}
+
+
+/* ========== Object public functions ==========
+ */
+int
+common_get_present(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ int UNPLUG = 1;
+ int retval = ERR_IOEXP_UNEXCPT;
+
+ retval = _common_get_bit(self,
+ &(self->ioexp_map_p->map_present[virt_offset]),
+ "common_get_present");
+ if (retval < 0) {
+ /* [Note]
+ * => Transceiver object does not need to handle IOEXP layer issues.
+ */
+ return UNPLUG;
+ }
+ return retval;
+}
+
+int
+common_get_tx_fault(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_tx_fault[virt_offset]),
+ "common_get_tx_fault");
+}
+
+int
+common_get_rxlos(struct ioexp_obj_s *self,
+ int virt_offset){
+ /* [Receiver Loss of Signal (Rx_LOS)]
+ * The post-amplification IC also includes transition detection circuitry
+ * which monitors the ac level of incoming optical signals and provides a
+ * TTL/CMOS compatible status signal to the host (pin 8). An adequate optical
+ * input results in a low Rx_LOS output while a high Rx_LOS output indicates
+ * an unusable optical input. The Rx_LOS thresholds are factory set so that
+ * a high output indicates a definite optical fault has occurred. Rx_LOS can
+ * also be monitored via the two-wire serial interface
+ * (address A2h, byte 110, bit 1).
+ *
+ * 0: Normal
+ * 1: Abnormal
+ */
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_rxlos[virt_offset]),
+ "common_get_rxlos");
+}
+
+
+int
+common_get_tx_disable(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_tx_disable[virt_offset]),
+ "common_get_tx_disable");
+}
+
+int
+common_get_reset(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_reset[virt_offset]),
+ "common_get_reset");
+}
+
+
+int
+common_get_lpmod(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_lpmod[virt_offset]),
+ "common_get_lpmod");
+}
+
+
+int
+common_get_modsel(struct ioexp_obj_s *self,
+ int virt_offset){
+
+ return _common_get_bit(self,
+ &(self->ioexp_map_p->map_modsel[virt_offset]),
+ "common_get_modsel");
+}
+
+int
+common_set_tx_disable(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_tx_disable[virt_offset]),
+ input_val,
+ "common_set_tx_disable");
+}
+
+int
+common_set_reset(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_reset[virt_offset]),
+ input_val,
+ "common_set_reset");
+}
+
+
+int
+common_set_lpmod(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_lpmod[virt_offset]),
+ input_val,
+ "common_set_lpmod");
+}
+
+
+int
+common_set_modsel(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+
+ return _common_set_bit(self,
+ &(self->ioexp_map_p->map_modsel[virt_offset]),
+ input_val,
+ "common_set_modsel");
+}
+
+int
+ioexp_get_not_support(struct ioexp_obj_s *self,
+ int virt_offset){
+ return ERR_IOEXP_NOTSUPPORT;
+}
+
+
+int
+ioexp_set_not_support(struct ioexp_obj_s *self,
+ int virt_offset,
+ int input_val){
+ return ERR_IOEXP_NOTSUPPORT;
+}
+
+/* ========== Initial functions for IO Expander ==========
+ */
+int
+common_ioexp_init(struct ioexp_obj_s *self) {
+
+ int chip_id, offset, err_code;
+ struct ioexp_addr_s *addr_p;
+
+ if (self->mode == IOEXP_MODE_DIRECT) { ///important
+ goto update_common_ioexp_init;
+ }
+ /* Setup default value to each physical IO Expander */
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ /* Get address mapping */
+ addr_p = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!addr_p){
+ SWPS_ERR("%s: IOEXP config incorrect! :%d \n",
+ __func__, chip_id);
+ return -1;
+ }
+ /* Setup default value */
+ for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id),
+ addr_p->write_offset[offset],
+ addr_p->data_default[offset]);
+ if (err_code < 0){
+ SWPS_ERR("%s: set default fail! :%d \n",
+ __func__, err_code);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ }
+ }
+
+update_common_ioexp_init:
+ /* Check and update info to object */
+ err_code = self->update_all(self, 1, "common_ioexp_init");
+ if (err_code < 0) {
+ SWPS_ERR("%s: update_all() fail! :%d \n",
+ __func__, err_code);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ return 0;
+}
+
+
+/* ========== Object functions for Final State Machine ==========
+ */
+int
+_is_channel_ready(struct ioexp_obj_s *self){
+
+ int buf = 0;
+ int chip_id = 0; /* Use first chip which be registered */
+ int data_id = 0; /* Use first byte which be registered */
+ struct ioexp_addr_s *ioexp_addr = NULL;
+
+ ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!ioexp_addr){
+ SWPS_ERR("%s: config incorrect!\n", __func__);
+ return ERR_IOEXP_UNEXCPT;
+ }
+ buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id),
+ ioexp_addr->read_offset[data_id]);
+ if (buf >= 0){
+ return 1;
+ }
+ return 0;
+}
+
+int
+_ioexp_init_handler(struct ioexp_obj_s *self){
+
+ int return_val;
+
+ switch (self->mode) {
+ case IOEXP_MODE_DIRECT:
+ return_val = self->init(self);
+ if (return_val < 0){
+ self->state = STATE_IOEXP_ABNORMAL;
+ } else {
+ self->state = STATE_IOEXP_NORMAL;
+ }
+ return return_val;
+ default:
+ break;
+ }
+ SWPS_ERR("%s: exception occur :%d\n", __func__, self->mode);
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+int
+common_ioexp_fsm_4_direct(struct ioexp_obj_s *self){
+
+ int result_val;
+ int show_err = 1;
+ char *func_mane = "common_ioexp_fsm_4_direct";
+
+ switch (self->state){
+ case STATE_IOEXP_INIT:
+ result_val = _ioexp_init_handler(self);
+ /* Exception case: terminate initial procedure */
+ if(result_val < 0){
+ /* Initial fail */
+ return result_val;
+ }
+ if(self->state == STATE_IOEXP_INIT){
+ /* Keep in INIT state, and return error */
+ return ERR_IOEXP_UNINIT;
+ }
+ /* Case: Initial done */
+ return 0;
+
+ case STATE_IOEXP_NORMAL:
+ result_val = self->update_all(self, show_err, func_mane);
+ if (result_val < 0){
+ SWPS_INFO("%s: NORMAL -> ABNORMAL :%d\n",
+ __func__, result_val);
+ self->state = STATE_IOEXP_ABNORMAL;
+ return result_val;
+ }
+ self->state = STATE_IOEXP_NORMAL;
+ return 0;
+
+ case STATE_IOEXP_ABNORMAL:
+ result_val = self->update_all(self, show_err, func_mane);
+ if (result_val < 0){
+ self->state = STATE_IOEXP_ABNORMAL;
+ return result_val;
+ }
+ SWPS_DEBUG("%s: ABNORMAL -> NORMAL :%d\n",
+ __func__, result_val);
+ self->state = STATE_IOEXP_NORMAL;
+ return 0;
+
+ default:
+ break;
+ }
+ SWPS_ERR("%s: Exception occurs :%d\n",
+ __func__, self->state);
+ return ERR_IOEXP_UNEXCPT;
+}
+
+/* ========== Functions for Factory pattern ==========
+ */
+static struct ioexp_map_s *
+get_ioexp_map(int ioexp_type){
+ switch (ioexp_type){
+ case IOEXP_TYPE_CYPRESS_NABC:
+ return &ioexp_map_cypress_nabc;
+ case IOEXP_TYPE_CYPRESS_7ABC:
+ return &ioexp_map_cypress_7abc;
+ default:
+ return NULL;
+ }
+}
+
+
+int
+setup_ioexp_ssize_attr(struct ioexp_obj_s *self,
+ struct ioexp_map_s *ioexp_map_p,
+ int ioexp_id,
+ int ioexp_type,
+ int run_mode){
+ switch (run_mode){
+ case IOEXP_MODE_DIRECT: /* Direct access device mode */
+ self->mode = run_mode;
+ break;
+ default:
+ SWPS_ERR("%s: non-defined run_mode:%d\n",
+ __func__, run_mode);
+ self->mode = ERR_IOEXP_UNEXCPT;
+ return ERR_IOEXP_UNEXCPT;
+ }
+ self->ioexp_id = ioexp_id;
+ self->ioexp_type = ioexp_type;
+ self->ioexp_map_p = ioexp_map_p;
+ self->state = STATE_IOEXP_INIT;
+ mutex_init(&self->lock);
+ return 0;
+}
+
+
+static int
+setup_addr_mapping(struct ioexp_obj_s *self,
+ struct ioexp_addr_s *addr_map_p){
+ if (!addr_map_p){
+ SWPS_ERR("%s: map is null\n", __func__);
+ return -1;
+ }
+ self->ioexp_map_p->map_addr = addr_map_p;
+ return 0;
+}
+
+
+static int
+setup_ioexp_public_cb(struct ioexp_obj_s *self,
+ int ioexp_type){
+ switch (ioexp_type){
+ case IOEXP_TYPE_CYPRESS_NABC:
+ self->get_present = common_get_present;
+ self->get_tx_fault = common_get_tx_fault;
+ self->get_rxlos = common_get_rxlos;
+ self->get_tx_disable = common_get_tx_disable;
+ self->get_reset = ioexp_get_not_support;
+ self->get_lpmod = ioexp_get_not_support;
+ self->get_modsel = ioexp_get_not_support;
+ self->set_tx_disable = common_set_tx_disable;
+ self->set_reset = ioexp_set_not_support;
+ self->set_lpmod = ioexp_set_not_support;
+ self->set_modsel = ioexp_set_not_support;
+ return 0;
+ case IOEXP_TYPE_CYPRESS_7ABC:
+ self->get_present = common_get_present;
+ self->get_tx_fault = ioexp_get_not_support;
+ self->get_rxlos = ioexp_get_not_support;
+ self->get_tx_disable = ioexp_get_not_support;
+ self->get_reset = common_get_reset;
+ self->get_lpmod = common_get_lpmod;
+ self->get_modsel = common_get_modsel;
+ self->set_tx_disable = ioexp_set_not_support;
+ self->set_reset = common_set_reset;
+ self->set_lpmod = common_set_lpmod;
+ self->set_modsel = common_set_modsel;
+ return 0;
+
+ default:
+ SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type);
+ break;
+ }
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+static int
+setup_ioexp_private_cb(struct ioexp_obj_s *self,
+ int ioexp_type){
+
+ switch (ioexp_type){
+ case IOEXP_TYPE_CYPRESS_NABC:
+ case IOEXP_TYPE_CYPRESS_7ABC:
+ self->init = common_ioexp_init;
+ self->update_all = common_ioexp_update_all;
+ self->fsm_4_direct = common_ioexp_fsm_4_direct;
+ return 0;
+
+ default:
+ SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type);
+ break;
+ }
+ return ERR_IOEXP_UNEXCPT;
+}
+
+
+static int
+setup_i2c_client_one(struct ioexp_obj_s *self,
+ int chip_id){
+
+ char *err_msg = "ERROR";
+ struct i2c_adapter *adap = NULL;
+ struct i2c_client *client = NULL;
+ struct ioexp_i2c_s *i2c_obj_p = NULL;
+ struct ioexp_i2c_s *i2c_curr_p = NULL;
+
+ int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id;
+ adap = i2c_get_adapter(chan_id);
+ if(!adap){
+ err_msg = "Can not get adap!";
+ goto err_ioexp_setup_i2c_1;
+ }
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client){
+ err_msg = "Can not kzalloc client!";
+ goto err_ioexp_setup_i2c_1;
+ }
+ i2c_obj_p = kzalloc(sizeof(*i2c_obj_p), GFP_KERNEL);
+ if (!i2c_obj_p){
+ err_msg = "Can not kzalloc i2c_obj_p!";
+ goto err_ioexp_setup_i2c_2;
+ }
+ client->adapter = adap;
+ client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr;
+ i2c_obj_p->i2c_client_p = client;
+ i2c_obj_p->chip_id = chip_id;
+ i2c_obj_p->next = NULL;
+ if (!self->i2c_head_p){
+ self->i2c_head_p = i2c_obj_p;
+ } else {
+ i2c_curr_p = self->i2c_head_p;
+ while (i2c_curr_p->next){
+ i2c_curr_p = i2c_curr_p->next;
+ }
+ i2c_curr_p->next = i2c_obj_p;
+ }
+ return 0;
+
+err_ioexp_setup_i2c_2:
+ kfree(client);
+err_ioexp_setup_i2c_1:
+ SWPS_ERR("%s: %s :%d\n", __func__, err_msg, chan_id);
+ return -1;
+}
+
+
+static int
+setup_i2c_client(struct ioexp_obj_s* self){
+
+ int result;
+ int chip_id = 0;
+
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ result = setup_i2c_client_one(self, chip_id);
+ if (result < 0){
+ SWPS_ERR("%s fail! :%d\n", __func__, chip_id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+setup_ioexp_config(struct ioexp_obj_s *self) {
+
+ int chip_id, offset, err_code;
+ struct ioexp_addr_s *addr_p;
+
+ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){
+ addr_p = &(self->ioexp_map_p->map_addr[chip_id]);
+ if (!addr_p){
+ SWPS_ERR("IOEXP config incorrect! :%d \n",chip_id);
+ return -1;
+ }
+ for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){
+
+ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id),
+ addr_p->conf_offset[offset],
+ addr_p->conf_default[offset]);
+
+ if (err_code < 0){
+ SWPS_INFO("%s: set conf fail! :%d \n", __func__, err_code);
+ return -2;
+ }
+ }
+ }
+ return 0;
+}
+
+struct ioexp_obj_s *
+_create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode){
+
+ struct ioexp_map_s* ioexp_map_p;
+ struct ioexp_obj_s* result_p;
+ struct ioexp_i2c_s *i2c_curr_p;
+ struct ioexp_i2c_s *i2c_next_p;
+
+ /* Get layout */
+ ioexp_map_p = get_ioexp_map(ioexp_type);
+ if (!ioexp_map_p){
+ SWPS_ERR("%s: Invalid ioexp_type\n", __func__);
+ goto err_create_ioexp_fail;
+ }
+ /* Prepare IOEXP object */
+ result_p = kzalloc(sizeof(*result_p), GFP_KERNEL);
+ if (!result_p){
+ SWPS_ERR("%s: kzalloc failure!\n", __func__);
+ goto err_create_ioexp_fail;
+ }
+ /* Prepare static size attributes */
+ if (setup_ioexp_ssize_attr(result_p,
+ ioexp_map_p,
+ ioexp_id,
+ ioexp_type,
+ run_mode) < 0){
+ goto err_create_ioexp_setup_attr_fail;
+ }
+ /* Prepare address mapping */
+ if (setup_addr_mapping(result_p, addr_map_p) < 0){
+ goto err_create_ioexp_setup_attr_fail;
+ }
+ if (setup_i2c_client(result_p) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ /* Prepare call back functions of object */
+ if (setup_ioexp_public_cb(result_p, ioexp_type) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ if (setup_ioexp_private_cb(result_p, ioexp_type) < 0){
+ goto err_create_ioexp_setup_i2c_fail;
+ }
+ return result_p;
+
+err_create_ioexp_setup_i2c_fail:
+ i2c_curr_p = result_p->i2c_head_p;
+ i2c_next_p = result_p->i2c_head_p;
+ while (i2c_curr_p){
+ i2c_next_p = i2c_curr_p->next;
+ kfree(i2c_curr_p->i2c_client_p);
+ kfree(i2c_curr_p);
+ i2c_curr_p = i2c_next_p;
+ }
+err_create_ioexp_setup_attr_fail:
+ kfree(result_p);
+err_create_ioexp_fail:
+ SWPS_ERR("%s: fail! :%d :%d \n",
+ __func__, ioexp_id, ioexp_type);
+ return NULL;
+}
+
+
+int
+create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode){
+
+ struct ioexp_obj_s *ioexp_p = NULL;
+
+ ioexp_p = _create_ioexp_obj(ioexp_id, ioexp_type,
+ addr_map_p, run_mode);
+ if (!ioexp_p){
+ return -1;
+ }
+ if (ioexp_head_p == NULL){
+ ioexp_head_p = ioexp_p;
+ ioexp_tail_p = ioexp_p;
+ return 0;
+ }
+ ioexp_tail_p->next = ioexp_p;
+ ioexp_tail_p = ioexp_p;
+ return 0;
+}
+
+static int
+_init_ioexp_obj(struct ioexp_obj_s* self) {
+
+ char *err_msg = "ERR";
+ char *func_name = "_init_ioexp_obj";
+
+ /* Setup IOEXP configure byte */
+ if (setup_ioexp_config(self) < 0){
+ err_msg = "setup_ioexp_config fail";
+ goto err_init_ioexp_obj;
+ }
+ /* Setup default data */
+ if (_ioexp_init_handler(self) < 0){
+ err_msg = "_ioexp_init_handler fail";
+ goto err_init_ioexp_obj;
+ }
+ /* Update all */
+ if (self->state == STATE_IOEXP_NORMAL){
+ if (self->update_all(self, 1, func_name) < 0){
+ err_msg = "update_all() fail";
+ goto err_init_ioexp_obj;
+ }
+ }
+ return 0;
+
+err_init_ioexp_obj:
+ SWPS_DEBUG("%s: %s\n", __func__, err_msg);
+ return -1;
+}
+
+int
+init_ioexp_objs(void){
+ /* Return value:
+ * 0: Success
+ * -1: Detect topology error
+ * -2: SWPS internal error
+ */
+
+ struct ioexp_obj_s *curr_p = ioexp_head_p;
+
+ if (!curr_p) {
+ SWPS_ERR("%s: ioexp_head_p is NULL\n", __func__);
+ return -2;
+ }
+ while (curr_p) {
+ if (_init_ioexp_obj(curr_p) < 0) {
+ SWPS_DEBUG("%s: _init_ioexp_obj() fail\n", __func__);
+ return -1;
+ }
+ curr_p = curr_p->next;
+ }
+ SWPS_DEBUG("%s: done.\n", __func__);
+ return 0;
+}
+
+void
+clean_ioexp_objs(void){
+
+ struct ioexp_i2c_s *i2c_curr_p = NULL;
+ struct ioexp_i2c_s *i2c_next_p = NULL;
+ struct ioexp_obj_s *ioexp_next_p = NULL;
+ struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p;
+
+ if (ioexp_head_p == NULL){
+ ioexp_tail_p = NULL;
+ return;
+ }
+ while(ioexp_curr_p){
+ ioexp_next_p = ioexp_curr_p->next;
+ i2c_curr_p = ioexp_curr_p->i2c_head_p;
+ while (i2c_curr_p) {
+ i2c_next_p = i2c_curr_p->next;
+ kfree(i2c_curr_p->i2c_client_p);
+ kfree(i2c_curr_p);
+ i2c_curr_p = i2c_next_p;
+ }
+ kfree(ioexp_curr_p);
+ ioexp_curr_p = ioexp_next_p;
+ }
+ ioexp_tail_p = NULL;
+ SWPS_DEBUG("%s: done.\n", __func__);
+}
+
+struct ioexp_obj_s *
+get_ioexp_obj(int ioexp_id){
+
+ struct ioexp_obj_s *result_p = NULL;
+ struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p;
+
+ while(ioexp_curr_p){
+ if (ioexp_curr_p->ioexp_id == ioexp_id){
+ result_p = ioexp_curr_p;
+ break;
+ }
+ ioexp_curr_p = ioexp_curr_p->next;
+ }
+ return result_p;
+}
+int
+check_channel_tier_1(void) {
+
+ if ( (!_is_channel_ready(ioexp_head_p)) &&
+ (!_is_channel_ready(ioexp_tail_p)) ){
+ return -1;
+ }
+ return 0;
+}
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h
new file mode 100644
index 0000000000..a5541617dd
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h
@@ -0,0 +1,143 @@
+#ifndef IO_EXPANDER_H
+#define IO_EXPANDER_H
+
+#include
+
+/* IOEXP type define (QSFP series) */
+#define IOEXP_TYPE_CYPRESS_NABC (10102)
+#define IOEXP_TYPE_CYPRESS_7ABC (10207)
+
+/* IOEXP mode define */
+#define IOEXP_MODE_DIRECT (19001)
+
+/* IOEXP state define */
+#define STATE_IOEXP_NORMAL (0)
+#define STATE_IOEXP_INIT (-1)
+#define STATE_IOEXP_ABNORMAL (-2)
+
+/* IOEXP error code define */
+#define ERR_IOEXP_NOTSUPPORT (-100)
+#define ERR_IOEXP_UNINIT (-101)
+#define ERR_IOEXP_BADCONF (-102)
+#define ERR_IOEXP_BADINPUT (-105)
+#define ERR_IOEXP_UNEXCPT (-199)
+
+
+#define SWPS_INFO(fmt, args...) printk( KERN_INFO "[SWPS] " fmt, ##args)
+#define SWPS_WARN(fmt, args...) printk( KERN_WARNING "[SWPS] " fmt, ##args)
+#define SWPS_ERR(fmt, args...) printk( KERN_ERR "[SWPS] " fmt, ##args)
+
+#ifdef DEBUG_SWPS
+# define SWPS_DEBUG(fmt, args...) printk( KERN_DEBUG "[SWPS] " fmt, ##args)
+#else
+# define SWPS_DEBUG(fmt, args...)
+#endif
+
+
+struct ioexp_addr_s {
+ int chan_id;
+ int chip_addr;
+ int read_offset[8];
+ int write_offset[8];
+ int conf_offset[8];
+ uint8_t data_default[8];
+ uint8_t conf_default[8];
+};
+
+struct ioexp_i2c_s {
+ int chip_id;
+ struct i2c_client *i2c_client_p;
+ struct ioexp_i2c_s *next;
+};
+
+
+struct ioexp_bitmap_s {
+ int chip_id; /* IOEXP chip id */
+ int ioexp_voffset; /* IOEXP virtual offset */
+ int bit_shift;
+};
+
+struct ioexp_map_s {
+ int chip_amount; /* Number of chips that IOEXP object content */
+ int data_width; /* Number of (Read/Write/Config) bytes */
+ struct ioexp_addr_s *map_addr; /* Chip address info */
+ struct ioexp_bitmap_s map_present[8]; /* IOEXP for SFP / QSFP */
+ struct ioexp_bitmap_s map_tx_disable[8]; /* IOEXP for SFP */
+ struct ioexp_bitmap_s map_tx_fault[8]; /* IOEXP for SFP */
+ struct ioexp_bitmap_s map_rxlos[8]; /* IOEXP for SFP */
+ struct ioexp_bitmap_s map_reset[8]; /* IOEXP for QSFP */
+ struct ioexp_bitmap_s map_lpmod[8]; /* IOEXP for QSFP */
+ struct ioexp_bitmap_s map_modsel[8]; /* IOEXP for QSFP */
+};
+
+struct ioexp_data_s {
+ uint8_t data[8];
+};
+
+struct ioexp_obj_s {
+
+ /* ============================
+ * Object public property
+ * ============================
+ */
+ int ioexp_id;
+ int ioexp_type;
+
+ /* ============================
+ * Object private property
+ * ============================
+ */
+ struct ioexp_data_s chip_data[16]; /* Max: 8-ioexp in one virt-ioexp(ioexp_obj) */
+ struct ioexp_map_s *ioexp_map_p;
+ struct ioexp_obj_s *next;
+ struct ioexp_i2c_s *i2c_head_p;
+ struct mutex lock;
+ int mode;
+ int state;
+
+ /* ===========================================
+ * Object public functions
+ * ===========================================
+ */
+ int (*get_present)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_tx_fault)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_rxlos)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_tx_disable)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_reset)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_lpmod)(struct ioexp_obj_s *self, int virt_offset);
+ int (*get_modsel)(struct ioexp_obj_s *self, int virt_offset);
+ int (*set_tx_disable)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+ int (*set_reset)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+ int (*set_lpmod)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+ int (*set_modsel)(struct ioexp_obj_s *self, int virt_offset, int input_val);
+
+ /* ===========================================
+ * Object private functions
+ * ===========================================
+ */
+ int (*init)(struct ioexp_obj_s *self);
+ int (*update_all)(struct ioexp_obj_s *self, int show_err, char *caller_name);
+ int (*fsm_4_direct)(struct ioexp_obj_s* self);
+};
+
+
+struct ioexp_obj_s* get_ioexp_obj(int ioexp_id);
+int create_ioexp_obj(int ioexp_id,
+ int ioexp_type,
+ struct ioexp_addr_s *addr_map_p,
+ int run_mode);
+int init_ioexp_objs(void);
+void clean_ioexp_objs(void);
+
+int check_channel_tier_1(void);
+
+/* Macro for bit control */
+#define SWP_BIT_SET(byte_val,bit_shift) ((byte_val) |= (1<<(bit_shift)))
+#define SWP_BIT_CLEAR(byte_val,bit_shift) ((byte_val) &= ~(1<<(bit_shift)))
+
+
+#endif /* IO_EXPANDER_H */
+
+
+
+
diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c
new file mode 100644
index 0000000000..368e412b19
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c
@@ -0,0 +1,906 @@
+#include
+#include
+#include
+#include
+#include "io_expander.h"
+#include "transceiver.h"
+
+
+/* ========== Register EEPROM address mapping ==========
+ */
+struct eeprom_map_s eeprom_map_sfp = {
+ .addr_rx_los =-1, .page_rx_los =-1, .offset_rx_los =-1, .length_rx_los =-1,
+ .addr_tx_disable =-1, .page_tx_disable =-1, .offset_tx_disable =-1, .length_tx_disable =-1,
+ .addr_tx_fault =-1, .page_tx_fault =-1, .offset_tx_fault =-1, .length_tx_fault =-1,
+};
+
+struct eeprom_map_s eeprom_map_qsfp = {
+ .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1,
+ .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1,
+ .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1,
+};
+
+struct eeprom_map_s eeprom_map_qsfp28 = {
+ .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1,
+ .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1,
+ .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1,
+};
+
+
+/* ========== Utility Functions ==========
+ */
+void
+alarm_msg_2_user(struct transvr_obj_s *self,
+ char *emsg) {
+
+ SWPS_ERR("%s on %s.\n", emsg, self->swp_name);
+}
+
+
+/* ========== Private functions ==========
+ */
+static int
+_reload_transvr_obj(struct transvr_obj_s *self,int new_type);
+
+static int
+reload_transvr_obj(struct transvr_obj_s *self,int new_type);
+
+static int
+_transvr_init_handler(struct transvr_obj_s *self);
+
+static void
+_transvr_clean_retry(struct transvr_obj_s *self) {
+ self->retry = 0;
+}
+
+
+static int
+_transvr_handle_retry(struct transvr_obj_s *self, int retry) {
+ /* Return: 0: keep retry
+ * -1: stop retry
+ */
+ if (self->retry == 0) {
+ self->retry = retry;
+ }
+ self->retry -= 1;
+ if (self->retry <= 0) {
+ _transvr_clean_retry(self);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_common_setup_page(struct transvr_obj_s *self,
+ int addr,
+ int page,
+ int offset,
+ int len,
+ int show_e) {
+ /* return:
+ * 0 : OK
+ * -1 : EEPROM settings incorrect
+ * -2 : I2C R/W failure
+ * -3 : Undefined case
+ */
+ int retval = DEBUG_TRANSVR_INT_VAL;
+ char *emsg = DEBUG_TRANSVR_STR_VAL;
+
+ /* Check */
+ if ((addr < 0) || (offset < 0) || (len < 0)) {
+ emsg = "EEPROM settings incorrect";
+ retval = -1;
+ goto err_common_setup_page;
+ }
+ /* Case1: continue access */
+ if ((self->i2c_client_p->addr == addr) &&
+ (self->curr_page == page)) {
+ return 0;
+ }
+ self->i2c_client_p->addr = addr;
+ /* Case2: select lower page */
+ if (page == -1) {
+ self->curr_page = page;
+ return 0;
+ }
+ /* Case3: select upper page */
+ if (page >= 0) {
+ goto upper_common_setup_page;
+ }
+ /* Unexpected case */
+ show_e = 1;
+ emsg = "Unexpected case";
+ retval = -3;
+ goto err_common_setup_page;
+
+upper_common_setup_page:
+ if (i2c_smbus_write_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_PAGE_SELECT_OFFSET,
+ page) < 0) {
+ emsg = "I2C R/W failure";
+ retval = -2;
+ goto err_common_setup_page;
+ }
+ self->curr_page = page;
+ mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY);
+ return 0;
+
+err_common_setup_page:
+ if (show_e) {
+ SWPS_INFO("%s: %s", __func__, emsg);
+ SWPS_INFO("%s: :0x%02x :%d :%d :%d\n",
+ __func__, addr, page, offset, len);
+ }
+ return retval;
+}
+
+/* ========== Object functions for Final State Machine ==========
+ */
+int
+is_plugged(struct transvr_obj_s *self){
+
+ int limit = 63;
+ int present = DEBUG_TRANSVR_INT_VAL;
+ char emsg[64] = DEBUG_TRANSVR_STR_VAL;
+ struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p;
+
+ if (!ioexp_p) {
+ snprintf(emsg, limit, "ioexp_p is null!");
+ goto err_is_plugged_1;
+ }
+ present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset);
+ switch (present){
+ case 0:
+ return 1;
+ case 1:
+ return 0;
+ case ERR_IOEXP_UNINIT:
+ snprintf(emsg, limit, "ioexp_p not ready!");
+ goto err_is_plugged_1;
+ default:
+ if (ioexp_p->state == STATE_IOEXP_INIT){
+ snprintf(emsg, limit, "ioexp_p not ready!");
+ goto err_is_plugged_1;
+ }
+ break;
+ }
+ SWPS_INFO("%s: Exception case! :%d :%d\n",
+ __func__, present, ioexp_p->state);
+ return 0;
+
+err_is_plugged_1:
+ SWPS_DEBUG("%s: %s\n", __func__, emsg);
+ return 0;
+}
+
+
+static int
+detect_transvr_type(struct transvr_obj_s* self){
+
+ int type = TRANSVR_TYPE_ERROR;
+
+ self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS;
+ type = i2c_smbus_read_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_COMID_OFFSET);
+
+ /* Case: 1. Wait transceiver I2C module.
+ * 2. Transceiver I2C module failure.
+ * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there
+ * are exist some case that we need to wait transceiver.
+ * For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than
+ * state machine will keep trace with it.
+ * 2. There exist some I2C failure case we need to handle. Such as user
+ * insert the failure transceiver, or any reason cause it abnormal.
+ */
+ if (type < 0){
+ switch (type) {
+ case -EIO:
+ SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n",
+ __func__, self->swp_name);
+ return TRANSVR_TYPE_UNPLUGGED;
+ case -ENXIO:
+ SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n",
+ __func__, self->swp_name);
+ return TRANSVR_TYPE_UNPLUGGED;
+ default:
+ break;
+ }
+ SWPS_INFO("%s: %s unexpected smbus return:%d \n",
+ __func__, self->swp_name, type);
+ return TRANSVR_TYPE_ERROR;
+ }
+ /* Identify valid transceiver type */
+ switch (type){
+ case TRANSVR_TYPE_SFP:
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ break;
+ case TRANSVR_TYPE_UNKNOW_1:
+ case TRANSVR_TYPE_UNKNOW_2:
+ type = TRANSVR_TYPE_UNKNOW_2;
+ break;
+ default:
+ SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type);
+ type = TRANSVR_TYPE_ERROR;
+ break;
+ }
+ return type;
+}
+
+
+static int
+detect_transvr_state(struct transvr_obj_s *self,
+ int result[2]){
+ /* [return] [result-0] [result-1]
+ * 0 STATE_TRANSVR_CONNECTED TRANSVR_TYPE_FAKE
+ * 0 STATE_TRANSVR_DISCONNECTED TRANSVR_TYPE_UNPLUGGED
+ * 0 STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR
+ * 0 STATE_TRANSVR_INIT /
+ * 0 STATE_TRANSVR_SWAPPED
+ * 0 STATE_TRANSVR_CONNECTED
+ * ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR
+ * ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR
+ * ERR_TRANSVR_UNEXCPT STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_UNKNOW_1/2
+ */
+ result[0] = STATE_TRANSVR_UNEXCEPTED; /* For return state */
+ result[1] = TRANSVR_TYPE_ERROR; /* For return type */
+
+ /* Case1: Fake type */
+ if (self->type == TRANSVR_TYPE_FAKE){
+ result[0] = STATE_TRANSVR_CONNECTED;
+ result[1] = TRANSVR_TYPE_FAKE;
+ return 0;
+ }
+ /* Case2: Transceiver unplugged */
+ if (!is_plugged(self)){
+ result[0] = STATE_TRANSVR_DISCONNECTED;
+ result[1] = TRANSVR_TYPE_UNPLUGGED;
+ return 0;
+ }
+ /* Case3: Transceiver be isolated */
+ if (self->state == STATE_TRANSVR_ISOLATED){
+ result[0] = STATE_TRANSVR_ISOLATED;
+ result[1] = TRANSVR_TYPE_ERROR;
+ return ERR_TRNASVR_BE_ISOLATED;
+ }
+ /* Case4: Transceiver plugged */
+ result[1] = detect_transvr_type(self);
+ /* Case4.1: I2C topology crash
+ * Note : There are some I2C issues cause by transceiver/cables.
+ * We need to check topology status when user insert it.
+ * But in this step, we can't not ensure this is the issues
+ * port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper
+ * layer will diagnostic I2C topology.
+ */
+ if (check_channel_tier_1() < 0) {
+ SWPS_INFO("%s: %s detect I2C crash :%d\n",
+ __func__, self->swp_name, self->state);
+ result[0] = STATE_TRANSVR_UNEXCEPTED;
+ result[1] = TRANSVR_TYPE_ERROR;
+ return ERR_TRANSVR_I2C_CRASH;
+ }
+ /* Case4.2: System initial not ready,
+ * Note : Sometime i2c channel or transceiver EEPROM will delay that will
+ * cause system in inconsistent state between EEPROM and IOEXP.
+ * In this case, SWP transceiver object keep state at LINK_DOWN
+ * to wait system ready.
+ * By the way, State Machine will handle these case.
+ */
+ if (result[1] == TRANSVR_TYPE_UNPLUGGED){
+ result[0] = STATE_TRANSVR_DISCONNECTED;
+ return 0;
+ }
+ /* Case4.3: Error transceiver type */
+ if (result[1] == TRANSVR_TYPE_ERROR){
+ result[0] = STATE_TRANSVR_ISOLATED;
+ SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name);
+ alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!");
+ return ERR_TRNASVR_BE_ISOLATED;
+ }
+ /* Case3.3: Unknow transceiver type */
+ if ((result[1] == TRANSVR_TYPE_UNKNOW_1) ||
+ (result[1] == TRANSVR_TYPE_UNKNOW_2) ){
+ result[0] = STATE_TRANSVR_UNEXCEPTED;
+ return ERR_TRANSVR_UNEXCPT;
+ }
+ /* Case3.4: During initial process */
+ if (self->state == STATE_TRANSVR_INIT){
+ result[0] = STATE_TRANSVR_INIT;
+ return 0;
+ }
+ /* Case3.5: Transceiver be swapped */
+ if (self->type != result[1]){
+ result[0] = STATE_TRANSVR_SWAPPED;
+ return 0;
+ }
+ /* Case3.6: Link up state */
+ result[0] = STATE_TRANSVR_CONNECTED;
+ return 0;
+}
+int
+common_fsm_4_direct_mode(struct transvr_obj_s* self,
+ char *caller_name){
+
+ int err;
+ int detect_result[2];
+ int current_state = STATE_TRANSVR_UNEXCEPTED;
+ int current_type = TRANSVR_TYPE_ERROR;
+
+ if (self->state == STATE_TRANSVR_NEW) {
+ if (_transvr_init_handler(self) < 0){
+ return ERR_TRANSVR_INIT_FAIL;
+ }
+ }
+ err = detect_transvr_state(self, detect_result);
+ if (err < 0) {
+ return err;
+ }
+ /* In Direct mode, driver only detect transceiver when user call driver interface
+ * which on sysfs. So it only need consider the state of Transceiver.
+ */
+ current_state = detect_result[0];
+ current_type = detect_result[1];
+
+ switch (current_state){
+
+ case STATE_TRANSVR_DISCONNECTED: /* Transceiver is not plugged */
+ self->state = current_state;
+ self->type = current_type;
+ return ERR_TRANSVR_UNPLUGGED;
+
+ case STATE_TRANSVR_INIT: /* Transceiver is plugged, system not ready */
+ return ERR_TRANSVR_UNINIT;
+
+ case STATE_TRANSVR_ISOLATED: /* Transceiver is plugged, but has some issues */
+ return ERR_TRNASVR_BE_ISOLATED;
+
+ case STATE_TRANSVR_CONNECTED: /* Transceiver is plugged, system is ready */
+ self->state = current_state;
+ self->type = current_type;
+ return 0;
+
+ case STATE_TRANSVR_SWAPPED: /* Transceiver is plugged, system detect user changed */
+ self->type = current_type;
+ if (reload_transvr_obj(self, current_type) < 0){
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ return ERR_TRANSVR_UNEXCPT;
+ }
+ self->state = current_state;
+ return 0;
+
+ case STATE_TRANSVR_UNEXCEPTED: /* Transceiver type or state is unexpected case */
+ self->state = STATE_TRANSVR_UNEXCEPTED;
+ self->type = TRANSVR_TYPE_ERROR;
+ return ERR_TRANSVR_UNEXCPT;
+
+ default:
+ SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state);
+ break;
+ }
+ return ERR_TRANSVR_UNEXCPT;
+}
+
+int
+fake_fsm_4_direct_mode(struct transvr_obj_s* self,
+ char *caller_name){
+ self->state = STATE_TRANSVR_CONNECTED;
+ self->type = TRANSVR_TYPE_FAKE;
+ return 0;
+}
+
+/* ========== Object Initial handler ==========
+ */
+static int
+_is_transvr_valid(struct transvr_obj_s *self,
+ int type,
+ int state) {
+ /* [Return]
+ * 0 : OK, inserted
+ * EVENT_TRANSVR_INIT_DOWN : OK, removed
+ * EVENT_TRANSVR_INIT_FAIL : Outside error, type doesn't supported
+ * EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined
+ */
+ switch (type) {
+ case TRANSVR_TYPE_SFP:
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ case TRANSVR_TYPE_UNPLUGGED:
+ case TRANSVR_TYPE_FAKE:
+ break;
+ default:
+ SWPS_INFO("detect undefined type:0x%02x on %s\n",
+ type, self->swp_name);
+ return EVENT_TRANSVR_INIT_FAIL;
+ }
+ switch (state) {
+ case STATE_TRANSVR_DISCONNECTED:
+ return EVENT_TRANSVR_INIT_DOWN;
+ case STATE_TRANSVR_INIT:
+ case STATE_TRANSVR_CONNECTED:
+ case STATE_TRANSVR_SWAPPED:
+ break;
+ default:
+ SWPS_INFO("detect undefined state:%d on %s\n",
+ state, self->swp_name);
+ return EVENT_TRANSVR_EXCEP_INIT;
+ }
+ return 0;
+}
+
+
+static int
+_is_transvr_hw_ready(struct transvr_obj_s *self,
+ int type){
+ /* [Return]
+ * EVENT_TRANSVR_TASK_DONE : Ready
+ * EVENT_TRANSVR_TASK_WAIT : Not ready
+ * EVENT_TRANSVR_INIT_FAIL : Error
+ */
+ int addr = DEBUG_TRANSVR_INT_VAL;
+ int page = DEBUG_TRANSVR_INT_VAL;
+ int offs = DEBUG_TRANSVR_INT_VAL;
+ int bit = DEBUG_TRANSVR_INT_VAL;
+ int ready = DEBUG_TRANSVR_INT_VAL;
+ int err = DEBUG_TRANSVR_INT_VAL;
+ char *emsg = DEBUG_TRANSVR_STR_VAL;
+ uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL;
+
+ switch (type) {
+ case TRANSVR_TYPE_SFP:
+ addr = VAL_TRANSVR_8472_READY_ADDR;
+ page = VAL_TRANSVR_8472_READY_PAGE;
+ offs = VAL_TRANSVR_8472_READY_OFFSET;
+ bit = VAL_TRANSVR_8472_READY_BIT;
+ ready = VAL_TRANSVR_8472_READY_VALUE;
+ ab_val = VAL_TRANSVR_8472_READY_ABNORMAL;
+ break;
+
+ case TRANSVR_TYPE_QSFP:
+ case TRANSVR_TYPE_QSFP_PLUS:
+ case TRANSVR_TYPE_QSFP_28:
+ addr = VAL_TRANSVR_8436_READY_ADDR;
+ page = VAL_TRANSVR_8436_READY_PAGE;
+ offs = VAL_TRANSVR_8436_READY_OFFSET;
+ bit = VAL_TRANSVR_8436_READY_BIT;
+ ready = VAL_TRANSVR_8436_READY_VALUE;
+ ab_val = VAL_TRANSVR_8436_READY_ABNORMAL;
+ break;
+
+ case TRANSVR_TYPE_UNPLUGGED:
+ case TRANSVR_TYPE_FAKE:
+ return EVENT_TRANSVR_TASK_DONE;
+
+ default:
+ emsg = "unexpected case";
+ goto err_is_transvr_hw_ready;
+ }
+ /* Select target page */
+ err = _common_setup_page(self, addr, page, offs, 1, 0);
+ if (err < 0) {
+ emsg = "setup page fail";
+ goto err_is_transvr_hw_ready;
+ }
+ /* Check feature supported
+ * [Note]
+ * Some of transceiver/cables doesn't support "Status Indicators"
+ * (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the
+ * step of checking Status Indicators, then state machine will take
+ * the following handle procedure.
+ */
+ err = i2c_smbus_read_byte_data(self->i2c_client_p,
+ VAL_TRANSVR_COMID_OFFSET);
+ if (err < 0) {
+ emsg = "doesn't support Status Indicators";
+ goto bypass_is_transvr_hw_ready;
+ }
+ /* Filter abnormal case */
+ if (err == ab_val) {
+ emsg = "detect using unusual definition.";
+ goto bypass_is_transvr_hw_ready;
+ }
+ /* Get Status Indicators */
+ err = i2c_smbus_read_byte_data(self->i2c_client_p, offs);
+ if (err < 0) {
+ emsg = "detect current value fail";
+ goto err_is_transvr_hw_ready;
+ }
+ if ((err & (1<