diff --git a/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/port_config.ini b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/port_config.ini
new file mode 100644
index 000000000000..fd2022dc2c9d
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/port_config.ini
@@ -0,0 +1,33 @@
+# name lanes alias
+Ethernet0 49,50,51,52 fortyGigE1
+Ethernet4 53,54,55,56 fortyGigE2
+Ethernet8 57,58,59,60 fortyGigE3
+Ethernet12 61,62,63,64 fortyGigE4
+Ethernet16 65,66,67,68 fortyGigE5
+Ethernet20 69,70,71,72 fortyGigE6
+Ethernet24 73,74,75,76 fortyGigE7
+Ethernet28 77,78,79,80 fortyGigE8
+Ethernet32 33,34,35,36 fortyGigE9
+Ethernet36 37,38,39,40 fortyGigE10
+Ethernet40 41,42,43,44 fortyGigE11
+Ethernet44 45,46,47,48 fortyGigE12
+Ethernet48 81,82,83,84 fortyGigE13
+Ethernet52 85,86,87,88 fortyGigE14
+Ethernet56 89,90,91,92 fortyGigE15
+Ethernet60 93,94,95,96 fortyGigE16
+Ethernet64 97,98,99,100 fortyGigE17
+Ethernet68 101,102,103,104 fortyGigE18
+Ethernet72 105,106,107,108 fortyGigE19
+Ethernet76 109,110,111,112 fortyGigE20
+Ethernet80 17,18,19,20 fortyGigE21
+Ethernet84 21,22,23,24 fortyGigE22
+Ethernet88 25,26,27,28 fortyGigE23
+Ethernet92 29,30,31,32 fortyGigE24
+Ethernet96 113,114,115,116 fortyGigE25
+Ethernet100 117,118,119,120 fortyGigE26
+Ethernet104 121,122,123,124 fortyGigE27
+Ethernet108 125,126,127,128 fortyGigE28
+Ethernet112 1,2,3,4 fortyGigE29
+Ethernet116 5,6,7,8 fortyGigE30
+Ethernet120 9,10,11,12 fortyGigE31
+Ethernet124 13,14,15,16 fortyGigE32
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/sai.profile b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/sai.profile
new file mode 100644
index 000000000000..22432e548b4a
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/sai.profile
@@ -0,0 +1 @@
+SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as6712-32x40G.config.bcm
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/td2-as6712-32x40G.config.bcm b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/td2-as6712-32x40G.config.bcm
new file mode 100644
index 000000000000..54f3c366fdc4
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/td2-as6712-32x40G.config.bcm
@@ -0,0 +1,132 @@
+os=unix
+bcm_stat_flags=0
+parity_enable=0
+parity_correction=0
+
+l2_mem_entries=163840
+l3_mem_entries=81920
+mmu_lossless=0
+lls_num_l2uc=12
+module_64ports=0
+
+#SFI
+serdes_if_type=9
+
+port_init_cl72=0
+phy_an_c73=5 # TSCMOD_CL73_CL37
+
+#sdk6.5.5 only supports 156(default) or 125
+#xgxs_lcpll_xtal_refclk=1
+tslam_dma_enable=1
+table_dma_enable=1
+
+#for 32x40G ports for breakout mode
+pbmp_oversubscribe=0x1fffffffe
+pbmp_xport_xe=0x1fffffffe
+
+rate_ext_mdio_divisor=96
+
+#QSFP+ 1 from WC0
+portmap_1=1:40
+
+#QSFP+ 2 from WC1
+portmap_2=5:40
+
+#QSFP+ 3 from WC2
+portmap_3=9:40
+
+#QSFP+ 4 from WC3
+portmap_4=13:40
+
+#QSFP+ 5 from WC4
+portmap_5=17:40
+
+#QSFP+ 6 from WC5
+portmap_6=21:40
+
+#QSFP+ 7 from WC6
+portmap_7=25:40
+
+#QSFP+ 8 from WC7
+portmap_8=29:40
+
+#QSFP+ 9 from WC8
+portmap_9=33:40
+
+#QSFP+ 10 from WC9
+portmap_10=37:40
+
+#QSFP+ 11 from WC10
+portmap_11=41:40
+
+#QSFP+ 12 from WC11
+portmap_12=45:40
+
+#QSFP+ 13 from WC12
+portmap_13=49:40
+
+#QSFP+ 14 from WC13
+portmap_14=53:40
+
+#QSFP+ 15 from WC14
+portmap_15=57:40
+
+#QSFP+ 16 from WC15
+portmap_16=61:40
+
+#QSFP+ 17 from WC16
+portmap_17=65:40
+
+#QSFP+ 18 from WC17
+portmap_18=69:40
+
+#QSFP+ 19 from WC18
+portmap_19=73:40
+
+#QSFP+ 20 from WC19
+portmap_20=77:40
+
+#QSFP+ 21 from WC20
+portmap_21=81:40
+
+#QSFP+ 22 from WC21
+portmap_22=85:40
+
+#QSFP+ 23 from WC22
+portmap_23=89:40
+
+#QSFP+ 24 from WC23
+portmap_24=93:40
+
+#QSFP+ 25 from WC24
+portmap_25=97:40
+
+#QSFP+ 26 from WC25
+portmap_26=101:40
+
+#QSFP+ 27 from WC26
+portmap_27=105:40
+
+#QSFP+ 28 from WC27
+portmap_28=109:40
+
+#QSFP+ 29 from WC28
+portmap_29=113:40
+
+#QSFP+ 30 from WC29
+portmap_30=117:40
+
+#QSFP+ 31 from WC30
+portmap_31=121:40
+
+#QSFP+ 32 from WC31
+portmap_32=125:40
+
+# L3 ECMP
+# - In Trident2, VP LAGs share the same table as ECMP group table.
+# The first N entries are reserved for VP LAGs, where N is the value of the
+# config property "max_vp_lags". By default this was set to 256
+l3_max_ecmp_mode=1
+max_vp_lags=0
+
+stable_size=0x2000000
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/default_sku b/device/accton/x86_64-accton_as6712_32x-r0/default_sku
new file mode 100644
index 000000000000..d8cdd655905b
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/default_sku
@@ -0,0 +1 @@
+Accton-AS6712-32X t1
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/installer.conf b/device/accton/x86_64-accton_as6712_32x-r0/installer.conf
new file mode 100644
index 000000000000..14404194ef53
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/installer.conf
@@ -0,0 +1,3 @@
+CONSOLE_PORT=0x2f8
+CONSOLE_DEV=1
+CONSOLE_SPEED=115200
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as6712_32x-r0/led_proc_init.soc
new file mode 100644
index 000000000000..9e29adf790de
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/led_proc_init.soc
@@ -0,0 +1,104 @@
+# LED setting for active
+# -----------------------------------------------------------------------------
+# for as6712_32x (32 qxg)
+# -----------------------------------------------------------------------------
+
+s CMIC_LEDUP0_DATA_RAM 0
+s CMIC_LEDUP1_DATA_RAM 0
+
+m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0
+m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=1
+m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=2
+m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=3
+m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=4
+m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=5
+m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=6
+m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=7
+
+m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=8
+m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=9
+m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=10
+m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=11
+m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=12
+m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=13
+m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=14
+m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=15
+
+
+m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=63
+m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=62
+m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=61
+m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=60
+m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=59
+m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=58
+m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=57
+m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=56
+m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=55
+m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=54
+m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=53
+m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=52
+m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=51
+m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=50
+m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=49
+m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=48
+m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=47
+m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=46
+m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=45
+m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=44
+m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=43
+m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=42
+m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=41
+m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=40
+m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=39
+m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=38
+m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=37
+m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=36
+m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=35
+m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=34
+m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=33
+m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=32
+m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=31
+m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=30
+m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=29
+m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=28
+m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=27
+m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=26
+m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=25
+m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=24
+m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=23
+m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=22
+m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=21
+m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=20
+m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=19
+m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=18
+m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=17
+m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=16
+
+
+led 0 stop
+led 0 prog \
+ 02 F9 42 80 02 F7 42 00 02 F8 42 00 02 F4 42 90 02 \
+ F3 42 10 67 6A 67 6A 67 38 67 6A 67 6A 67 6A 67 6A \
+ 67 6A 67 6A 86 F8 06 F3 D6 F8 74 14 86 F0 3E F4 67 \
+ 6A 57 67 7E 57 06 F8 88 80 4A 00 27 97 75 35 90 4A \
+ 00 27 4A 01 27 B7 97 71 4F 77 32 06 F5 D6 F0 74 62 \
+ 02 F5 4A 07 37 4E 07 02 F0 42 00 4E 07 02 F5 4A 07 \
+ 71 32 77 35 16 F7 06 F9 17 4D DA 07 74 7B 12 F7 52 \
+ 00 86 F9 57 86 F7 57 16 F7 06 F9 07 4D DA 07 74 8F \
+ 12 F7 52 00 86 F9 57 86 F7 57 00 00 00 00 00 00 00 \
+ 00 00 00 00 00 00 00
+led 0 start
+
+led 1 stop
+led 1 prog \
+ 02 F9 42 80 02 F7 42 00 02 F8 42 01 02 F4 42 90 02 \
+ F3 42 11 67 6A 67 6A 67 38 67 6A 67 6A 67 6A 67 6A \
+ 67 6A 67 6A 86 F8 06 F3 D6 F8 74 14 86 F0 3E F4 67 \
+ 6A 57 67 7E 57 06 F8 88 80 4A 00 27 97 75 35 90 4A \
+ 00 27 4A 01 27 B7 97 71 4F 77 32 06 F5 D6 F0 74 62 \
+ 02 F5 4A 07 37 4E 07 02 F0 42 00 4E 07 02 F5 4A 07 \
+ 71 32 77 35 16 F7 06 F9 17 4D DA 07 74 7B 12 F7 52 \
+ 00 86 F9 57 86 F7 57 16 F7 06 F9 07 4D DA 07 74 8F \
+ 12 F7 52 00 86 F9 57 86 F7 57 00 00 00 00 00 00 00 \
+ 00 00 00 00 00 00 00
+led 1 start
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as6712_32x-r0/plugins/eeprom.py
new file mode 100644
index 000000000000..7681caafeef4
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/plugins/eeprom.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+try:
+ import exceptions
+ import binascii
+ import time
+ import optparse
+ import warnings
+ import os
+ import sys
+ from sonic_eeprom import eeprom_base
+ from sonic_eeprom import eeprom_tlvinfo
+ import subprocess
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+ _TLV_INFO_MAX_LEN = 256
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
+ #Two i2c buses might get flipped order, check them both.
+ if not os.path.exists(self.eeprom_path):
+ self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as6712_32x-r0/plugins/psuutil.py
new file mode 100644
index 000000000000..191654429e6b
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/plugins/psuutil.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Accton
+#
+# Module contains an implementation of SONiC PSU Base API and
+# provides the PSUs status which are available in the platform
+#
+#############################################################################
+
+import os.path
+
+try:
+ from sonic_psu.psu_base import PsuBase
+except ImportError as e:
+ raise ImportError (str(e) + "- required module not found")
+
+class PsuUtil(PsuBase):
+ """Platform-specific PSUutil class"""
+
+ def __init__(self):
+ PsuBase.__init__(self)
+
+ self.psu_path = "/sys/bus/i2c/devices/"
+ self.psu_presence = "/psu_present"
+ self.psu_oper_status = "/psu_power_good"
+ self.psu_mapping = {
+ 1: "35-0038",
+ 2: "36-003b",
+ }
+
+ def get_num_psus(self):
+ return len(self.psu_mapping)
+
+ def get_psu_status(self, index):
+ if index is None:
+ return False
+
+ status = 0
+ node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status
+ try:
+ with open(node, 'r') as power_status:
+ status = int(power_status.read())
+ except IOError:
+ return False
+
+ return status == 1
+
+ def get_psu_presence(self, index):
+ if index is None:
+ return False
+
+ status = 0
+ node = self.psu_path + self.psu_mapping[index] + self.psu_presence
+ try:
+ with open(node, 'r') as presence_status:
+ status = int(presence_status.read())
+ except IOError:
+ return False
+
+ return status == 1
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as6712_32x-r0/plugins/sfputil.py
new file mode 100644
index 000000000000..3c93649d760e
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/plugins/sfputil.py
@@ -0,0 +1,215 @@
+# sfputil.py
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
+
+try:
+ import time
+ import os
+ 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 = 31
+ PORTS_IN_BLOCK = 32
+ QSFP_PORT_START = 0
+ QSFP_PORT_END = 32
+
+ I2C_DEV_PATH = "/sys/bus/i2c/devices/"
+ BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{1}-0050/"
+ BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
+ CPLD_ADDRESS = ['-0062', '-0064']
+
+ _port_to_is_present = {}
+ _port_to_lp_mode = {}
+
+ _port_to_eeprom_mapping = {}
+ _port_to_i2c_mapping = {
+ 0: [1, 2],
+ 1: [2, 3],
+ 2: [3, 4],
+ 3: [4, 5],
+ 4: [5, 6],
+ 5: [6, 7],
+ 6: [7, 8],
+ 7: [8, 9],
+ 8: [9, 10],
+ 9: [10, 11],
+ 10: [11, 12],
+ 11: [12, 13],
+ 12: [13, 14],
+ 13: [14, 15],
+ 14: [15, 16],
+ 15: [16, 17],
+ 16: [17, 18],
+ 17: [18, 19],
+ 18: [19, 20],
+ 19: [20, 21],
+ 20: [21, 22],
+ 21: [22, 23],
+ 22: [23, 24],
+ 23: [24, 25],
+ 24: [25, 26],
+ 25: [26, 27],
+ 26: [27, 28],
+ 27: [28, 29],
+ 28: [29, 30],
+ 29: [30, 31],
+ 30: [31, 32],
+ 31: [32, 33],
+ 32: [33, 34],
+ 33: [34, 35],
+ 34: [35, 36],
+ 35: [36, 37],
+ 36: [37, 38],
+ 37: [38, 39],
+ 38: [39, 40],
+ 39: [40, 41],
+ 40: [41, 42],
+ 41: [42, 43],
+ 42: [43, 44],
+ 43: [44, 45],
+ 44: [45, 46],
+ 45: [46, 47],
+ 46: [47, 48],
+ 47: [48, 49],
+ 48: [49, 50],#QSFP49
+ 49: [49, 50],
+ 50: [49, 50],
+ 51: [49, 50],
+ 52: [50, 52],#QSFP50
+ 53: [50, 52],
+ 54: [50, 52],
+ 55: [50, 52],
+ 56: [51, 54],#QSFP51
+ 57: [51, 54],
+ 58: [51, 54],
+ 59: [51, 54],
+ 60: [52, 51],#QSFP52
+ 61: [52, 51],
+ 62: [52, 51],
+ 63: [52, 51],
+ 64: [53, 53], #QSFP53
+ 65: [53, 53],
+ 66: [53, 53],
+ 67: [53, 53],
+ 68: [54, 55],#QSFP54
+ 69: [54, 55],
+ 70: [54, 55],
+ 71: [54, 55],
+ }
+
+ @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(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ def __init__(self):
+ eeprom_path = self.BASE_OOM_PATH + "eeprom"
+
+ for x in range(0, self.port_end+1):
+ self.port_to_eeprom_mapping[x] = eeprom_path.format(
+ self._port_to_i2c_mapping[x][1]
+ )
+
+ SfpUtilBase.__init__(self)
+
+ def get_cpld_dev_path(self, port_num):
+ if port_num < 16:
+ cpld_num = 0
+ else:
+ cpld_num = 1
+
+ #cpld can be at either bus 0 or bus 1.
+ cpld_path = self.I2C_DEV_PATH + str(0) + self.CPLD_ADDRESS[cpld_num]
+ if not os.path.exists(cpld_path):
+ cpld_path = self.I2C_DEV_PATH + str(1) + self.CPLD_ADDRESS[cpld_num]
+ return cpld_path
+
+ 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
+
+ cpld_path = self.get_cpld_dev_path(port_num)
+ present_path = cpld_path + "/module_present_"
+ present_path += str(self._port_to_i2c_mapping[port_num][0])
+
+ self.__port_to_is_present = present_path
+
+ try:
+ val_file = open(self.__port_to_is_present)
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = val_file.readline().rstrip()
+ val_file.close()
+
+ # content is a string, either "0" or "1"
+ if content == "1":
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ raise NotImplementedError
+
+ def set_low_power_mode(self, port_num, lpmode):
+ raise NotImplementedError
+
+ def reset(self, port_num):
+ if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
+ return False
+
+ cpld_path = self.get_cpld_dev_path(port_num)
+ _path = cpld_path + "/module_reset_"
+ _path += str(self._port_to_i2c_mapping[port_num][0])
+
+ try:
+ reg_file = open(_path, 'w')
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_file.seek(0)
+ reg_file.write('1')
+ time.sleep(1)
+ reg_file.seek(0)
+ reg_file.write('0')
+ reg_file.close()
+
+ return True
+
+ def get_transceiver_change_event(self):
+ """
+ TODO: This function need to be implemented
+ when decide to support monitoring SFP(Xcvrd)
+ on this platform.
+ """
+ raise NotImplementedError
+
diff --git a/device/accton/x86_64-accton_as6712_32x-r0/sensors.conf b/device/accton/x86_64-accton_as6712_32x-r0/sensors.conf
new file mode 100644
index 000000000000..84ee0fd9f333
--- /dev/null
+++ b/device/accton/x86_64-accton_as6712_32x-r0/sensors.conf
@@ -0,0 +1,23 @@
+# libsensors configuration file for AS6712-32X
+# ------------------------------------------------
+
+chip "cpr_4011_4mxx-i2c-*-3c"
+ label in1 "PSU1_VIN"
+ label in2 "PSU1_VOUT"
+ label curr1 "PSU1_IIN"
+ label curr2 "PSU1_IOUT"
+ label power1 "PSU1_PIN"
+ label power2 "PSU1_POUT"
+ label fan1 "PSU1_FAN"
+ label temp1 "PSU1_TEMP"
+
+chip "cpr_4011_4mxx-i2c-*-3f"
+ label in1 "PSU2_VIN"
+ label in2 "PSU2_VOUT"
+ label curr1 "PSU2_IIN"
+ label curr2 "PSU2_IOUT"
+ label power1 "PSU2_PIN"
+ label power2 "PSU2_POUT"
+ label fan1 "PSU2_FAN"
+ label temp1 "PSU2_TEMP"
+
diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk
index 8f56a6cf50ad..61794979a753 100755
--- a/platform/broadcom/one-image.mk
+++ b/platform/broadcom/one-image.mk
@@ -20,6 +20,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(ACCTON_AS7312_54X_PLATFORM_MODULE) \
$(ACCTON_AS7326_56X_PLATFORM_MODULE) \
$(ACCTON_AS7716_32XB_PLATFORM_MODULE) \
+ $(ACCTON_AS6712_32X_PLATFORM_MODULE) \
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7264Q28B_PLATFORM_MODULE) \
diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk
index 729e76e3ed1d..72c2453c5359 100755
--- a/platform/broadcom/platform-modules-accton.mk
+++ b/platform/broadcom/platform-modules-accton.mk
@@ -7,6 +7,7 @@ ACCTON_AS7716_32X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION = 1.1
+ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1
export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION
@@ -15,6 +16,7 @@ export ACCTON_AS7716_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION
export ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION
export ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION
+export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION
ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton
@@ -46,4 +48,8 @@ ACCTON_AS7716_32XB_PLATFORM_MODULE = sonic-platform-accton-as7716-32xb_$(ACCTON_
$(ACCTON_AS7716_32XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7716_32xb-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7716_32XB_PLATFORM_MODULE)))
+ACCTON_AS6712_32X_PLATFORM_MODULE = sonic-platform-accton-as6712-32x_$(ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
+$(ACCTON_AS6712_32X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as6712_32x-r0
+$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS6712_32X_PLATFORM_MODULE)))
+
SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE)
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/fanutil.py
new file mode 100644
index 000000000000..73d020acccce
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/fanutil.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Accton Technology Corporation
+#
+# 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 .
+
+# ------------------------------------------------------------------
+# HISTORY:
+# mm/dd/yyyy (A.D.)
+# 11/13/2017: Polly Hsu, Create
+# 1/10/2018: Jostar modify for as7716_32
+# 3/32/2018: Roy Lee modify for as7326_56x
+# ------------------------------------------------------------------
+
+try:
+ import time
+ import logging
+ from collections import namedtuple
+except ImportError as e:
+ raise ImportError('%s - required module not found' % str(e))
+
+
+class FanUtil(object):
+ """Platform-specific FanUtil class"""
+
+ FAN_NUM_ON_MAIN_BROAD = 5
+ FAN_NUM_1_IDX = 1
+ FAN_NUM_2_IDX = 2
+ FAN_NUM_3_IDX = 3
+ FAN_NUM_4_IDX = 4
+ FAN_NUM_5_IDX = 5
+
+ FAN_NODE_NUM_OF_MAP = 2
+ FAN_NODE_FAULT_IDX_OF_MAP = 1
+ #FAN_NODE_SPEED_IDX_OF_MAP = 2
+ FAN_NODE_DIR_IDX_OF_MAP = 2
+ #FAN_NODE_DUTY_IDX_OF_MAP = 4
+ #FANR_NODE_FAULT_IDX_OF_MAP = 5
+
+ #BASE_VAL_PATH = '/sys/bus/i2c/devices/11-0066/{0}'
+ #FAN_DUTY_PATH = '/sys/bus/i2c/devices/11-0066/fan_duty_cycle_percentage'
+ BASE_VAL_PATH = '/sys/devices/platform/as6712_32x_fan/{0}'
+ FAN_DUTY_PATH = '/sys/devices/platform/as6712_32x_fan/fan1_duty_cycle_percentage'
+
+ #logfile = ''
+ #loglevel = logging.INFO
+
+ """ Dictionary where
+ key1 = fan id index (integer) starting from 1
+ key2 = fan node index (interger) starting from 1
+ value = path to fan device file (string) """
+ _fan_to_device_path_mapping = {}
+
+#fan1_direction
+#fan1_fault
+#fan1_present
+
+ #(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
+ _fan_to_device_node_mapping = {
+ (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault',
+ (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction',
+
+ (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault',
+ (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction',
+
+ (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault',
+ (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction',
+
+ (FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault',
+ (FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction',
+
+ (FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault',
+ (FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction',
+
+ }
+
+ def _get_fan_to_device_node(self, fan_num, node_num):
+ return self._fan_to_device_node_mapping[(fan_num, node_num)]
+
+ def _get_fan_node_val(self, fan_num, node_num):
+ if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
+ logging.debug('GET. Parameter error. fan_num:%d', fan_num)
+ return None
+
+ if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
+ logging.debug('GET. Parameter error. node_num:%d', node_num)
+ return None
+
+ device_path = self.get_fan_to_device_path(fan_num, node_num)
+
+ try:
+ val_file = open(device_path, 'r')
+ except IOError as e:
+ logging.error('GET. unable to open file: %s', str(e))
+ return None
+
+ content = val_file.readline().rstrip()
+
+ if content == '':
+ logging.debug('GET. content is NULL. device_path:%s', device_path)
+ return None
+
+ try:
+ val_file.close()
+ except:
+ logging.debug('GET. unable to close file. device_path:%s', device_path)
+ return None
+
+ return int(content)
+
+ def _set_fan_node_val(self, fan_num, node_num, val):
+ if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
+ logging.debug('GET. Parameter error. fan_num:%d', fan_num)
+ return None
+
+ if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
+ logging.debug('GET. Parameter error. node_num:%d', node_num)
+ return None
+
+ content = str(val)
+ if content == '':
+ logging.debug('GET. content is NULL. device_path:%s', device_path)
+ return None
+
+ device_path = self.get_fan_to_device_path(fan_num, node_num)
+ try:
+ val_file = open(device_path, 'w')
+ except IOError as e:
+ logging.error('GET. unable to open file: %s', str(e))
+ return None
+
+ val_file.write(content)
+
+ try:
+ val_file.close()
+ except:
+ logging.debug('GET. unable to close file. device_path:%s', device_path)
+ return None
+
+ return True
+
+ def __init__(self):
+ fan_path = self.BASE_VAL_PATH
+
+ for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1):
+ for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1):
+ self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format(
+ self._fan_to_device_node_mapping[(fan_num, node_num)])
+
+ def get_num_fans(self):
+ return self.FAN_NUM_ON_MAIN_BROAD
+
+ def get_idx_fan_start(self):
+ return self.FAN_NUM_1_IDX
+
+ def get_num_nodes(self):
+ return self.FAN_NODE_NUM_OF_MAP
+
+ def get_idx_node_start(self):
+ return self.FAN_NODE_FAULT_IDX_OF_MAP
+
+ def get_size_node_map(self):
+ return len(self._fan_to_device_node_mapping)
+
+ def get_size_path_map(self):
+ return len(self._fan_to_device_path_mapping)
+
+ def get_fan_to_device_path(self, fan_num, node_num):
+ return self._fan_to_device_path_mapping[(fan_num, node_num)]
+
+ def get_fan_fault(self, fan_num):
+ return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP)
+
+ #def get_fan_speed(self, fan_num):
+ # return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP)
+
+ def get_fan_dir(self, fan_num):
+ return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP)
+
+ def get_fan_duty_cycle(self):
+ #duty_path = self.FAN_DUTY_PATH
+ try:
+ val_file = open(self.FAN_DUTY_PATH)
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = val_file.readline().rstrip()
+ val_file.close()
+
+ return int(content)
+ #self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP)
+#static u32 reg_val_to_duty_cycle(u8 reg_val)
+#{
+# reg_val &= FAN_DUTY_CYCLE_REG_MASK;
+# return ((u32)(reg_val+1) * 625 + 75)/ 100;
+#}
+#
+ def set_fan_duty_cycle(self, val):
+
+ try:
+ fan_file = open(self.FAN_DUTY_PATH, 'r+')
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+ #val = ((val + 1 ) * 625 +75 ) / 100
+ fan_file.write(str(val))
+ fan_file.close()
+ return True
+
+ #def get_fanr_fault(self, fan_num):
+ # return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP)
+
+ def get_fanr_speed(self, fan_num):
+ return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP)
+
+ def get_fan_status(self, fan_num):
+ if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
+ logging.debug('GET. Parameter error. fan_num, %d', fan_num)
+ return None
+
+ if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0:
+ logging.debug('GET. FAN fault. fan_num, %d', fan_num)
+ return False
+
+ #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0:
+ # logging.debug('GET. FANR fault. fan_num, %d', fan_num)
+ # return False
+
+ return True
+
+#def main():
+# fan = FanUtil()
+#
+# print 'get_size_node_map : %d' % fan.get_size_node_map()
+# print 'get_size_path_map : %d' % fan.get_size_path_map()
+# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
+# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
+# print fan.get_fan_to_device_path(x, y)
+#
+#if __name__ == '__main__':
+# main()
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/thermalutil.py
new file mode 100644
index 000000000000..8fdb01ecc564
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/thermalutil.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Accton Technology Corporation
+#
+# 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 .
+
+# ------------------------------------------------------------------
+# HISTORY:
+# mm/dd/yyyy (A.D.)
+# 11/13/2017: Polly Hsu, Create
+# 1/10/2018:Jostar modify for as7716_32x
+# 3/23/2018: Roy Lee modify for as7326_56x
+# ------------------------------------------------------------------
+
+try:
+ import time
+ import logging
+ import glob
+ from collections import namedtuple
+except ImportError as e:
+ raise ImportError('%s - required module not found' % str(e))
+
+
+class ThermalUtil(object):
+ """Platform-specific ThermalUtil class"""
+
+ THERMAL_NUM_ON_MAIN_BROAD = 3
+ THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD
+ THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD
+ THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD
+
+ BASE_VAL_PATH = '/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input'
+
+ """ Dictionary where
+ key1 = thermal id index (integer) starting from 1
+ value = path to fan device file (string) """
+ _thermal_to_device_path_mapping = {}
+
+ _thermal_to_device_node_mapping = {
+ THERMAL_NUM_1_IDX: ['38', '48'],
+ THERMAL_NUM_2_IDX: ['39', '49'],
+ THERMAL_NUM_3_IDX: ['40', '4a'],
+ }
+
+ def __init__(self):
+ thermal_path = self.BASE_VAL_PATH
+
+ for x in range(self.THERMAL_NUM_1_IDX, self.THERMAL_NUM_ON_MAIN_BROAD+1):
+ self._thermal_to_device_path_mapping[x] = thermal_path.format(
+ self._thermal_to_device_node_mapping[x][0],
+ self._thermal_to_device_node_mapping[x][1])
+
+ def _get_thermal_node_val(self, thermal_num):
+ if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_ON_MAIN_BROAD:
+ logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
+ return None
+
+ device_path = self.get_thermal_to_device_path(thermal_num)
+ for filename in glob.glob(device_path):
+ try:
+ val_file = open(filename, 'r')
+ except IOError as e:
+ logging.error('GET. unable to open file: %s', str(e))
+ return None
+
+ content = val_file.readline().rstrip()
+
+ if content == '':
+ logging.debug('GET. content is NULL. device_path:%s', device_path)
+ return None
+
+ try:
+ val_file.close()
+ except:
+ logging.debug('GET. unable to close file. device_path:%s', device_path)
+ return None
+
+ return int(content)
+
+
+ def get_num_thermals(self):
+ return self.THERMAL_NUM_ON_MAIN_BROAD
+
+ def get_idx_thermal_start(self):
+ return self.THERMAL_NUM_1_IDX
+
+ def get_size_node_map(self):
+ return len(self._thermal_to_device_node_mapping)
+
+ def get_size_path_map(self):
+ return len(self._thermal_to_device_path_mapping)
+
+ def get_thermal_to_device_path(self, thermal_num):
+ return self._thermal_to_device_path_mapping[thermal_num]
+
+ def get_thermal_1_val(self):
+ return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX)
+
+ def get_thermal_2_val(self):
+ return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX)
+ def get_thermal_temp(self):
+ return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX))
+
+#def main():
+# thermal = ThermalUtil()
+#
+# print 'get_size_node_map : %d' % thermal.get_size_node_map()
+# print 'get_size_path_map : %d' % thermal.get_size_path_map()
+# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
+# print thermal.get_thermal_to_device_path(x)
+#
+#if __name__ == '__main__':
+# main()
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/Makefile
new file mode 100644
index 000000000000..d052ddaf04e6
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/Makefile
@@ -0,0 +1,2 @@
+obj-m:= accton_as6712_32x_psu.o accton-as6712-32x-cpld.o \
+ accton_as6712_32x_fan.o cpr_4011_4mxx.o leds-accton_as6712_32x.o
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c
new file mode 100755
index 000000000000..ff350597a718
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c
@@ -0,0 +1,887 @@
+/*
+ * I2C multiplexer
+ *
+ * Copyright (C) 2014 Accton Technology Corporation.
+ *
+ * This module supports the accton cpld that hold the channel select
+ * mechanism for other i2c slave devices, such as SFP.
+ * This includes the:
+ * Accton as6712_32x CPLD1/CPLD2/CPLD3
+ *
+ * Based on:
+ * pca954x.c from Kumar Gala
+ * Copyright (C) 2006
+ *
+ * Based on:
+ * pca954x.c from Ken Harrenstien
+ * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
+ *
+ * Based on:
+ * i2c-virtual_cb.c from Brian Kuschak
+ * and
+ * pca9540.c from Jean Delvare .
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define I2C_RW_RETRY_COUNT 10
+#define I2C_RW_RETRY_INTERVAL 60 /* ms */
+
+#define NUM_OF_CPLD1_CHANS 0x0
+#define NUM_OF_CPLD2_CHANS 0x10
+#define NUM_OF_CPLD3_CHANS 0x10
+#define CPLD_CHANNEL_SELECT_REG 0x2
+#define CPLD_DESELECT_CHANNEL 0xFF
+
+#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
+
+static LIST_HEAD(cpld_client_list);
+static struct mutex list_lock;
+
+struct cpld_client_node {
+ struct i2c_client *client;
+ struct list_head list;
+};
+
+enum cpld_mux_type {
+ as6712_32x_cpld2,
+ as6712_32x_cpld3,
+ as6712_32x_cpld1
+};
+
+struct as6712_32x_cpld_data {
+ enum cpld_mux_type type;
+ struct i2c_client *client;
+ u8 last_chan; /* last register value */
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+};
+
+struct chip_desc {
+ u8 nchans;
+ u8 deselectChan;
+};
+
+/* Provide specs for the PCA954x types we know about */
+static const struct chip_desc chips[] = {
+ [as6712_32x_cpld1] = {
+ .nchans = NUM_OF_CPLD1_CHANS,
+ .deselectChan = NUM_OF_CPLD1_CHANS,
+ },
+ [as6712_32x_cpld2] = {
+ .nchans = NUM_OF_CPLD2_CHANS,
+ .deselectChan = NUM_OF_CPLD2_CHANS,
+ },
+ [as6712_32x_cpld3] = {
+ .nchans = NUM_OF_CPLD3_CHANS,
+ .deselectChan = NUM_OF_CPLD3_CHANS,
+ }
+};
+
+static const struct i2c_device_id as6712_32x_cpld_mux_id[] = {
+ { "as6712_32x_cpld1", as6712_32x_cpld1 },
+ { "as6712_32x_cpld2", as6712_32x_cpld2 },
+ { "as6712_32x_cpld3", as6712_32x_cpld3 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, as6712_32x_cpld_mux_id);
+
+#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index
+#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index
+#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index
+#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
+#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index
+
+enum as6712_32x_cpld_sysfs_attributes {
+ CPLD_VERSION,
+ ACCESS,
+ MODULE_PRESENT_ALL,
+ MODULE_RXLOS_ALL,
+ /* transceiver attributes */
+ TRANSCEIVER_PRESENT_ATTR_ID(1),
+ TRANSCEIVER_PRESENT_ATTR_ID(2),
+ TRANSCEIVER_PRESENT_ATTR_ID(3),
+ TRANSCEIVER_PRESENT_ATTR_ID(4),
+ TRANSCEIVER_PRESENT_ATTR_ID(5),
+ TRANSCEIVER_PRESENT_ATTR_ID(6),
+ TRANSCEIVER_PRESENT_ATTR_ID(7),
+ TRANSCEIVER_PRESENT_ATTR_ID(8),
+ TRANSCEIVER_PRESENT_ATTR_ID(9),
+ TRANSCEIVER_PRESENT_ATTR_ID(10),
+ TRANSCEIVER_PRESENT_ATTR_ID(11),
+ TRANSCEIVER_PRESENT_ATTR_ID(12),
+ TRANSCEIVER_PRESENT_ATTR_ID(13),
+ TRANSCEIVER_PRESENT_ATTR_ID(14),
+ TRANSCEIVER_PRESENT_ATTR_ID(15),
+ TRANSCEIVER_PRESENT_ATTR_ID(16),
+ TRANSCEIVER_PRESENT_ATTR_ID(17),
+ TRANSCEIVER_PRESENT_ATTR_ID(18),
+ TRANSCEIVER_PRESENT_ATTR_ID(19),
+ TRANSCEIVER_PRESENT_ATTR_ID(20),
+ TRANSCEIVER_PRESENT_ATTR_ID(21),
+ TRANSCEIVER_PRESENT_ATTR_ID(22),
+ TRANSCEIVER_PRESENT_ATTR_ID(23),
+ TRANSCEIVER_PRESENT_ATTR_ID(24),
+ TRANSCEIVER_PRESENT_ATTR_ID(25),
+ TRANSCEIVER_PRESENT_ATTR_ID(26),
+ TRANSCEIVER_PRESENT_ATTR_ID(27),
+ TRANSCEIVER_PRESENT_ATTR_ID(28),
+ TRANSCEIVER_PRESENT_ATTR_ID(29),
+ TRANSCEIVER_PRESENT_ATTR_ID(30),
+ TRANSCEIVER_PRESENT_ATTR_ID(31),
+ TRANSCEIVER_PRESENT_ATTR_ID(32),
+ /*Reset*/
+ TRANSCEIVER_RESET_ATTR_ID(1),
+ TRANSCEIVER_RESET_ATTR_ID(2),
+ TRANSCEIVER_RESET_ATTR_ID(3),
+ TRANSCEIVER_RESET_ATTR_ID(4),
+ TRANSCEIVER_RESET_ATTR_ID(5),
+ TRANSCEIVER_RESET_ATTR_ID(6),
+ TRANSCEIVER_RESET_ATTR_ID(7),
+ TRANSCEIVER_RESET_ATTR_ID(8),
+ TRANSCEIVER_RESET_ATTR_ID(9),
+ TRANSCEIVER_RESET_ATTR_ID(10),
+ TRANSCEIVER_RESET_ATTR_ID(11),
+ TRANSCEIVER_RESET_ATTR_ID(12),
+ TRANSCEIVER_RESET_ATTR_ID(13),
+ TRANSCEIVER_RESET_ATTR_ID(14),
+ TRANSCEIVER_RESET_ATTR_ID(15),
+ TRANSCEIVER_RESET_ATTR_ID(16),
+ TRANSCEIVER_RESET_ATTR_ID(17),
+ TRANSCEIVER_RESET_ATTR_ID(18),
+ TRANSCEIVER_RESET_ATTR_ID(19),
+ TRANSCEIVER_RESET_ATTR_ID(20),
+ TRANSCEIVER_RESET_ATTR_ID(21),
+ TRANSCEIVER_RESET_ATTR_ID(22),
+ TRANSCEIVER_RESET_ATTR_ID(23),
+ TRANSCEIVER_RESET_ATTR_ID(24),
+ TRANSCEIVER_RESET_ATTR_ID(25),
+ TRANSCEIVER_RESET_ATTR_ID(26),
+ TRANSCEIVER_RESET_ATTR_ID(27),
+ TRANSCEIVER_RESET_ATTR_ID(28),
+ TRANSCEIVER_RESET_ATTR_ID(29),
+ TRANSCEIVER_RESET_ATTR_ID(30),
+ TRANSCEIVER_RESET_ATTR_ID(31),
+ TRANSCEIVER_RESET_ATTR_ID(32),
+};
+
+/* sysfs attributes for hwmon
+ */
+static ssize_t show_status(struct device *dev, struct device_attribute *da,
+ char *buf);
+static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
+ char *buf);
+static ssize_t set_status(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count);
+static ssize_t access(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count);
+static ssize_t show_version(struct device *dev, struct device_attribute *da,
+ char *buf);
+static int as6712_32x_cpld_read_internal(struct i2c_client *client, u8 reg);
+static int as6712_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
+
+/* transceiver attributes */
+#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \
+ static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index)
+#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr
+
+#define DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(index) \
+ static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR|S_IRUGO, show_status, set_status, MODULE_RESET_##index)
+#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr
+
+static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
+static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
+/* transceiver attributes */
+static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31);
+DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32);
+
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(1);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(2);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(3);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(4);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(5);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(6);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(7);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(8);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(9);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(10);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(11);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(12);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(13);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(14);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(15);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(16);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(17);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(18);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(19);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(20);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(21);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(22);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(23);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(24);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(25);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(26);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(27);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(28);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(29);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(30);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(31);
+DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(32);
+
+
+static struct attribute *as6712_32x_cpld1_attributes[] = {
+ &sensor_dev_attr_version.dev_attr.attr,
+ &sensor_dev_attr_access.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group as6712_32x_cpld1_group = {
+ .attrs = as6712_32x_cpld1_attributes,
+};
+
+static struct attribute *as6712_32x_cpld2_attributes[] = {
+ &sensor_dev_attr_version.dev_attr.attr,
+ &sensor_dev_attr_access.dev_attr.attr,
+ /* transceiver attributes */
+ &sensor_dev_attr_module_present_all.dev_attr.attr,
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(1),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(2),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(3),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(4),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(5),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(6),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(7),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(8),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(9),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(10),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(11),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(12),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(13),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(14),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(15),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(16),
+ DECLARE_TRANSCEIVER_RESET_ATTR(1),
+ DECLARE_TRANSCEIVER_RESET_ATTR(2),
+ DECLARE_TRANSCEIVER_RESET_ATTR(3),
+ DECLARE_TRANSCEIVER_RESET_ATTR(4),
+ DECLARE_TRANSCEIVER_RESET_ATTR(5),
+ DECLARE_TRANSCEIVER_RESET_ATTR(6),
+ DECLARE_TRANSCEIVER_RESET_ATTR(7),
+ DECLARE_TRANSCEIVER_RESET_ATTR(8),
+ DECLARE_TRANSCEIVER_RESET_ATTR(9),
+ DECLARE_TRANSCEIVER_RESET_ATTR(10),
+ DECLARE_TRANSCEIVER_RESET_ATTR(11),
+ DECLARE_TRANSCEIVER_RESET_ATTR(12),
+ DECLARE_TRANSCEIVER_RESET_ATTR(13),
+ DECLARE_TRANSCEIVER_RESET_ATTR(14),
+ DECLARE_TRANSCEIVER_RESET_ATTR(15),
+ DECLARE_TRANSCEIVER_RESET_ATTR(16),
+ NULL
+};
+
+static const struct attribute_group as6712_32x_cpld2_group = {
+ .attrs = as6712_32x_cpld2_attributes,
+};
+
+static struct attribute *as6712_32x_cpld3_attributes[] = {
+ &sensor_dev_attr_version.dev_attr.attr,
+ &sensor_dev_attr_access.dev_attr.attr,
+ /* transceiver attributes */
+ &sensor_dev_attr_module_present_all.dev_attr.attr,
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(17),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(18),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(19),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(20),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(21),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(22),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(23),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(24),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(25),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(26),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(27),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(28),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(29),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(30),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(31),
+ DECLARE_TRANSCEIVER_PRESENT_ATTR(32),
+ DECLARE_TRANSCEIVER_RESET_ATTR(17),
+ DECLARE_TRANSCEIVER_RESET_ATTR(18),
+ DECLARE_TRANSCEIVER_RESET_ATTR(19),
+ DECLARE_TRANSCEIVER_RESET_ATTR(20),
+ DECLARE_TRANSCEIVER_RESET_ATTR(21),
+ DECLARE_TRANSCEIVER_RESET_ATTR(22),
+ DECLARE_TRANSCEIVER_RESET_ATTR(23),
+ DECLARE_TRANSCEIVER_RESET_ATTR(24),
+ DECLARE_TRANSCEIVER_RESET_ATTR(25),
+ DECLARE_TRANSCEIVER_RESET_ATTR(26),
+ DECLARE_TRANSCEIVER_RESET_ATTR(27),
+ DECLARE_TRANSCEIVER_RESET_ATTR(28),
+ DECLARE_TRANSCEIVER_RESET_ATTR(29),
+ DECLARE_TRANSCEIVER_RESET_ATTR(30),
+ DECLARE_TRANSCEIVER_RESET_ATTR(31),
+ DECLARE_TRANSCEIVER_RESET_ATTR(32),
+ NULL
+};
+
+static const struct attribute_group as6712_32x_cpld3_group = {
+ .attrs = as6712_32x_cpld3_attributes,
+};
+
+static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ int i, status;
+ u8 values[2] = {0};
+ u8 regs[] = {0xA, 0xB};
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+
+ mutex_lock(&data->update_lock);
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ status = as6712_32x_cpld_read_internal(client, regs[i]);
+
+ if (status < 0) {
+ goto exit;
+ }
+
+ values[i] = ~(u8)status;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ /* Return values 1 -> 32 in order */
+ return sprintf(buf, "%.2x %.2x\n", values[0], values[1]);
+
+exit:
+ mutex_unlock(&data->update_lock);
+ return status;
+}
+
+static ssize_t set_status(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+
+ int status = 0;
+ u8 reg = 0, mask = 0;
+ u32 val, para;
+
+ if (sscanf(buf, "%d", ¶) != 1) {
+ return -EINVAL;
+ }
+
+ switch (attr->index) {
+ case MODULE_RESET_1 ... MODULE_RESET_32:
+ reg = 0x4 + (((attr->index - MODULE_PRESENT_1)/8)%2);
+ mask = 0x1 << ((attr->index - MODULE_PRESENT_1)%8);
+ break;
+ default:
+ return 0;
+ }
+
+ mutex_lock(&data->update_lock);
+ status = as6712_32x_cpld_read_internal(client, reg);
+ if (unlikely(status < 0)) {
+ goto exit;
+ }
+
+ val = status & ~mask;
+ if (!para) { /*0 means reset*/
+ val |= mask;
+ }
+ status = as6712_32x_cpld_write_internal(client, reg, val);
+ if (unlikely(status < 0)) {
+ goto exit;
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+
+exit:
+ mutex_unlock(&data->update_lock);
+ return status;
+}
+static ssize_t show_status(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+ int status = 0;
+ u8 reg = 0, mask = 0;
+
+ switch (attr->index) {
+ case MODULE_PRESENT_1 ... MODULE_PRESENT_8:
+ reg = 0xA;
+ mask = 0x1 << (attr->index - MODULE_PRESENT_1);
+ break;
+ case MODULE_PRESENT_9 ... MODULE_PRESENT_16:
+ reg = 0xB;
+ mask = 0x1 << (attr->index - MODULE_PRESENT_9);
+ break;
+ case MODULE_PRESENT_17 ... MODULE_PRESENT_24:
+ reg = 0xA;
+ mask = 0x1 << (attr->index - MODULE_PRESENT_17);
+ break;
+ case MODULE_PRESENT_25 ... MODULE_PRESENT_32:
+ reg = 0xB;
+ mask = 0x1 << (attr->index - MODULE_PRESENT_25);
+ break;
+ case MODULE_RESET_1 ... MODULE_RESET_32:
+ reg = 0x4 + (((attr->index - MODULE_PRESENT_1)/8)%2);
+ mask = 0x1 << ((attr->index - MODULE_PRESENT_1)%8);
+ break;
+ default:
+ return 0;
+ }
+
+ mutex_lock(&data->update_lock);
+ status = as6712_32x_cpld_read_internal(client, reg);
+ if (unlikely(status < 0)) {
+ goto exit;
+ }
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", !(status & mask));
+
+exit:
+ mutex_unlock(&data->update_lock);
+ return status;
+}
+
+static ssize_t access(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ int status;
+ u32 addr, val;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+
+ if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
+ return -EINVAL;
+ }
+
+ if (addr > 0xFF || val > 0xFF) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ status = as6712_32x_cpld_write_internal(client, addr, val);
+ if (unlikely(status < 0)) {
+ goto exit;
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+
+exit:
+ mutex_unlock(&data->update_lock);
+ return status;
+}
+
+/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ for this as they will try to lock adapter a second time */
+static int as6712_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
+ struct i2c_client *client, u8 val)
+{
+ unsigned long orig_jiffies;
+ unsigned short flags;
+ union i2c_smbus_data data;
+ int try;
+ s32 res = -EIO;
+
+ data.byte = val;
+ flags = client->flags;
+ flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+
+ if (adap->algo->smbus_xfer) {
+ /* Retry automatically on arbitration loss */
+ orig_jiffies = jiffies;
+ for (res = 0, try = 0; try <= adap->retries; try++) {
+ res = adap->algo->smbus_xfer(adap, client->addr, flags,
+ I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (res != -EAGAIN)
+ break;
+ if (time_after(jiffies,
+ orig_jiffies + adap->timeout))
+ break;
+ }
+ }
+
+ return res;
+}
+
+static int as6712_32x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
+ u32 chan)
+{
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
+ u8 regval;
+ int ret = 0;
+ regval = chan;
+
+ /* Only select the channel if its different from the last channel */
+ if (data->last_chan != regval) {
+ ret = as6712_32x_cpld_mux_reg_write(muxc->parent, client, regval);
+ data->last_chan = regval;
+ }
+
+ return ret;
+}
+
+static int as6712_32x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
+ u32 chan)
+{
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
+
+ /* Deselect active channel */
+ data->last_chan = chips[data->type].deselectChan;
+
+ return as6712_32x_cpld_mux_reg_write(muxc->parent, client, data->last_chan);
+}
+
+static void as6712_32x_cpld_add_client(struct i2c_client *client)
+{
+ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
+
+ if (!node) {
+ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
+ return;
+ }
+
+ node->client = client;
+
+ mutex_lock(&list_lock);
+ list_add(&node->list, &cpld_client_list);
+ mutex_unlock(&list_lock);
+}
+
+static void as6712_32x_cpld_remove_client(struct i2c_client *client)
+{
+ struct list_head *list_node = NULL;
+ struct cpld_client_node *cpld_node = NULL;
+ int found = 0;
+
+ mutex_lock(&list_lock);
+
+ list_for_each(list_node, &cpld_client_list)
+ {
+ cpld_node = list_entry(list_node, struct cpld_client_node, list);
+
+ if (cpld_node->client == client) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(list_node);
+ kfree(cpld_node);
+ }
+
+ mutex_unlock(&list_lock);
+}
+
+static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int val = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ val = i2c_smbus_read_byte_data(client, 0x1);
+
+ if (val < 0) {
+ dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
+ }
+
+ return sprintf(buf, "%d", val);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int as6712_32x_cpld_mux_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ int force, class;
+ struct i2c_mux_core *muxc;
+ struct as6712_32x_cpld_data *data;
+ int chan = 0;
+ int ret = -ENODEV;
+ const struct attribute_group *group = NULL;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
+ return -ENODEV;
+
+ muxc = i2c_mux_alloc(adap, &client->dev,
+ chips[id->driver_data].nchans,
+ sizeof(*data), 0,
+ as6712_32x_cpld_mux_select_chan,
+ as6712_32x_cpld_mux_deselect_mux);
+ if (!muxc)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, muxc);
+ data = i2c_mux_priv(muxc);
+ data->client = client;
+ mutex_init(&data->update_lock);
+
+ if (data->type == as6712_32x_cpld2 || data->type == as6712_32x_cpld3) {
+ data->type = id->driver_data;
+ data->last_chan = chips[data->type].deselectChan; /* force the first selection */
+
+ /* Now create an adapter for each channel */
+ for (chan = 0; chan < chips[data->type].nchans; chan++) {
+ force = 0; /* dynamic adap number */
+ class = 0; /* no class by default */
+
+ ret = i2c_mux_add_adapter(muxc, force, chan, class);
+
+ if (ret) {
+ ret = -ENODEV;
+ dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
+ goto exit_mux_register;
+ }
+ }
+
+ dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
+ chan, client->name);
+ }
+
+ /* Register sysfs hooks */
+ switch (data->type) {
+ case as6712_32x_cpld1:
+ group = &as6712_32x_cpld1_group;
+ break;
+ case as6712_32x_cpld2:
+ group = &as6712_32x_cpld2_group;
+ break;
+ case as6712_32x_cpld3:
+ group = &as6712_32x_cpld3_group;
+ break;
+ default:
+ break;
+ }
+
+ if (group) {
+ ret = sysfs_create_group(&client->dev.kobj, group);
+ if (ret) {
+ goto exit_mux_register;
+ }
+ }
+
+ if (chips[data->type].nchans) {
+ dev_info(&client->dev,
+ "registered %d multiplexed busses for I2C %s\n",
+ chan, client->name);
+ }
+ else {
+ dev_info(&client->dev,
+ "device %s registered\n", client->name);
+ }
+
+ as6712_32x_cpld_add_client(client);
+
+ return 0;
+
+exit_mux_register:
+ i2c_mux_del_adapters(muxc);
+ kfree(data);
+ return ret;
+}
+
+static int as6712_32x_cpld_mux_remove(struct i2c_client *client)
+{
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
+ const struct attribute_group *group = NULL;
+
+ as6712_32x_cpld_remove_client(client);
+
+ /* Remove sysfs hooks */
+ switch (data->type) {
+ case as6712_32x_cpld1:
+ group = &as6712_32x_cpld1_group;
+ break;
+ case as6712_32x_cpld2:
+ group = &as6712_32x_cpld2_group;
+ break;
+ case as6712_32x_cpld3:
+ group = &as6712_32x_cpld3_group;
+ break;
+ default:
+ break;
+ }
+
+ if (group) {
+ sysfs_remove_group(&client->dev.kobj, group);
+ }
+
+ i2c_mux_del_adapters(muxc);
+
+ return 0;
+}
+
+static int as6712_32x_cpld_read_internal(struct i2c_client *client, u8 reg)
+{
+ int status = 0, retry = I2C_RW_RETRY_COUNT;
+
+ while (retry) {
+ status = i2c_smbus_read_byte_data(client, reg);
+ if (unlikely(status < 0)) {
+ msleep(I2C_RW_RETRY_INTERVAL);
+ retry--;
+ continue;
+ }
+
+ break;
+ }
+
+ return status;
+}
+
+static int as6712_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
+{
+ int status = 0, retry = I2C_RW_RETRY_COUNT;
+
+ while (retry) {
+ status = i2c_smbus_write_byte_data(client, reg, value);
+ if (unlikely(status < 0)) {
+ msleep(I2C_RW_RETRY_INTERVAL);
+ retry--;
+ continue;
+ }
+
+ break;
+ }
+
+ return status;
+}
+
+int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg)
+{
+ struct list_head *list_node = NULL;
+ struct cpld_client_node *cpld_node = NULL;
+ int ret = -EPERM;
+
+ mutex_lock(&list_lock);
+
+ list_for_each(list_node, &cpld_client_list)
+ {
+ cpld_node = list_entry(list_node, struct cpld_client_node, list);
+
+ if (cpld_node->client->addr == cpld_addr) {
+ ret = as6712_32x_cpld_read_internal(cpld_node->client, reg);
+ break;
+ }
+ }
+
+ mutex_unlock(&list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(as6712_32x_cpld_read);
+
+int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
+{
+ struct list_head *list_node = NULL;
+ struct cpld_client_node *cpld_node = NULL;
+ int ret = -EIO;
+
+ mutex_lock(&list_lock);
+
+ list_for_each(list_node, &cpld_client_list)
+ {
+ cpld_node = list_entry(list_node, struct cpld_client_node, list);
+
+ if (cpld_node->client->addr == cpld_addr) {
+ ret = as6712_32x_cpld_write_internal(cpld_node->client, reg, value);
+ break;
+ }
+ }
+
+ mutex_unlock(&list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(as6712_32x_cpld_write);
+
+static struct i2c_driver as6712_32x_cpld_mux_driver = {
+ .driver = {
+ .name = "as6712_32x_cpld",
+ .owner = THIS_MODULE,
+ },
+ .probe = as6712_32x_cpld_mux_probe,
+ .remove = as6712_32x_cpld_mux_remove,
+ .id_table = as6712_32x_cpld_mux_id,
+};
+
+static int __init as6712_32x_cpld_mux_init(void)
+{
+ mutex_init(&list_lock);
+ return i2c_add_driver(&as6712_32x_cpld_mux_driver);
+}
+
+static void __exit as6712_32x_cpld_mux_exit(void)
+{
+ i2c_del_driver(&as6712_32x_cpld_mux_driver);
+}
+
+MODULE_AUTHOR("Brandon Chuang ");
+MODULE_DESCRIPTION("Accton as6712-32x CPLD driver");
+MODULE_LICENSE("GPL");
+
+module_init(as6712_32x_cpld_mux_init);
+module_exit(as6712_32x_cpld_mux_exit);
+
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_fan.c b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_fan.c
new file mode 100644
index 000000000000..7033d8b75687
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_fan.c
@@ -0,0 +1,463 @@
+/*
+ * A hwmon driver for the Accton as6712 32x fan contrl
+ *
+ * Copyright (C) 2014 Accton Technology Corporation.
+ * Brandon Chuang
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DRVNAME "as6712_32x_fan"
+
+#define FAN_MAX_NUMBER 5
+#define FAN_SPEED_CPLD_TO_RPM_STEP 150
+#define FAN_SPEED_PRECENT_TO_CPLD_STEP 5
+#define FAN_DUTY_CYCLE_MIN 0 /* 10% ??*/
+#define FAN_DUTY_CYCLE_MAX 100 /* 100% */
+
+#define CPLD_REG_FAN_STATUS_OFFSET 0xC
+#define CPLD_REG_FANR_STATUS_OFFSET 0x17
+#define CPLD_REG_FAN_DIRECTION_OFFSET 0x1E
+
+#define CPLD_FAN1_REG_SPEED_OFFSET 0x10
+#define CPLD_FAN2_REG_SPEED_OFFSET 0x11
+#define CPLD_FAN3_REG_SPEED_OFFSET 0x12
+#define CPLD_FAN4_REG_SPEED_OFFSET 0x13
+#define CPLD_FAN5_REG_SPEED_OFFSET 0x14
+
+#define CPLD_FANR1_REG_SPEED_OFFSET 0x18
+#define CPLD_FANR2_REG_SPEED_OFFSET 0x19
+#define CPLD_FANR3_REG_SPEED_OFFSET 0x1A
+#define CPLD_FANR4_REG_SPEED_OFFSET 0x1B
+#define CPLD_FANR5_REG_SPEED_OFFSET 0x1C
+
+#define CPLD_REG_FAN_PWM_CYCLE_OFFSET 0xD
+
+#define CPLD_FAN1_INFO_BIT_MASK 0x1
+#define CPLD_FAN2_INFO_BIT_MASK 0x2
+#define CPLD_FAN3_INFO_BIT_MASK 0x4
+#define CPLD_FAN4_INFO_BIT_MASK 0x8
+#define CPLD_FAN5_INFO_BIT_MASK 0x10
+
+#define PROJECT_NAME
+
+#define DEBUG_MODE 0
+
+#if (DEBUG_MODE == 1)
+ #define DEBUG_PRINT(format, ...) printk(format, __VA_ARGS__)
+#else
+ #define DEBUG_PRINT(format, ...)
+#endif
+
+static struct accton_as6712_32x_fan *fan_data = NULL;
+
+struct accton_as6712_32x_fan {
+ struct platform_device *pdev;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* != 0 if registers are valid */
+ unsigned long last_updated; /* In jiffies */
+ u8 status[FAN_MAX_NUMBER]; /* inner first fan status */
+ u32 speed[FAN_MAX_NUMBER]; /* inner first fan speed */
+ u8 direction[FAN_MAX_NUMBER]; /* reconrd the direction of inner first and second fans */
+ u32 duty_cycle[FAN_MAX_NUMBER]; /* control the speed of inner first and second fans */
+ u8 r_status[FAN_MAX_NUMBER]; /* inner second fan status */
+ u32 r_speed[FAN_MAX_NUMBER]; /* inner second fan speed */
+};
+
+/*******************/
+#define MAKE_FAN_MASK_OR_REG(name,type) \
+ CPLD_FAN##type##1_##name, \
+ CPLD_FAN##type##2_##name, \
+ CPLD_FAN##type##3_##name, \
+ CPLD_FAN##type##4_##name, \
+ CPLD_FAN##type##5_##name,
+
+/* fan related data
+ */
+static const u8 fan_info_mask[] = {
+ MAKE_FAN_MASK_OR_REG(INFO_BIT_MASK,)
+};
+
+static const u8 fan_speed_reg[] = {
+ MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,)
+};
+
+static const u8 fanr_speed_reg[] = {
+ MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,R)
+};
+
+/*******************/
+#define DEF_FAN_SET(id) \
+ FAN##id##_FAULT, \
+ FAN##id##_SPEED, \
+ FAN##id##_DUTY_CYCLE, \
+ FAN##id##_DIRECTION, \
+ FANR##id##_FAULT, \
+ FANR##id##_SPEED,
+
+enum sysfs_fan_attributes {
+ DEF_FAN_SET(1)
+ DEF_FAN_SET(2)
+ DEF_FAN_SET(3)
+ DEF_FAN_SET(4)
+ DEF_FAN_SET(5)
+};
+/*******************/
+static void accton_as6712_32x_fan_update_device(struct device *dev);
+static int accton_as6712_32x_fan_read_value(u8 reg);
+static int accton_as6712_32x_fan_write_value(u8 reg, u8 value);
+
+static ssize_t fan_set_duty_cycle(struct device *dev,
+ struct device_attribute *da,const char *buf, size_t count);
+static ssize_t fan_show_value(struct device *dev,
+ struct device_attribute *da, char *buf);
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *da, char *buf);
+
+extern int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg);
+extern int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
+
+
+/*******************/
+#define _MAKE_SENSOR_DEVICE_ATTR(prj, id, id2) \
+ static SENSOR_DEVICE_ATTR(prj##fan##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, \
+ fan_set_duty_cycle, FAN##id##_DUTY_CYCLE); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id##_direction, S_IRUGO, fan_show_value, NULL, FAN##id##_DIRECTION); \
+ static SENSOR_DEVICE_ATTR(prj##fanr##id##_fault, S_IRUGO, fan_show_value, NULL, FANR##id##_FAULT); \
+ static SENSOR_DEVICE_ATTR(prj##fanr##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id##_input, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id2##_input, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT); \
+ static SENSOR_DEVICE_ATTR(prj##fan##id2##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT);
+
+#define MAKE_SENSOR_DEVICE_ATTR(prj,id, id2) _MAKE_SENSOR_DEVICE_ATTR(prj,id, id2)
+
+MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,1 ,11)
+MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,2 ,12)
+MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,3 ,13)
+MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,4 ,14)
+MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,5 ,15)
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+/*******************/
+
+#define _MAKE_FAN_ATTR(prj, id, id2) \
+ &sensor_dev_attr_##prj##fan##id##_speed_rpm.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fan##id##_duty_cycle_percentage.dev_attr.attr,\
+ &sensor_dev_attr_##prj##fan##id##_direction.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fanr##id##_fault.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fanr##id##_speed_rpm.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fan##id##_input.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fan##id2##_input.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fan##id##_fault.dev_attr.attr, \
+ &sensor_dev_attr_##prj##fan##id2##_fault.dev_attr.attr,
+
+
+#define MAKE_FAN_ATTR(prj, id, id2) _MAKE_FAN_ATTR(prj, id, id2)
+
+static struct attribute *accton_as6712_32x_fan_attributes[] = {
+ /* fan related attributes */
+ MAKE_FAN_ATTR(PROJECT_NAME,1 ,11)
+ MAKE_FAN_ATTR(PROJECT_NAME,2 ,12)
+ MAKE_FAN_ATTR(PROJECT_NAME,3 ,13)
+ MAKE_FAN_ATTR(PROJECT_NAME,4 ,14)
+ MAKE_FAN_ATTR(PROJECT_NAME,5 ,15)
+ &sensor_dev_attr_name.dev_attr.attr,
+ NULL
+};
+/*******************/
+
+/* fan related functions
+ */
+static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ ssize_t ret = 0;
+ int data_index, type_index;
+
+ accton_as6712_32x_fan_update_device(dev);
+
+ if (fan_data->valid == 0) {
+ return ret;
+ }
+
+ type_index = attr->index%FAN2_FAULT;
+ data_index = attr->index/FAN2_FAULT;
+
+ switch (type_index) {
+ case FAN1_FAULT:
+ ret = sprintf(buf, "%d\n", fan_data->status[data_index]);
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ case FAN1_SPEED:
+ ret = sprintf(buf, "%d\n", fan_data->speed[data_index]);
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ case FAN1_DUTY_CYCLE:
+ ret = sprintf(buf, "%d\n", fan_data->duty_cycle[data_index]);
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ case FAN1_DIRECTION:
+ ret = sprintf(buf, "%d\n", fan_data->direction[data_index]); /* presnet, need to modify*/
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ case FANR1_FAULT:
+ ret = sprintf(buf, "%d\n", fan_data->r_status[data_index]);
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ case FANR1_SPEED:
+ ret = sprintf(buf, "%d\n", fan_data->r_speed[data_index]);
+ DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
+ break;
+ default:
+ DEBUG_PRINT("[Check !!][%s][%d] \n", __FUNCTION__, __LINE__);
+ break;
+ }
+
+ return ret;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+/*******************/
+static ssize_t fan_set_duty_cycle(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+
+ int error, value;
+
+ error = kstrtoint(buf, 10, &value);
+ if (error)
+ return error;
+
+ if (value < FAN_DUTY_CYCLE_MIN || value > FAN_DUTY_CYCLE_MAX)
+ return -EINVAL;
+
+ accton_as6712_32x_fan_write_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET, value/FAN_SPEED_PRECENT_TO_CPLD_STEP);
+
+ fan_data->valid = 0;
+
+ return count;
+}
+
+static const struct attribute_group accton_as6712_32x_fan_group = {
+ .attrs = accton_as6712_32x_fan_attributes,
+};
+
+static int accton_as6712_32x_fan_read_value(u8 reg)
+{
+ return as6712_32x_cpld_read(0x60, reg);
+}
+
+static int accton_as6712_32x_fan_write_value(u8 reg, u8 value)
+{
+ return as6712_32x_cpld_write(0x60, reg, value);
+}
+
+static void accton_as6712_32x_fan_update_device(struct device *dev)
+{
+ int speed, r_speed, fault, r_fault, direction, ctrl_speed;
+ int i;
+ int retry_count;
+
+ mutex_lock(&fan_data->update_lock);
+
+ DEBUG_PRINT("Starting accton_as6712_32x_fan update \n");
+
+ if (!(time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) || !fan_data->valid)) {
+ /* do nothing */
+ goto _exit;
+ }
+
+ fan_data->valid = 0;
+
+ DEBUG_PRINT("Starting accton_as6712_32x_fan update 2 \n");
+
+ fault = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_STATUS_OFFSET);
+ r_fault = accton_as6712_32x_fan_read_value(CPLD_REG_FANR_STATUS_OFFSET);
+ direction = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_DIRECTION_OFFSET);
+ ctrl_speed = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET);
+
+ if ( (fault < 0) || (r_fault < 0) || (ctrl_speed < 0) )
+ {
+ DEBUG_PRINT("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
+ goto _exit; /* error */
+ }
+
+ DEBUG_PRINT("[fan:] fault:%d, r_fault=%d, ctrl_speed=%d \n",fault, r_fault, ctrl_speed);
+
+ for (i = 0; i < FAN_MAX_NUMBER; i++)
+ {
+ /* Update fan data
+ */
+
+ /* fan fault
+ * 0: normal, 1:abnormal
+ * Each FAN-tray module has two fans.
+ */
+ fan_data->status[i] = (fault & fan_info_mask[i]) >> i;
+ DEBUG_PRINT("[fan%d:] fail=%d \n",i, fan_data->status[i]);
+
+ fan_data->r_status[i] = (r_fault & fan_info_mask[i]) >> i;
+ fan_data->direction[i] = (direction & fan_info_mask[i]) >> i;
+ fan_data->duty_cycle[i] = ctrl_speed * FAN_SPEED_PRECENT_TO_CPLD_STEP;
+
+ /* fan speed
+ */
+ speed = 0;
+ r_speed = 0;
+ retry_count = 3;
+ while (retry_count) {
+ retry_count--;
+ speed = accton_as6712_32x_fan_read_value(fan_speed_reg[i]);
+ r_speed = accton_as6712_32x_fan_read_value(fanr_speed_reg[i]);
+ if ( (speed < 0) || (r_speed < 0) )
+ {
+ DEBUG_PRINT("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
+ goto _exit; /* error */
+ }
+ if ( (speed == 0) || (r_speed == 0) )
+ {
+ msleep(50);
+ continue;
+ }
+ break;
+ }
+
+ DEBUG_PRINT("[fan%d:] speed:%d, r_speed=%d \n", i, speed, r_speed);
+
+ fan_data->speed[i] = speed * FAN_SPEED_CPLD_TO_RPM_STEP;
+ fan_data->r_speed[i] = r_speed * FAN_SPEED_CPLD_TO_RPM_STEP;
+ }
+
+ /* finish to update */
+ fan_data->last_updated = jiffies;
+ fan_data->valid = 1;
+
+_exit:
+ mutex_unlock(&fan_data->update_lock);
+}
+
+static int accton_as6712_32x_fan_probe(struct platform_device *pdev)
+{
+ int status = -1;
+
+ /* Register sysfs hooks */
+ status = sysfs_create_group(&pdev->dev.kobj, &accton_as6712_32x_fan_group);
+ if (status) {
+ goto exit;
+
+ }
+
+ fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(fan_data->hwmon_dev)) {
+ status = PTR_ERR(fan_data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&pdev->dev, "accton_as6712_32x_fan\n");
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&pdev->dev.kobj, &accton_as6712_32x_fan_group);
+exit:
+ return status;
+}
+
+static int accton_as6712_32x_fan_remove(struct platform_device *pdev)
+{
+ hwmon_device_unregister(fan_data->hwmon_dev);
+ sysfs_remove_group(&fan_data->pdev->dev.kobj, &accton_as6712_32x_fan_group);
+
+ return 0;
+}
+
+
+
+static struct platform_driver accton_as6712_32x_fan_driver = {
+ .probe = accton_as6712_32x_fan_probe,
+ .remove = accton_as6712_32x_fan_remove,
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init accton_as6712_32x_fan_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&accton_as6712_32x_fan_driver);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ fan_data = kzalloc(sizeof(struct accton_as6712_32x_fan), GFP_KERNEL);
+ if (!fan_data) {
+ ret = -ENOMEM;
+ platform_driver_unregister(&accton_as6712_32x_fan_driver);
+ goto exit;
+ }
+
+ mutex_init(&fan_data->update_lock);
+ fan_data->valid = 0;
+
+ fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
+ if (IS_ERR(fan_data->pdev)) {
+ ret = PTR_ERR(fan_data->pdev);
+ platform_driver_unregister(&accton_as6712_32x_fan_driver);
+ kfree(fan_data);
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static void __exit accton_as6712_32x_fan_exit(void)
+{
+ platform_device_unregister(fan_data->pdev);
+ platform_driver_unregister(&accton_as6712_32x_fan_driver);
+ kfree(fan_data);
+}
+
+MODULE_AUTHOR("Brandon Chuang ");
+MODULE_DESCRIPTION("accton_as6712_32x_fan driver");
+MODULE_LICENSE("GPL");
+
+module_init(accton_as6712_32x_fan_init);
+module_exit(accton_as6712_32x_fan_exit);
+
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_psu.c
new file mode 100644
index 000000000000..5b9eda261489
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_psu.c
@@ -0,0 +1,364 @@
+/*
+ * An hwmon driver for accton as6712_32x Power Module
+ *
+ * Copyright (C) 2014 Accton Technology Corporation.
+ *
+ * Based on ad7414.c
+ * Copyright 2006 Stefan Roese , DENX Software Engineering
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define PSU_STATUS_I2C_ADDR 0x60
+#define PSU_STATUS_I2C_REG_OFFSET 0x2
+
+#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1)))
+#define IS_PRESENT(id, value) (!(value & BIT(id*4)))
+
+static ssize_t show_index(struct device *dev, struct device_attribute *da, char *buf);
+static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
+static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf);
+static int as6712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
+extern int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg);
+static int as6712_32x_psu_model_name_get(struct device *dev);
+
+/* Addresses scanned
+ */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Each client has this additional data
+ */
+struct as6712_32x_psu_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if registers are valid */
+ unsigned long last_updated; /* In jiffies */
+ u8 index; /* PSU index */
+ u8 status; /* Status(present/power_good) register read from CPLD */
+ char model_name[14]; /* Model name, read from eeprom */
+};
+
+static struct as6712_32x_psu_data *as6712_32x_psu_update_device(struct device *dev);
+
+enum as6712_32x_psu_sysfs_attributes {
+ PSU_INDEX,
+ PSU_PRESENT,
+ PSU_MODEL_NAME,
+ PSU_POWER_GOOD
+};
+
+/* sysfs attributes for hwmon
+ */
+static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_INDEX);
+static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
+static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME);
+static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
+
+static struct attribute *as6712_32x_psu_attributes[] = {
+ &sensor_dev_attr_psu_index.dev_attr.attr,
+ &sensor_dev_attr_psu_present.dev_attr.attr,
+ &sensor_dev_attr_psu_model_name.dev_attr.attr,
+ &sensor_dev_attr_psu_power_good.dev_attr.attr,
+ NULL
+};
+
+static ssize_t show_index(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", data->index);
+}
+
+static ssize_t show_status(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct as6712_32x_psu_data *data = as6712_32x_psu_update_device(dev);
+ u8 status = 0;
+
+ if (!data->valid) {
+ return sprintf(buf, "0\n");
+ }
+
+ if (attr->index == PSU_PRESENT) {
+ status = IS_PRESENT(data->index, data->status);
+ }
+ else { /* PSU_POWER_GOOD */
+ status = IS_POWER_GOOD(data->index, data->status);
+ }
+
+ return sprintf(buf, "%d\n", status);
+}
+
+static ssize_t show_model_name(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct as6712_32x_psu_data *data = as6712_32x_psu_update_device(dev);
+
+ if (!data->valid) {
+ return 0;
+ }
+
+ if (!IS_PRESENT(data->index, data->status)) {
+ return 0;
+ }
+
+ if (as6712_32x_psu_model_name_get(dev) < 0) {
+ return -ENXIO;
+ }
+ return sprintf(buf, "%s\n", data->model_name);
+}
+
+static const struct attribute_group as6712_32x_psu_group = {
+ .attrs = as6712_32x_psu_attributes,
+};
+
+static int as6712_32x_psu_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ struct as6712_32x_psu_data *data;
+ int status;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ status = -EIO;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct as6712_32x_psu_data), GFP_KERNEL);
+ if (!data) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->valid = 0;
+ data->index = dev_id->driver_data;
+ mutex_init(&data->update_lock);
+
+ dev_info(&client->dev, "chip found\n");
+
+ /* Register sysfs hooks */
+ status = sysfs_create_group(&client->dev.kobj, &as6712_32x_psu_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: psu '%s'\n",
+ dev_name(data->hwmon_dev), client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &as6712_32x_psu_group);
+exit_free:
+ kfree(data);
+exit:
+
+ return status;
+}
+
+static int as6712_32x_psu_remove(struct i2c_client *client)
+{
+ struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &as6712_32x_psu_group);
+ kfree(data);
+
+ return 0;
+}
+
+enum psu_index
+{
+ as6712_32x_psu1,
+ as6712_32x_psu2
+};
+
+static const struct i2c_device_id as6712_32x_psu_id[] = {
+ { "as6712_32x_psu1", as6712_32x_psu1 },
+ { "as6712_32x_psu2", as6712_32x_psu2 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, as6712_32x_psu_id);
+
+static struct i2c_driver as6712_32x_psu_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "as6712_32x_psu",
+ },
+ .probe = as6712_32x_psu_probe,
+ .remove = as6712_32x_psu_remove,
+ .id_table = as6712_32x_psu_id,
+ .address_list = normal_i2c,
+};
+
+static int as6712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
+ int data_len)
+{
+ int result = 0;
+ int retry_count = 5;
+
+ while (retry_count) {
+ retry_count--;
+
+ result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
+
+ if (unlikely(result < 0)) {
+ msleep(10);
+ continue;
+ }
+
+ if (unlikely(result != data_len)) {
+ result = -EIO;
+ msleep(10);
+ continue;
+ }
+
+ result = 0;
+ break;
+ }
+
+ return result;
+}
+
+enum psu_type {
+ PSU_YM_2401_JCR, /* AC110V - F2B */
+ PSU_YM_2401_JDR, /* AC110V - B2F */
+ PSU_CPR_4011_4M11, /* AC110V - F2B */
+ PSU_CPR_4011_4M21, /* AC110V - B2F */
+ PSU_CPR_6011_2M11, /* AC110V - F2B */
+ PSU_CPR_6011_2M21, /* AC110V - B2F */
+ PSU_UM400D_01G, /* DC48V - F2B */
+ PSU_UM400D01_01G /* DC48V - B2F */
+};
+
+struct model_name_info {
+ enum psu_type type;
+ u8 offset;
+ u8 length;
+ char* model_name;
+};
+
+struct model_name_info models[] = {
+{PSU_YM_2401_JCR, 0x20, 11, "YM-2401JCR"},
+{PSU_YM_2401_JDR, 0x20, 11, "YM-2401JDR"},
+{PSU_CPR_4011_4M11, 0x26, 13, "CPR-4011-4M11"},
+{PSU_CPR_4011_4M21, 0x26, 13, "CPR-4011-4M21"},
+{PSU_CPR_6011_2M11, 0x26, 13, "CPR-6011-2M11"},
+{PSU_CPR_6011_2M21, 0x26, 13, "CPR-6011-2M21"},
+{PSU_UM400D_01G, 0x50, 9, "um400d01G"},
+{PSU_UM400D01_01G, 0x50, 12, "um400d01-01G"},
+};
+
+static int as6712_32x_psu_model_name_get(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
+ int i, status;
+
+ for (i = 0; i < ARRAY_SIZE(models); i++) {
+ memset(data->model_name, 0, sizeof(data->model_name));
+
+ status = as6712_32x_psu_read_block(client, models[i].offset,
+ data->model_name, models[i].length);
+ if (status < 0) {
+ data->model_name[0] = '\0';
+ dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n",
+ client->addr, models[i].offset);
+ return status;
+ }
+ else {
+ data->model_name[models[i].length] = '\0';
+ }
+
+ if (i == PSU_YM_2401_JCR || i == PSU_YM_2401_JDR) {
+ /* Skip the meaningless data byte 8*/
+ data->model_name[8] = data->model_name[9];
+ data->model_name[9] = data->model_name[10];
+ data->model_name[10] = '\0';
+ }
+
+ /* Determine if the model name is known, if not, read next index
+ */
+ if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) {
+ return 0;
+ }
+ else {
+ data->model_name[0] = '\0';
+ }
+ }
+
+ return -ENODATA;
+}
+static struct as6712_32x_psu_data *as6712_32x_psu_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ int status = -1;
+
+ dev_dbg(&client->dev, "Starting as6812_32x update\n");
+ data->valid = 0;
+
+ /* Read psu status */
+ status = as6712_32x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET);
+
+ if (status < 0) {
+ dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status);
+ goto exit;
+ }
+ else {
+ data->status = status;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+module_i2c_driver(as6712_32x_psu_driver);
+
+MODULE_AUTHOR("Brandon Chuang ");
+MODULE_DESCRIPTION("as6712_32x_psu driver");
+MODULE_LICENSE("GPL");
+
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/cpr_4011_4mxx.c b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/cpr_4011_4mxx.c
new file mode 100644
index 000000000000..15cef4ef50d7
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/cpr_4011_4mxx.c
@@ -0,0 +1,439 @@
+/*
+ * An hwmon driver for the CPR-4011-4Mxx Redundant Power Module
+ *
+ * Copyright (C) Brandon Chuang
+ *
+ * Based on ad7414.c
+ * Copyright 2006 Stefan Roese , DENX Software Engineering
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#if 0
+#define DEBUG
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAX_FAN_DUTY_CYCLE 100
+
+/* Addresses scanned
+ */
+static const unsigned short normal_i2c[] = { 0x3c, 0x3d, 0x3e, 0x3f, I2C_CLIENT_END };
+
+/* Each client has this additional data
+ */
+struct cpr_4011_4mxx_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if registers are valid */
+ unsigned long last_updated; /* In jiffies */
+ u8 vout_mode; /* Register value */
+ u16 v_in; /* Register value */
+ u16 v_out; /* Register value */
+ u16 i_in; /* Register value */
+ u16 i_out; /* Register value */
+ u16 p_in; /* Register value */
+ u16 p_out; /* Register value */
+ u16 temp_input[2]; /* Register value */
+ u8 fan_fault; /* Register value */
+ u16 fan_duty_cycle[2]; /* Register value */
+ u16 fan_speed[2]; /* Register value */
+};
+
+static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf);
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf);
+static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf);
+static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
+static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value);
+static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev);
+
+enum cpr_4011_4mxx_sysfs_attributes {
+ PSU_V_IN,
+ PSU_V_OUT,
+ PSU_I_IN,
+ PSU_I_OUT,
+ PSU_P_IN,
+ PSU_P_OUT,
+ PSU_P_IN_UV,
+ PSU_P_OUT_UV,
+ PSU_TEMP1_INPUT,
+ PSU_FAN1_FAULT,
+ PSU_FAN1_DUTY_CYCLE,
+ PSU_FAN1_SPEED,
+};
+
+/* sysfs attributes for hwmon
+ */
+static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN);
+static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
+static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN);
+static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
+static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN);
+static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
+static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
+static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
+static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
+static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
+
+/*Duplicate nodes for lm-sensors. 1 for input, 2 for output.*/
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_linear, NULL, PSU_V_IN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_vout, NULL, PSU_V_OUT);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_linear, NULL, PSU_I_IN);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_linear, NULL, PSU_P_IN_UV);
+static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
+
+
+
+
+
+static struct attribute *cpr_4011_4mxx_attributes[] = {
+ &sensor_dev_attr_psu_v_in.dev_attr.attr,
+ &sensor_dev_attr_psu_v_out.dev_attr.attr,
+ &sensor_dev_attr_psu_i_in.dev_attr.attr,
+ &sensor_dev_attr_psu_i_out.dev_attr.attr,
+ &sensor_dev_attr_psu_p_in.dev_attr.attr,
+ &sensor_dev_attr_psu_p_out.dev_attr.attr,
+ &sensor_dev_attr_psu_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
+ &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
+ &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
+ /*Duplicate nodes for lm-sensors.*/
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr2_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_power2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_fault.dev_attr.attr,
+ NULL
+};
+
+static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
+{
+ u16 valid_data = data & mask;
+ bool is_negative = valid_data >> (valid_bit - 1);
+
+ return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data;
+}
+
+static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
+ int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1;
+ long speed;
+ int error;
+
+ error = kstrtol(buf, 10, &speed);
+ if (error)
+ return error;
+
+ if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->fan_duty_cycle[nr] = speed;
+ cpr_4011_4mxx_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_linear(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
+
+ u16 value = 0;
+ int exponent, mantissa;
+ int multiplier = 1000;
+
+ switch (attr->index) {
+ case PSU_V_IN:
+ value = data->v_in;
+ break;
+ case PSU_I_IN:
+ value = data->i_in;
+ break;
+ case PSU_I_OUT:
+ value = data->i_out;
+ break;
+ case PSU_P_IN_UV:
+ multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
+ /*Passing through*/
+ case PSU_P_IN:
+ value = data->p_in;
+ break;
+ case PSU_P_OUT_UV:
+ multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
+ /*Passing through*/
+ case PSU_P_OUT:
+ value = data->p_out;
+ break;
+ case PSU_TEMP1_INPUT:
+ value = data->temp_input[0];
+ break;
+ case PSU_FAN1_DUTY_CYCLE:
+ multiplier = 1;
+ value = data->fan_duty_cycle[0];
+ break;
+ case PSU_FAN1_SPEED:
+ multiplier = 1;
+ value = data->fan_speed[0];
+ break;
+ default:
+ break;
+ }
+
+ exponent = two_complement_to_int(value >> 11, 5, 0x1f);
+ mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
+
+ return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
+ sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
+
+ u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
+
+ return sprintf(buf, "%d\n", data->fan_fault >> shift);
+}
+
+static ssize_t show_vout(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
+ int exponent, mantissa;
+ int multiplier = 1000;
+
+ exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
+ mantissa = data->v_out;
+
+ return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
+ sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
+}
+
+static const struct attribute_group cpr_4011_4mxx_group = {
+ .attrs = cpr_4011_4mxx_attributes,
+};
+
+static int cpr_4011_4mxx_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ struct cpr_4011_4mxx_data *data;
+ int status;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) {
+ status = -EIO;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct cpr_4011_4mxx_data), GFP_KERNEL);
+ if (!data) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->valid = 0;
+ mutex_init(&data->update_lock);
+
+ dev_info(&client->dev, "chip found\n");
+
+ /* Register sysfs hooks */
+ status = sysfs_create_group(&client->dev.kobj, &cpr_4011_4mxx_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: psu '%s'\n",
+ dev_name(data->hwmon_dev), client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group);
+exit_free:
+ kfree(data);
+exit:
+
+ return status;
+}
+
+static int cpr_4011_4mxx_remove(struct i2c_client *client)
+{
+ struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id cpr_4011_4mxx_id[] = {
+ { "cpr_4011_4mxx", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cpr_4011_4mxx_id);
+
+static struct i2c_driver cpr_4011_4mxx_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "cpr_4011_4mxx",
+ },
+ .probe = cpr_4011_4mxx_probe,
+ .remove = cpr_4011_4mxx_remove,
+ .id_table = cpr_4011_4mxx_id,
+ .address_list = normal_i2c,
+};
+
+static int cpr_4011_4mxx_read_byte(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cpr_4011_4mxx_read_word(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_word_data(client, reg);
+}
+
+static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+ return i2c_smbus_write_word_data(client, reg, value);
+}
+
+struct reg_data_byte {
+ u8 reg;
+ u8 *value;
+};
+
+struct reg_data_word {
+ u8 reg;
+ u16 *value;
+};
+
+static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ int i, status;
+ struct reg_data_byte regs_byte[] = { {0x20, &data->vout_mode},
+ {0x81, &data->fan_fault}};
+ struct reg_data_word regs_word[] = { {0x96, &data->p_out}, /*p_out must be the first one.*/
+ {0x97, &data->p_in},
+ {0x8b, &data->v_out},
+ {0x89, &data->i_in},
+ {0x8c, &data->i_out},
+ {0x8d, &(data->temp_input[0])},
+ {0x8e, &(data->temp_input[1])},
+ {0x3b, &(data->fan_duty_cycle[0])},
+ {0x3c, &(data->fan_duty_cycle[1])},
+ {0x90, &(data->fan_speed[0])},
+ {0x91, &(data->fan_speed[1])}};
+
+ dev_dbg(&client->dev, "Starting cpr_4011_4mxx update\n");
+
+ /* Read byte data */
+ for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
+ status = cpr_4011_4mxx_read_byte(client, regs_byte[i].reg);
+
+ if (status < 0) {
+ dev_dbg(&client->dev, "reg %d, err %d\n",
+ regs_byte[i].reg, status);
+ *(regs_byte[i].value) = 0;
+ }
+ else {
+ *(regs_byte[i].value) = status;
+ }
+ }
+
+ /* Read word data */
+ for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
+ status = cpr_4011_4mxx_read_word(client, regs_word[i].reg);
+
+ if (status < 0) {
+ dev_dbg(&client->dev, "reg %d, err %d\n",
+ regs_word[i].reg, status);
+ *(regs_word[i].value) = 0;
+ }
+ else {
+ *(regs_word[i].value) = status;
+ }
+
+ /*Elimated false values. so p_out must be updated at first. */
+ if (data->p_out == 0) {
+ *(regs_word[i].value) = 0;
+ }
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init cpr_4011_4mxx_init(void)
+{
+ return i2c_add_driver(&cpr_4011_4mxx_driver);
+}
+
+static void __exit cpr_4011_4mxx_exit(void)
+{
+ i2c_del_driver(&cpr_4011_4mxx_driver);
+}
+
+MODULE_AUTHOR("Brandon Chuang ");
+MODULE_DESCRIPTION("CPR_4011_4MXX driver");
+MODULE_LICENSE("GPL");
+
+module_init(cpr_4011_4mxx_init);
+module_exit(cpr_4011_4mxx_exit);
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/leds-accton_as6712_32x.c b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/leds-accton_as6712_32x.c
new file mode 100644
index 000000000000..2b45bc8777c8
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/leds-accton_as6712_32x.c
@@ -0,0 +1,612 @@
+/*
+ * A LED driver for the accton_as6712_32x_led
+ *
+ * Copyright (C) 2014 Accton Technology Corporation.
+ * Brandon Chuang
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*#define DEBUG*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern int as6712_32x_cpld_read (unsigned short cpld_addr, u8 reg);
+extern int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
+
+extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
+extern void led_classdev_resume(struct led_classdev *led_cdev);
+extern void led_classdev_suspend(struct led_classdev *led_cdev);
+
+#define DRVNAME "as6712_32x_led"
+
+struct accton_as6712_32x_led_data {
+ struct platform_device *pdev;
+ struct mutex update_lock;
+ char valid; /* != 0 if registers are valid */
+ unsigned long last_updated; /* In jiffies */
+ u8 reg_val[4]; /* Register value, 0 = LOC/DIAG/FAN LED
+ 1 = PSU1/PSU2 LED
+ 2 = FAN1-4 LED
+ 3 = FAN5-6 LED */
+};
+
+static struct accton_as6712_32x_led_data *ledctl = NULL;
+
+/* LED related data
+ */
+#define LED_TYPE_PSU1_REG_MASK 0x03
+#define LED_MODE_PSU1_GREEN_MASK 0x02
+#define LED_MODE_PSU1_AMBER_MASK 0x01
+#define LED_MODE_PSU1_OFF_MASK 0x03
+#define LED_MODE_PSU1_AUTO_MASK 0x00
+
+#define LED_TYPE_PSU2_REG_MASK 0x0C
+#define LED_MODE_PSU2_GREEN_MASK 0x08
+#define LED_MODE_PSU2_AMBER_MASK 0x04
+#define LED_MODE_PSU2_OFF_MASK 0x0C
+#define LED_MODE_PSU2_AUTO_MASK 0x00
+
+#define LED_TYPE_DIAG_REG_MASK 0x0C
+#define LED_MODE_DIAG_GREEN_MASK 0x08
+#define LED_MODE_DIAG_AMBER_MASK 0x04
+#define LED_MODE_DIAG_OFF_MASK 0x0C
+#define LED_MODE_DIAG_BLINK_MASK 0x48
+
+#define LED_TYPE_FAN_REG_MASK 0x03
+#define LED_MODE_FAN_GREEN_MASK 0x02
+#define LED_MODE_FAN_AMBER_MASK 0x01
+#define LED_MODE_FAN_OFF_MASK 0x03
+#define LED_MODE_FAN_AUTO_MASK 0x00
+
+#define LED_TYPE_FAN1_REG_MASK 0x03
+#define LED_TYPE_FAN2_REG_MASK 0xC0
+#define LED_TYPE_FAN3_REG_MASK 0x30
+#define LED_TYPE_FAN4_REG_MASK 0x0C
+#define LED_TYPE_FAN5_REG_MASK 0x03
+
+#define LED_MODE_FANX_GREEN_MASK 0x01
+#define LED_MODE_FANX_RED_MASK 0x02
+#define LED_MODE_FANX_OFF_MASK 0x00
+
+#define LED_TYPE_LOC_REG_MASK 0x30
+#define LED_MODE_LOC_ON_MASK 0x00
+#define LED_MODE_LOC_OFF_MASK 0x10
+#define LED_MODE_LOC_BLINK_MASK 0x20
+
+static const u8 led_reg[] = {
+ 0xA, /* LOC/DIAG/FAN LED*/
+ 0xB, /* PSU1/PSU2 LED */
+ 0xE, /* FAN2-5 LED */
+ 0xF, /* FAN1 LED */
+};
+
+enum led_type {
+ LED_TYPE_PSU1,
+ LED_TYPE_PSU2,
+ LED_TYPE_DIAG,
+ LED_TYPE_FAN,
+ LED_TYPE_FAN1,
+ LED_TYPE_FAN2,
+ LED_TYPE_FAN3,
+ LED_TYPE_FAN4,
+ LED_TYPE_FAN5,
+ LED_TYPE_LOC
+};
+
+enum led_light_mode {
+ LED_MODE_OFF = 0,
+ LED_MODE_GREEN,
+ LED_MODE_AMBER,
+ LED_MODE_RED,
+ LED_MODE_GREEN_BLINK,
+ LED_MODE_AMBER_BLINK,
+ LED_MODE_RED_BLINK,
+ LED_MODE_AUTO,
+};
+
+struct led_type_mode {
+ enum led_type type;
+ int type_mask;
+ enum led_light_mode mode;
+ int mode_mask;
+};
+
+struct led_type_mode led_type_mode_data[] = {
+{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU1_GREEN_MASK},
+{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU1_AMBER_MASK},
+{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU1_AUTO_MASK},
+{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_OFF, LED_MODE_PSU1_OFF_MASK},
+{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU2_GREEN_MASK},
+{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU2_AMBER_MASK},
+{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU2_AUTO_MASK},
+{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_OFF, LED_MODE_PSU2_OFF_MASK},
+{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_GREEN, LED_MODE_FAN_GREEN_MASK},
+{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AMBER, LED_MODE_FAN_AMBER_MASK},
+{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AUTO, LED_MODE_FAN_AUTO_MASK},
+{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_OFF, LED_MODE_FAN_OFF_MASK},
+{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0},
+{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0},
+{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0},
+{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 6},
+{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 6},
+{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 6},
+{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 4},
+{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 4},
+{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 4},
+{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 2},
+{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 2},
+{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 2},
+{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0},
+{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0},
+{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0},
+{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_GREEN, LED_MODE_DIAG_GREEN_MASK},
+{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_AMBER, LED_MODE_DIAG_AMBER_MASK},
+{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_OFF, LED_MODE_DIAG_OFF_MASK},
+{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_GREEN_BLINK, LED_MODE_DIAG_BLINK_MASK},
+{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER, LED_MODE_LOC_ON_MASK},
+{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_OFF, LED_MODE_LOC_OFF_MASK},
+{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER_BLINK, LED_MODE_LOC_BLINK_MASK}
+};
+
+
+struct fanx_info_s {
+ u8 cname; /* device name */
+ enum led_type type;
+ u8 reg_id; /* map to led_reg & reg_val */
+};
+
+static struct fanx_info_s fanx_info[] = {
+ {'1', LED_TYPE_FAN1, 3},
+ {'2', LED_TYPE_FAN2, 2},
+ {'3', LED_TYPE_FAN3, 2},
+ {'4', LED_TYPE_FAN4, 2},
+ {'5', LED_TYPE_FAN5, 2},
+};
+
+static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
+
+ if (type != led_type_mode_data[i].type)
+ continue;
+
+ if (type == LED_TYPE_DIAG)
+ { /* special case : bit 6 - meaning blinking */
+ if (0x40 & reg_val)
+ return LED_MODE_GREEN_BLINK;
+ }
+ if ((led_type_mode_data[i].type_mask & reg_val) ==
+ led_type_mode_data[i].mode_mask)
+ {
+ return led_type_mode_data[i].mode;
+ }
+ }
+
+ return 0;
+}
+
+static u8 led_light_mode_to_reg_val(enum led_type type,
+ enum led_light_mode mode, u8 reg_val) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
+ if (type != led_type_mode_data[i].type)
+ continue;
+
+ if (mode != led_type_mode_data[i].mode)
+ continue;
+
+ if (type == LED_TYPE_DIAG)
+ {
+ if (mode == LED_MODE_GREEN_BLINK)
+ { /* special case : bit 6 - meaning blinking */
+ reg_val = 0x48 | (reg_val & ~0x4C);
+ break;
+ }
+ else
+ { /* for diag led, other case must cancel bit 6 first */
+ reg_val = reg_val & ~0x40;
+ }
+ }
+ reg_val = led_type_mode_data[i].mode_mask |
+ (reg_val & (~led_type_mode_data[i].type_mask));
+ break;
+ }
+
+ return reg_val;
+}
+
+static int accton_as6712_32x_led_read_value(u8 reg)
+{
+ return as6712_32x_cpld_read(0x60, reg);
+}
+
+static int accton_as6712_32x_led_write_value(u8 reg, u8 value)
+{
+ return as6712_32x_cpld_write(0x60, reg, value);
+}
+
+static void accton_as6712_32x_led_update(void)
+{
+ mutex_lock(&ledctl->update_lock);
+
+ if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
+ || !ledctl->valid) {
+ int i;
+
+ dev_dbg(&ledctl->pdev->dev, "Starting accton_as6712_32x_led update\n");
+
+ /* Update LED data
+ */
+ for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
+ int status = accton_as6712_32x_led_read_value(led_reg[i]);
+
+ if (status < 0) {
+ ledctl->valid = 0;
+ dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status);
+ goto exit;
+ }
+ else
+ {
+ ledctl->reg_val[i] = status;
+ }
+ }
+
+ ledctl->last_updated = jiffies;
+ ledctl->valid = 1;
+ }
+
+exit:
+ mutex_unlock(&ledctl->update_lock);
+}
+
+static void accton_as6712_32x_led_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode,
+ u8 reg, enum led_type type)
+{
+ int reg_val;
+
+ mutex_lock(&ledctl->update_lock);
+
+ reg_val = accton_as6712_32x_led_read_value(reg);
+
+ if (reg_val < 0) {
+ dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val);
+ goto exit;
+ }
+
+ reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val);
+ accton_as6712_32x_led_write_value(reg, reg_val);
+
+ /* to prevent the slow-update issue */
+ ledctl->valid = 0;
+
+exit:
+ mutex_unlock(&ledctl->update_lock);
+}
+
+static void accton_as6712_32x_led_psu_1_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1);
+}
+
+static enum led_brightness accton_as6712_32x_led_psu_1_get(struct led_classdev *cdev)
+{
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]);
+}
+
+static void accton_as6712_32x_led_psu_2_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2);
+}
+
+static enum led_brightness accton_as6712_32x_led_psu_2_get(struct led_classdev *cdev)
+{
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
+}
+
+static void accton_as6712_32x_led_fan_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN);
+}
+
+static enum led_brightness accton_as6712_32x_led_fan_get(struct led_classdev *cdev)
+{
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
+}
+
+
+static void accton_as6712_32x_led_fanx_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ enum led_type led_type1;
+ int reg_id;
+ int i, nsize;
+ int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s);
+
+ for(i=0;iname);
+
+ if (led_cdev->name[nsize-1] == fanx_info[i].cname)
+ {
+ led_type1 = fanx_info[i].type;
+ reg_id = fanx_info[i].reg_id;
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1);
+ return;
+ }
+ }
+}
+
+
+static enum led_brightness accton_as6712_32x_led_fanx_get(struct led_classdev *cdev)
+{
+ enum led_type led_type1;
+ int reg_id;
+ int i, nsize;
+ int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s);
+
+ for(i=0;iname);
+
+ if (cdev->name[nsize-1] == fanx_info[i].cname)
+ {
+ led_type1 = fanx_info[i].type;
+ reg_id = fanx_info[i].reg_id;
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(led_type1, ledctl->reg_val[reg_id]);
+ }
+ }
+
+
+ return led_reg_val_to_light_mode(LED_TYPE_FAN1, ledctl->reg_val[2]);
+}
+
+
+static void accton_as6712_32x_led_diag_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG);
+}
+
+static enum led_brightness accton_as6712_32x_led_diag_get(struct led_classdev *cdev)
+{
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
+}
+
+static void accton_as6712_32x_led_loc_set(struct led_classdev *led_cdev,
+ enum led_brightness led_light_mode)
+{
+ accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC);
+}
+
+static enum led_brightness accton_as6712_32x_led_loc_get(struct led_classdev *cdev)
+{
+ accton_as6712_32x_led_update();
+ return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]);
+}
+
+static struct led_classdev accton_as6712_32x_leds[] = {
+ [LED_TYPE_PSU1] = {
+ .name = "accton_as6712_32x_led::psu1",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_psu_1_set,
+ .brightness_get = accton_as6712_32x_led_psu_1_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_PSU2] = {
+ .name = "accton_as6712_32x_led::psu2",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_psu_2_set,
+ .brightness_get = accton_as6712_32x_led_psu_2_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN] = {
+ .name = "accton_as6712_32x_led::fan",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fan_set,
+ .brightness_get = accton_as6712_32x_led_fan_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN1] = {
+ .name = "accton_as6712_32x_led::fan1",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fanx_set,
+ .brightness_get = accton_as6712_32x_led_fanx_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN2] = {
+ .name = "accton_as6712_32x_led::fan2",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fanx_set,
+ .brightness_get = accton_as6712_32x_led_fanx_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN3] = {
+ .name = "accton_as6712_32x_led::fan3",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fanx_set,
+ .brightness_get = accton_as6712_32x_led_fanx_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN4] = {
+ .name = "accton_as6712_32x_led::fan4",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fanx_set,
+ .brightness_get = accton_as6712_32x_led_fanx_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_FAN5] = {
+ .name = "accton_as6712_32x_led::fan5",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_fanx_set,
+ .brightness_get = accton_as6712_32x_led_fanx_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_DIAG] = {
+ .name = "accton_as6712_32x_led::diag",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_diag_set,
+ .brightness_get = accton_as6712_32x_led_diag_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+ [LED_TYPE_LOC] = {
+ .name = "accton_as6712_32x_led::loc",
+ .default_trigger = "unused",
+ .brightness_set = accton_as6712_32x_led_loc_set,
+ .brightness_get = accton_as6712_32x_led_loc_get,
+ .flags = LED_CORE_SUSPENDRESUME,
+ .max_brightness = LED_MODE_AUTO,
+ },
+};
+
+static int accton_as6712_32x_led_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
+ led_classdev_suspend(&accton_as6712_32x_leds[i]);
+ }
+
+ return 0;
+}
+
+static int accton_as6712_32x_led_resume(struct platform_device *dev)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
+ led_classdev_resume(&accton_as6712_32x_leds[i]);
+ }
+
+ return 0;
+}
+
+static int accton_as6712_32x_led_probe(struct platform_device *pdev)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
+ ret = led_classdev_register(&pdev->dev, &accton_as6712_32x_leds[i]);
+
+ if (ret < 0)
+ break;
+ }
+
+ /* Check if all LEDs were successfully registered */
+ if (i != ARRAY_SIZE(accton_as6712_32x_leds)){
+ int j;
+
+ /* only unregister the LEDs that were successfully registered */
+ for (j = 0; j < i; j++) {
+ led_classdev_unregister(&accton_as6712_32x_leds[i]);
+ }
+ }
+
+ return ret;
+}
+
+static int accton_as6712_32x_led_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
+ led_classdev_unregister(&accton_as6712_32x_leds[i]);
+ }
+
+ return 0;
+}
+
+static struct platform_driver accton_as6712_32x_led_driver = {
+ .probe = accton_as6712_32x_led_probe,
+ .remove = accton_as6712_32x_led_remove,
+ .suspend = accton_as6712_32x_led_suspend,
+ .resume = accton_as6712_32x_led_resume,
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init accton_as6712_32x_led_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&accton_as6712_32x_led_driver);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ ledctl = kzalloc(sizeof(struct accton_as6712_32x_led_data), GFP_KERNEL);
+ if (!ledctl) {
+ ret = -ENOMEM;
+ platform_driver_unregister(&accton_as6712_32x_led_driver);
+ goto exit;
+ }
+
+ mutex_init(&ledctl->update_lock);
+
+ ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
+ if (IS_ERR(ledctl->pdev)) {
+ ret = PTR_ERR(ledctl->pdev);
+ platform_driver_unregister(&accton_as6712_32x_led_driver);
+ kfree(ledctl);
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static void __exit accton_as6712_32x_led_exit(void)
+{
+ platform_device_unregister(ledctl->pdev);
+ platform_driver_unregister(&accton_as6712_32x_led_driver);
+ kfree(ledctl);
+}
+
+module_init(accton_as6712_32x_led_init);
+module_exit(accton_as6712_32x_led_exit);
+
+MODULE_AUTHOR("Brandon Chuang ");
+MODULE_DESCRIPTION("accton_as6712_32x_led driver");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/service/as6712-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/service/as6712-platform-init.service
new file mode 100644
index 000000000000..ffdd6e1cee74
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/service/as6712-platform-init.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=Accton AS6712-32X Platform Monitoring service
+Before=pmon.service
+After=sysinit.target
+DefaultDependencies=no
+
+[Service]
+ExecStartPre=/usr/local/bin/accton_as6712_util.py install
+ExecStart=/usr/local/bin/accton_as6712_monitor.py
+KillSignal=SIGKILL
+SuccessExitStatus=SIGKILL
+
+# Resource Limitations
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/setup.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/setup.py
new file mode 100644
index 000000000000..114b0837be69
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/setup.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+import os
+import sys
+from setuptools import setup
+os.listdir
+
+setup(
+ name='as6712_32x',
+ version='1.0',
+ description='Module to initialize Accton AS6712-32X platforms',
+
+ packages=['as6712_32x'],
+ package_dir={'as6712_32x': 'as6712-32x/classes'},
+)
+
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/README b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/README
new file mode 100644
index 000000000000..bfa90e6b68e1
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/README
@@ -0,0 +1,74 @@
+Copyright (C) 2016 Accton Networks, 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 .
+
+Contents of this package:
+ module - Contains source code of as6712 kernel driver modules.
+ util - operational scripts.
+
+Sonic creates a docker container and run building process under it.
+If user tries to built new drivers, please get into that docker and
+dpkg-buildpackage for them.
+
+All Linux kernel code is licensed under the GPLv1. All other code is
+licensed under the GPLv3. Please see the LICENSE file for copies of
+both licenses.
+
+The code for integacting with Accton AS6712-32X has 2 parts,
+kernel drivers and operational script.
+The kernel drivers of peripherals are under module/ directory.
+1. These drivers can be built to individual ko during dpkg-buildpackage.
+2. A operational script, accton_as6712_util.py, for device initializatian.
+ Run "accton_as6712_util.py install" to install drivers.
+
+To initialize the system, run "accton_as6712_util.py install".
+To clean up the drivers & devices, run "accton_as6712_util.py clean".
+To dump information of sensors, run "accton_as6712_util.py show".
+To dump SFP EEPROM, run "accton_as6712_util.py sff".
+To set fan speed, run "accton_as6712_util.py set fan".
+To enable/disable SFP emission, run "accton_as6712_util.py set sfp".
+To set system LEDs' color, run "accton_as6712_util.py set led"
+For more information, run "accton_as6712_util.py --help".
+
+====================================================================
+Besides applying accton_as6712_util.py to access peripherals, you can
+access peripherals by sysfs nodes directly after the installation is run.
+
+System LED:
+ There are 5 system LEDs at the lower-left corner of front panel.
+ They are loc, diag, fan, ps1, and ps2.
+ The sysfs interface color mappings are as follows:
+ Brightness:
+ 0 => off
+ 1 => green
+ 2 => amber
+ 3 => red
+ 4 => blue
+ But not all colors are available for each LED.
+
+Fan Control:
+ There are 10 fans inside 5 fan modules.
+ All fans share 1 duty setting, ranged from 0~100.
+
+Thermal sensers:
+ 3 temperature sensors are controlled by the lm75 kernel modules.
+
+PSUs:
+ There 2 power supplies slot at the left/right side of the back.
+ Once if a PSU is not plugged, the status of it is shown failed.
+
+There are 32 QSFP modules are equipped.
+Before operating on PSU and QSFP+, please make sure it is well plugged.
+Otherwise, operation is going to fail.
+
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_monitor.py
new file mode 100755
index 000000000000..fbcc74565d62
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_monitor.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Accton Technology Corporation
+#
+# 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 .
+
+# ------------------------------------------------------------------
+# HISTORY:
+# mm/dd/yyyy (A.D.)
+# 11/13/2017: Polly Hsu, Create
+# 1/10/2018: Jostar modify for as7716_32
+# 4/10/2018: Roy Lee modify for as6712_32x
+# ------------------------------------------------------------------
+
+try:
+ import os
+ import sys, getopt
+ import subprocess
+ import click
+ import imp
+ import logging
+ import logging.config
+ import types
+ import time # this is only being used as part of the example
+ import traceback
+ from tabulate import tabulate
+ from as6712_32x.fanutil import FanUtil
+ from as6712_32x.thermalutil import ThermalUtil
+except ImportError as e:
+ raise ImportError('%s - required module not found' % str(e))
+
+# Deafults
+VERSION = '1.0'
+FUNCTION_NAME = 'accton_as6712_monitor'
+
+global log_file
+global log_level
+
+# (LM75_1+ LM75_2+ LM75_3) is LM75 at i2c addresses 0x48, 0x49, and 0x4A.
+# TMP = (LM75_1+ LM75_2+ LM75_3)/3
+#1. If TMP < 35, All fans run with duty 30%.
+#2. If TMP>=35 or the temperature of any one of fan is higher than 40,
+# All fans run with duty 50%
+#3. If TMP >= 40 or the temperature of any one of fan is higher than 45,
+# All fans run with duty 65%.
+#4. If TMP >= 45 or the temperature of any one of fan is higher than 50,
+# All fans run with duty 100%.
+#5. Any one of 5 fans is fault, set duty = 100%.
+#6. Direction factor. If it is B2F direction, duty + 10%.
+
+ # MISC:
+ # 1.Check single LM75 before applied average.
+ # 2.If no matched fan speed is found from the policy,
+ # use FAN_DUTY_CYCLE_MIN as default speed
+ # Get current temperature
+ # 4.Decision 3: Decide new fan speed depend on fan direction/current fan speed/temperature
+
+
+
+
+# Make a class we can use to capture stdout and sterr in the log
+class accton_as6712_monitor(object):
+ # static temp var
+ _ori_temp = 0
+ _new_perc = 0
+ _ori_perc = 0
+
+ def __init__(self, log_file, log_level):
+ """Needs a logger and a logger level."""
+ # set up logging to file
+ logging.basicConfig(
+ filename=log_file,
+ filemode='w',
+ level=log_level,
+ format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
+ datefmt='%H:%M:%S'
+ )
+
+ # set up logging to console
+ if log_level == logging.DEBUG:
+ console = logging.StreamHandler()
+ console.setLevel(log_level)
+ formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
+ console.setFormatter(formatter)
+ logging.getLogger('').addHandler(console)
+
+ logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
+
+ def manage_fans(self):
+ max_duty = 100
+ fan_policy_f2b = {
+ 0: [30, 0, 105000],
+ 1: [50, 105000, 120000],
+ 2: [65, 120000, 135000],
+ 3: [max_duty, 135000, sys.maxsize],
+ }
+ fan_policy_b2f = {
+ 0: [40, 0, 105000],
+ 1: [60, 105000, 120000],
+ 2: [75, 120000, 135000],
+ 3: [max_duty, 135000, sys.maxsize],
+ }
+ fan_policy_single = {
+ 0: 40000,
+ 1: 45000,
+ 2: 50000,
+ }
+
+ thermal = ThermalUtil()
+ fan = FanUtil()
+ for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
+ fan_status = fan.get_fan_status(x)
+ if fan_status is None:
+ logging.debug('INFO. SET new_perc to %d (FAN stauts is None. fan_num:%d)', max_duty, x)
+ return False
+ if fan_status is False:
+ logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', max_duty, x)
+ fan.set_fan_duty_cycle(max_duty)
+ return True
+ #logging.debug('INFO. fan_status is True (fan_num:%d)', x)
+
+ fan_dir=fan.get_fan_dir(1)
+ if fan_dir == 0:
+ fan_policy = fan_policy_f2b
+ else:
+ fan_policy = fan_policy_b2f
+
+ #Decide fan duty by if any of sensors > fan_policy_single.
+ new_duty_cycle = fan_policy[0][0]
+ for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
+ single_thm = thermal._get_thermal_node_val(x)
+ for y in range(0, len(fan_policy_single)):
+ if single_thm > fan_policy_single[y]:
+ if fan_policy[y+1][0] > new_duty_cycle:
+ new_duty_cycle = fan_policy[y+1][0]
+ logging.debug('INFO. Single thermal sensor %d with temp %d > %d , new_duty_cycle=%d',
+ x, single_thm, fan_policy_single[y], new_duty_cycle)
+ single_result = new_duty_cycle
+
+
+ #Find if current duty matched any of define duty.
+ #If not, set it to highest one.
+ cur_duty_cycle = fan.get_fan_duty_cycle()
+ for x in range(0, len(fan_policy)):
+ if cur_duty_cycle == fan_policy[x][0]:
+ break
+ if x == len(fan_policy) :
+ fan.set_fan_duty_cycle(fan_policy[0][0])
+ cur_duty_cycle = max_duty
+
+ #Decide fan duty by if sum of sensors falls into any of fan_policy{}
+ get_temp = thermal.get_thermal_temp()
+ new_duty_cycle = cur_duty_cycle
+ for x in range(0, len(fan_policy)):
+ y = len(fan_policy) - x -1 #checked from highest
+ if get_temp > fan_policy[y][1] and get_temp <= fan_policy[y][2] :
+ new_duty_cycle= fan_policy[y][0]
+ logging.debug('INFO. Sum of temp %d > %d , new_duty_cycle=%d', get_temp, fan_policy[y][1], new_duty_cycle)
+
+ sum_result = new_duty_cycle
+ if (sum_result>single_result):
+ new_duty_cycle = sum_result;
+ else:
+ new_duty_cycle = single_result
+
+ logging.debug('INFO. Final duty_cycle=%d', new_duty_cycle)
+ if(new_duty_cycle != cur_duty_cycle):
+ fan.set_fan_duty_cycle(new_duty_cycle)
+ return True
+
+def main(argv):
+ log_file = '%s.log' % FUNCTION_NAME
+ log_level = logging.INFO
+ if len(sys.argv) != 1:
+ try:
+ opts, args = getopt.getopt(argv,'hdl:',['lfile='])
+ except getopt.GetoptError:
+ print 'Usage: %s [-d] [-l ]' % sys.argv[0]
+ return 0
+ for opt, arg in opts:
+ if opt == '-h':
+ print 'Usage: %s [-d] [-l ]' % sys.argv[0]
+ return 0
+ elif opt in ('-d', '--debug'):
+ log_level = logging.DEBUG
+ elif opt in ('-l', '--lfile'):
+ log_file = arg
+
+ monitor = accton_as6712_monitor(log_file, log_level)
+
+ # Loop forever, doing something useful hopefully:
+ while True:
+ monitor.manage_fans()
+ time.sleep(10)
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_util.py b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_util.py
new file mode 100755
index 000000000000..a77841857e6c
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_util.py
@@ -0,0 +1,627 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 Accton Networks, 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 .
+#
+# Description:
+# Due to adoption of optoe drivers, sideband signals of SFPs are moved
+# into cpld drivers. Add a new dict, cpld_of_module, for mapping this
+# attributes to corresponding cpld nodes.
+#
+
+
+"""
+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
+ show : show all systen status
+ sff : dump SFP eeprom
+ set : change board setting with fan|led|sfp
+"""
+
+import os
+import commands
+import sys, getopt
+import logging
+import re
+import time
+from collections import namedtuple
+
+PROJECT_NAME = 'as6712_32x'
+version = '0.2.0'
+verbose = False
+DEBUG = False
+args = []
+ALL_DEVICE = {}
+DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':4, 'psu':2, 'sfp':32}
+
+
+led_prefix ='/sys/devices/platform/as6712_32x_led/leds/accton_'+PROJECT_NAME+'_led::'
+fan_prefix ='/sys/devices/platform/as6712_32x_'
+hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'],
+ 'fan1': ['fan'],
+ 'fan2': ['fan'],
+ 'fan3': ['fan'],
+ 'fan4': ['fan'],
+ 'fan5': ['fan'],
+ }
+hwmon_nodes = {'led': ['brightness'] ,
+ 'fan1': ['fan1_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'],
+ 'fan2': ['fan2_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'],
+ 'fan3': ['fan3_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'],
+ 'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'],
+ 'fan5': ['fan5_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'],
+ }
+hwmon_prefix ={'led': led_prefix,
+ 'fan1': fan_prefix,
+ 'fan2': fan_prefix,
+ 'fan3': fan_prefix,
+ 'fan4': fan_prefix,
+ 'fan5': fan_prefix,
+ }
+
+i2c_prefix = '/sys/bus/i2c/devices/'
+i2c_bus = {'thermal': ['38-0048','39-0049', '40-004a', '41-004b'] ,
+ 'psu': ['35-0038','36-003b'],
+ 'sfp': ['-0050']}
+i2c_nodes = {
+ 'thermal': ['hwmon/hwmon*/temp1_input'] ,
+ 'psu': ['psu_present ', 'psu_power_good'] ,
+ 'sfp': ['module_present_', 'sfp_tx_disable']}
+
+sfp_map = [ 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33
+ ]
+
+#For sideband signals of SFP/QSFP modules.
+bus_of_cpld = [0, 1]
+cpld_of_module = {'-0062': list(range(0,16)),
+ '-0064': list(range(16,32)) }
+
+
+mknod =[
+'echo as6712_32x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-0/new_device',
+'echo as6712_32x_cpld2 0x62 > /sys/bus/i2c/devices/i2c-0/new_device',
+'echo as6712_32x_cpld3 0x64 > /sys/bus/i2c/devices/i2c-0/new_device',
+'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device',
+'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device',
+
+# PSU-1
+'echo as6712_32x_psu1 0x38 > /sys/bus/i2c/devices/i2c-35/new_device',
+'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-35/new_device',
+#'echo as6712_32x_psu1 0x50 > /sys/bus/i2c/devices/i2c-35/new_device',
+#'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-35/new_device',
+
+# PSU-2
+'echo as6712_32x_psu2 0x3b > /sys/bus/i2c/devices/i2c-36/new_device',
+'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-36/new_device',
+#'echo as6712_32x_psu2 0x53 > /sys/bus/i2c/devices/i2c-36/new_device',
+#'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-36/new_device',
+
+'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-38/new_device',
+'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-39/new_device',
+'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-40/new_device',
+'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-41/new_device',
+]
+
+mknod2 =[
+'echo as6712_32x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-1/new_device',
+'echo as6712_32x_cpld2 0x62 > /sys/bus/i2c/devices/i2c-1/new_device',
+'echo as6712_32x_cpld3 0x64 > /sys/bus/i2c/devices/i2c-1/new_device',
+'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-0/new_device',
+'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device',
+
+# PSU-1
+'echo as6712_32x_psu1 0x38 > /sys/bus/i2c/devices/i2c-35/new_device',
+'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-35/new_device',
+#'echo as6712_32x_psu1 0x50 > /sys/bus/i2c/devices/i2c-35/new_device',
+#'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-35/new_device',
+
+# PSU-2
+'echo as6712_32x_psu2 0x3b > /sys/bus/i2c/devices/i2c-36/new_device',
+'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-36/new_device',
+#'echo as6712_32x_psu2 0x53 > /sys/bus/i2c/devices/i2c-36/new_device',
+#'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-36/new_device',
+
+'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-38/new_device',
+'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-39/new_device',
+'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-40/new_device',
+'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-41/new_device',
+]
+
+FORCE = 0
+
+
+
+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(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG)
+ logging.basicConfig(level=logging.INFO)
+ elif opt in ('-f', '--force'):
+ FORCE = 1
+ else:
+ logging.info('no option')
+ for arg in args:
+ if arg == 'install':
+ do_install()
+ elif arg == 'clean':
+ do_uninstall()
+ elif arg == 'show':
+ device_traversal()
+ elif arg == 'sff':
+ if len(args)!=2:
+ show_eeprom_help()
+ elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']:
+ show_eeprom_help()
+ else:
+ show_eeprom(args[1])
+ return
+ elif arg == 'set':
+ if len(args)<3:
+ show_set_help()
+ else:
+ set_device(args[1:])
+ return
+ else:
+ show_help()
+
+
+ return 0
+
+def show_help():
+ print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
+ sys.exit(0)
+
+def show_set_help():
+ cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
+ print cmd +" [led|sfp|fan]"
+ print " use \""+ cmd + " led 0-4 \" to set led color"
+ print " use \""+ cmd + " fan 0-100\" to set fan duty percetage"
+ print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable"
+ sys.exit(0)
+
+def show_eeprom_help():
+ cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
+ print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom"
+ sys.exit(0)
+
+def my_log(txt):
+ if DEBUG == True:
+ print "[ACCTON DBG]: "+txt
+ return
+
+def log_os_system(cmd, show):
+ logging.info('Run :'+cmd)
+ status = 1
+ output = ""
+ status, output = commands.getstatusoutput(cmd)
+ my_log (cmd +"with result:" + str(status))
+ my_log ("cmd:" + cmd)
+ my_log (" output:"+output)
+ if status:
+ logging.info('Failed :'+cmd)
+ if show:
+ print('Failed :'+cmd)
+ return status, output
+
+def driver_inserted():
+ ret, lsmod = log_os_system("lsmod| grep accton", 0)
+ logging.info('mods:'+lsmod)
+ if len(lsmod) ==0:
+ return False
+
+
+
+kos = [
+'depmod -ae',
+'modprobe i2c_dev',
+'modprobe i2c_mux_pca954x',
+'modprobe optoe',
+'modprobe accton_as6712_32x_cpld',
+'modprobe cpr_4011_4mxx',
+#'modprobe ym2651y',
+'modprobe accton_as6712_32x_fan',
+'modprobe leds-accton_as6712_32x',
+'modprobe accton_as6712_32x_psu']
+
+def driver_install():
+ global FORCE
+ for i in range(0,len(kos)):
+ status, output = log_os_system(kos[i], 1)
+ if status:
+ if FORCE == 0:
+ return status
+ return 0
+
+def driver_uninstall():
+ global FORCE
+ for i in range(0,len(kos)):
+ rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
+ rm = rm.replace("insmod", "rmmod")
+ status, output = log_os_system(rm, 1)
+ if status:
+ if FORCE == 0:
+ return status
+ return 0
+
+def cpld_bus_check():
+ tmp = "i2cget -y -f 0 0x60"
+ status, output = log_os_system(tmp, 0)
+ if status:
+ return 1
+ else:
+ return 0
+
+def i2c_order_check():
+ # i2c bus 0 and 1 might be installed in different order.
+ # Here check if 0x70 is exist @ i2c-0
+ tmp = "echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device"
+ status, output = log_os_system(tmp, 0)
+ if not device_exist():
+ order = 1
+ else:
+ order = 0
+ tmp = "echo 0x70 > /sys/bus/i2c/devices/i2c-1/delete_device"
+ status, output = log_os_system(tmp, 0)
+ return order
+
+def device_install():
+ global FORCE
+
+ order = i2c_order_check()
+ # if 0x76 is not exist @i2c-0, use reversed bus order
+ if order:
+ for i in range(0,len(mknod2)):
+ #for pca932x need times to built new i2c buses
+ if mknod2[i].find('pca954') != -1:
+ time.sleep(2)
+
+ status, output = log_os_system(mknod2[i], 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ else:
+ for i in range(0,len(mknod)):
+ #for pca932x need times to built new i2c buses
+ if mknod[i].find('pca954') != -1:
+ time.sleep(2)
+
+ status, output = log_os_system(mknod[i], 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ for i in range(0,len(sfp_map)):
+ status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+ status, output =log_os_system("echo port"+str(i)+" > /sys/bus/i2c/devices/"+str(sfp_map[i])+"-0050/port_name", 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ return
+
+def device_uninstall():
+ global FORCE
+
+ status, output =log_os_system("ls /sys/bus/i2c/devices/0-0070", 0)
+ if status==0:
+ I2C_ORDER=1
+ else:
+ I2C_ORDER=0
+
+ for i in range(0,len(sfp_map)):
+ target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device"
+ status, output =log_os_system("echo 0x50 > "+ target, 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ if I2C_ORDER==0:
+ nodelist = mknod
+ else:
+ nodelist = mknod2
+
+ for i in range(len(nodelist)):
+ target = nodelist[-(i+1)]
+ temp = target.split()
+ del temp[1]
+ temp[-1] = temp[-1].replace('new_device', 'delete_device')
+ status, output = log_os_system(" ".join(temp), 1)
+ if status:
+ print output
+ if FORCE == 0:
+ return status
+
+ return
+
+def system_ready():
+ if driver_inserted() == False:
+ return False
+ if not device_exist():
+ return False
+ return True
+
+def do_install():
+ print "Checking system...."
+ if driver_inserted() == False:
+ print "No driver, installing...."
+ status = driver_install()
+ if status:
+ if FORCE == 0:
+ return status
+ else:
+ print PROJECT_NAME.upper()+" drivers detected...."
+ if not device_exist():
+ print "No device, installing...."
+ status = device_install()
+ if status:
+ if FORCE == 0:
+ return status
+ else:
+ print PROJECT_NAME.upper()+" devices detected...."
+ return
+
+def do_uninstall():
+ print "Checking system...."
+ if not device_exist():
+ print PROJECT_NAME.upper() +" has no device installed...."
+ else:
+ print "Removing device...."
+ status = device_uninstall()
+ if status:
+ if FORCE == 0:
+ return status
+
+ if driver_inserted()== False :
+ print PROJECT_NAME.upper() +" has no driver installed...."
+ else:
+ print "Removing installed driver...."
+ status = driver_uninstall()
+ if status:
+ if FORCE == 0:
+ return status
+
+ return
+
+def devices_info():
+ global DEVICE_NO
+ global ALL_DEVICE
+ global i2c_bus, hwmon_types
+ for key in DEVICE_NO:
+ ALL_DEVICE[key]= {}
+ for i in range(0,DEVICE_NO[key]):
+ ALL_DEVICE[key][key+str(i+1)] = []
+
+ order = cpld_bus_check()
+ for key in i2c_bus:
+ buses = i2c_bus[key]
+ nodes = i2c_nodes[key]
+ for i in range(0,len(buses)):
+ for j in range(0,len(nodes)):
+ if 'fan' == key:
+ for k in range(0,DEVICE_NO[key]):
+ node = key+str(k+1)
+ path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j]
+ my_log(node+": "+ path)
+ ALL_DEVICE[key][node].append(path)
+ elif 'sfp' == key:
+ for k in range(0,DEVICE_NO[key]):
+ for lk in cpld_of_module:
+ if k in cpld_of_module[lk]:
+ bus = bus_of_cpld[order]
+ node = key+str(k+1)
+ path = i2c_prefix + str(bus) + lk + "/"+ nodes[j] + str(k+1)
+ my_log(node+": "+ path)
+ ALL_DEVICE[key][node].append(path)
+ else:
+ node = key+str(i+1)
+ path = i2c_prefix+ buses[i]+"/"+ nodes[j]
+ my_log(node+": "+ path)
+ ALL_DEVICE[key][node].append(path)
+
+ for key in hwmon_types:
+ itypes = hwmon_types[key]
+ nodes = hwmon_nodes[key]
+ for i in range(0,len(itypes)):
+ for j in range(0,len(nodes)):
+ node = key+"_"+itypes[i]
+ path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j]
+ my_log(node+": "+ path)
+ ALL_DEVICE[key][ key+str(i+1)].append(path)
+
+ #show dict all in the order
+ if DEBUG == True:
+ for i in sorted(ALL_DEVICE.keys()):
+ print(i+": ")
+ for j in sorted(ALL_DEVICE[i].keys()):
+ print(" "+j)
+ for k in (ALL_DEVICE[i][j]):
+ print(" "+" "+k)
+ return
+
+def show_eeprom(index):
+ if system_ready()==False:
+ print("System's not ready.")
+ print("Please install first!")
+ return
+
+ if len(ALL_DEVICE)==0:
+ devices_info()
+ node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0]
+ node = node.replace(node.split("/")[-1], 'eeprom')
+ # check if got hexdump command in current environment
+ ret, log = log_os_system("which hexdump", 0)
+ ret, log2 = log_os_system("which busybox hexdump", 0)
+ if len(log):
+ hex_cmd = 'hexdump'
+ elif len(log2):
+ hex_cmd = ' busybox hexdump'
+ else:
+ log = 'Failed : no hexdump cmd!!'
+ logging.info(log)
+ print log
+ return 1
+
+ print node + ":"
+ ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
+ if ret==0:
+ print log
+ else:
+ print "**********device no found**********"
+ return
+
+def set_device(args):
+ global DEVICE_NO
+ global ALL_DEVICE
+ if system_ready()==False:
+ print("System's not ready.")
+ print("Please install first!")
+ return
+
+ if len(ALL_DEVICE)==0:
+ devices_info()
+
+ if args[0]=='led':
+ if int(args[1])>4:
+ show_set_help()
+ return
+ #print ALL_DEVICE['led']
+ for i in range(0,len(ALL_DEVICE['led'])):
+ for k in (ALL_DEVICE['led']['led'+str(i+1)]):
+ ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
+ if ret:
+ return ret
+ elif args[0]=='fan':
+ if int(args[1])>100:
+ show_set_help()
+ return
+ #print ALL_DEVICE['fan']
+ #fan1~6 is all fine, all fan share same setting
+ node = ALL_DEVICE['fan1'] ['fan11'][0]
+ node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage')
+ ret, log = log_os_system("cat "+ node, 1)
+ if ret==0:
+ print ("Previous fan duty: " + log.strip() +"%")
+ ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
+ if ret==0:
+ print ("Current fan duty: " + args[1] +"%")
+ return ret
+ elif args[0]=='sfp':
+ if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0:
+ show_set_help()
+ return
+ if len(args)<2:
+ show_set_help()
+ return
+
+ if int(args[2])>1:
+ show_set_help()
+ return
+
+ #print ALL_DEVICE[args[0]]
+ for i in range(0,len(ALL_DEVICE[args[0]])):
+ for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]:
+ if j.find('tx_disable')!= -1:
+ ret, log = log_os_system("echo "+args[2]+" >"+ j, 1)
+ if ret:
+ return ret
+
+ return
+
+#get digits inside a string.
+#Ex: 31 for "sfp31"
+def get_value(input):
+ digit = re.findall('\d+', input)
+ return int(digit[0])
+
+def device_traversal():
+ if system_ready()==False:
+ print("System's not ready.")
+ print("Please install first!")
+ return
+
+ if len(ALL_DEVICE)==0:
+ devices_info()
+ for i in sorted(ALL_DEVICE.keys()):
+ print("============================================")
+ print(i.upper()+": ")
+ print("============================================")
+
+ for j in sorted(ALL_DEVICE[i].keys(), key=get_value):
+ print " "+j+":",
+ for k in (ALL_DEVICE[i][j]):
+ ret, log = log_os_system("cat "+k, 0)
+ func = k.split("/")[-1].strip()
+ func = re.sub(j+'_','',func,1)
+ func = re.sub(i.lower()+'_','',func,1)
+ if ret==0:
+ print func+"="+log+" ",
+ else:
+ print func+"="+"X"+" ",
+ print
+ print("----------------------------------------------------------------")
+
+
+ print
+ return
+
+def device_exist():
+ ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0)
+ ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0)
+ return not(ret1 or ret2)
+
+if __name__ == "__main__":
+ main()
diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control
index 8b020a6644e0..c2e4ccc795df 100755
--- a/platform/broadcom/sonic-platform-modules-accton/debian/control
+++ b/platform/broadcom/sonic-platform-modules-accton/debian/control
@@ -32,3 +32,7 @@ Description: kernel modules for platform devices such as fan, led, sfp
Package: sonic-platform-accton-as7326-56x
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp
+
+Package: sonic-platform-accton-as6712-32x
+Architecture: amd64
+Description: kernel modules for platform devices such as fan, led, sfp
diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules
index 8274607f27b5..2ac628b45cb3 100755
--- a/platform/broadcom/sonic-platform-modules-accton/debian/rules
+++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules
@@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
-MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x
+MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service
diff --git a/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules b/platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules
old mode 100644
new mode 100755