From 8f843ef4f8e7060526dc24ffe94b68acca9f95e7 Mon Sep 17 00:00:00 2001 From: roy_lee Date: Fri, 19 Oct 2018 11:52:03 +0800 Subject: [PATCH 1/4] [platform] Add 6712 dpkg on building. Signed-off-by: roy_lee --- platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-accton.mk | 6 ++++++ .../broadcom/sonic-platform-modules-accton/debian/control | 4 ++++ .../broadcom/sonic-platform-modules-accton/debian/rules | 2 +- .../sonic-platform-modules-alphanetworks/debian/rules | 0 5 files changed, 12 insertions(+), 1 deletion(-) mode change 100644 => 100755 platform/broadcom/sonic-platform-modules-alphanetworks/debian/rules 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/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 From 2215397624501deb653df490e583d32f85234461 Mon Sep 17 00:00:00 2001 From: roy_lee Date: Fri, 19 Oct 2018 11:52:45 +0800 Subject: [PATCH 2/4] [platform] remove scache_filename for it failed the bcm checker. Signed-off-by: roy_lee --- .../td2-as6712-32x40G.config.bcm | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/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 From 99c150f8bbf99af0856092b4529abdd55dbc7a08 Mon Sep 17 00:00:00 2001 From: roy_lee Date: Fri, 19 Oct 2018 11:55:53 +0800 Subject: [PATCH 3/4] [plaform] add platform/device as6712-32x. Signed-off-by: roy_lee --- .../Accton-AS6712-32X/port_config.ini | 33 + .../Accton-AS6712-32X/sai.profile | 1 + .../x86_64-accton_as6712_32x-r0/default_sku | 1 + .../installer.conf | 3 + .../led_proc_init.soc | 104 +++ .../plugins/eeprom.py | 24 + .../plugins/psuutil.py | 61 ++ .../plugins/sfputil.py | 215 +++++ .../x86_64-accton_as6712_32x-r0/sensors.conf | 23 + .../as6712-32x/classes/__init__.py | 0 .../as6712-32x/classes/fanutil.py | 253 +++++ .../as6712-32x/classes/thermalutil.py | 124 +++ .../as6712-32x/modules/Makefile | 2 + .../modules/accton-as6712-32x-cpld.c | 883 ++++++++++++++++++ .../modules/accton_as6712_32x_fan.c | 463 +++++++++ .../modules/accton_as6712_32x_psu.c | 364 ++++++++ .../as6712-32x/modules/cpr_4011_4mxx.c | 439 +++++++++ .../modules/leds-accton_as6712_32x.c | 612 ++++++++++++ .../service/as6712-platform-init.service | 17 + .../as6712-32x/setup.py | 16 + .../as6712-32x/utils/README | 74 ++ .../as6712-32x/utils/accton_as6712_monitor.py | 208 +++++ .../as6712-32x/utils/accton_as6712_util.py | 627 +++++++++++++ 23 files changed, 4547 insertions(+) create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/port_config.ini create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/Accton-AS6712-32X/sai.profile create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/default_sku create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/installer.conf create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/led_proc_init.soc create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/plugins/eeprom.py create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/plugins/psuutil.py create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/plugins/sfputil.py create mode 100644 device/accton/x86_64-accton_as6712_32x-r0/sensors.conf create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/fanutil.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/classes/thermalutil.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_fan.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton_as6712_32x_psu.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/cpr_4011_4mxx.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/leds-accton_as6712_32x.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/service/as6712-platform-init.service create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/README create mode 100755 platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-accton/as6712-32x/utils/accton_as6712_util.py 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/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/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 100644 index 000000000000..b015015c2aa4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c @@ -0,0 +1,883 @@ +/* + * 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 i2c_mux_core *muxc; + 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 as6712_32x_cpld_data *data = i2c_get_clientdata(client); + + 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 as6712_32x_cpld_data *data = i2c_get_clientdata(client); + 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 as6712_32x_cpld_data *data = i2c_get_clientdata(client); + 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 as6712_32x_cpld_data *data = i2c_get_clientdata(client); + + 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; + + data = i2c_mux_priv(muxc); + i2c_set_clientdata(client, data); + data->muxc = muxc; + data->client = client; + + 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 as6712_32x_cpld_data *data = i2c_get_clientdata(client); + struct i2c_mux_core *muxc = data->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() From e8c3c7a93ec73949ef257af281fe0ab134cee4a2 Mon Sep 17 00:00:00 2001 From: roy_lee Date: Mon, 22 Oct 2018 14:33:05 +0800 Subject: [PATCH 4/4] [platform] fix error on private data reference at cpld.c. Signed-off-by: roy_lee --- .../modules/accton-as6712-32x-cpld.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) mode change 100644 => 100755 platform/broadcom/sonic-platform-modules-accton/as6712-32x/modules/accton-as6712-32x-cpld.c 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 old mode 100644 new mode 100755 index b015015c2aa4..ff350597a718 --- 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 @@ -66,7 +66,6 @@ struct as6712_32x_cpld_data { enum cpld_mux_type type; struct i2c_client *client; u8 last_chan; /* last register value */ - struct i2c_mux_core *muxc; struct device *hwmon_dev; struct mutex update_lock; }; @@ -379,7 +378,8 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, u8 values[2] = {0}; u8 regs[] = {0xA, 0xB}; struct i2c_client *client = to_i2c_client(dev); - struct as6712_32x_cpld_data *data = i2c_get_clientdata(client); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc); mutex_lock(&data->update_lock); @@ -408,7 +408,9 @@ static ssize_t set_status(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); - struct as6712_32x_cpld_data *data = i2c_get_clientdata(client); + 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; @@ -452,7 +454,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); - struct as6712_32x_cpld_data *data = i2c_get_clientdata(client); + 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; @@ -501,7 +504,8 @@ static ssize_t access(struct device *dev, struct device_attribute *da, int status; u32 addr, val; struct i2c_client *client = to_i2c_client(dev); - struct as6712_32x_cpld_data *data = i2c_get_clientdata(client); + 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; @@ -668,13 +672,13 @@ static int as6712_32x_cpld_mux_probe(struct i2c_client *client, if (!muxc) return -ENOMEM; + i2c_set_clientdata(client, muxc); data = i2c_mux_priv(muxc); - i2c_set_clientdata(client, data); - data->muxc = 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->type = id->driver_data; data->last_chan = chips[data->type].deselectChan; /* force the first selection */ /* Now create an adapter for each channel */ @@ -739,8 +743,8 @@ static int as6712_32x_cpld_mux_probe(struct i2c_client *client, static int as6712_32x_cpld_mux_remove(struct i2c_client *client) { - struct as6712_32x_cpld_data *data = i2c_get_clientdata(client); - struct i2c_mux_core *muxc = data->muxc; + 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);