[device][platform] add platform as5812-54x, accton. (#2889)

* Add new device accton_as5812_54x.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Rename 5812's config.bcm.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Change fan module to support lm-sensors.
Validate for thermal policy.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Add bask reset and lpmode control of 6 QSFP ports.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Get currect duty of fan for comparing. Instead of by stored duty from previous iteration.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Roll back the mistakes to update mellanox submodules.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Rollback for misoperation on submodule platform/p4/SAI-P4-BM.
Signed-off-by: roy_lee <roy_lee@accton.com>

* Change indexes of ports to start from 1, as them on the front panel.
Add low-power mode control of the transciever's eeprom, follows SFF-8436.
Signed-off-by: roy_lee <roy_lee@accton.com>
This commit is contained in:
Roy Lee 2019-05-29 13:44:32 +08:00 committed by lguohan
parent df149cd1fc
commit 4d212debc7
31 changed files with 7170 additions and 59 deletions

View File

@ -0,0 +1,73 @@
# name lanes alias index
Ethernet0 13 tenGigE0 1
Ethernet1 14 tenGigE1 2
Ethernet2 15 tenGigE2 3
Ethernet3 16 tenGigE3 4
Ethernet4 21 tenGigE4 5
Ethernet5 22 tenGigE5 6
Ethernet6 23 tenGigE6 7
Ethernet7 24 tenGigE7 8
Ethernet8 25 tenGigE8 9
Ethernet9 26 tenGigE9 10
Ethernet10 27 tenGigE10 11
Ethernet11 28 tenGigE11 12
Ethernet12 29 tenGigE12 13
Ethernet13 30 tenGigE13 14
Ethernet14 31 tenGigE14 15
Ethernet15 32 tenGigE15 16
Ethernet16 45 tenGigE16 17
Ethernet17 46 tenGigE17 18
Ethernet18 47 tenGigE18 19
Ethernet19 48 tenGigE19 20
Ethernet20 49 tenGigE20 21
Ethernet21 50 tenGigE21 22
Ethernet22 51 tenGigE22 23
Ethernet23 52 tenGigE23 24
Ethernet24 53 tenGigE24 25
Ethernet25 54 tenGigE25 26
Ethernet26 55 tenGigE26 27
Ethernet27 56 tenGigE27 28
Ethernet28 57 tenGigE28 29
Ethernet29 58 tenGigE29 30
Ethernet30 59 tenGigE30 31
Ethernet31 60 tenGigE31 32
Ethernet32 61 tenGigE32 33
Ethernet33 62 tenGigE33 34
Ethernet34 63 tenGigE34 35
Ethernet35 64 tenGigE35 36
Ethernet36 65 tenGigE36 37
Ethernet37 66 tenGigE37 38
Ethernet38 67 tenGigE38 39
Ethernet39 68 tenGigE39 40
Ethernet40 69 tenGigE40 41
Ethernet41 70 tenGigE41 42
Ethernet42 71 tenGigE42 43
Ethernet43 72 tenGigE43 44
Ethernet44 73 tenGigE44 45
Ethernet45 74 tenGigE45 46
Ethernet46 75 tenGigE46 47
Ethernet47 76 tenGigE47 48
Ethernet48 97 tenGigE48 49
Ethernet49 98 tenGigE49 50
Ethernet50 99 tenGigE50 51
Ethernet51 100 tenGigE51 52
Ethernet52 101 tenGigE52 53
Ethernet53 102 tenGigE53 54
Ethernet54 103 tenGigE54 55
Ethernet55 104 tenGigE55 56
Ethernet56 81 tenGigE56 57
Ethernet57 82 tenGigE57 58
Ethernet58 83 tenGigE58 59
Ethernet59 84 tenGigE59 60
Ethernet60 105 tenGigE60 61
Ethernet61 106 tenGigE61 62
Ethernet62 107 tenGigE62 63
Ethernet63 108 tenGigE63 64
Ethernet64 109 tenGigE64 65
Ethernet65 110 tenGigE65 66
Ethernet66 111 tenGigE66 67
Ethernet67 112 tenGigE67 68
Ethernet68 77 tenGigE68 69
Ethernet69 78 tenGigE69 70
Ethernet70 79 tenGigE70 71
EthernEt71 80 tenGigE71 72

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as5812-72x10G.config.bcm

View File

@ -0,0 +1,148 @@
os=unix
bcm_stat_flags=0
parity_enable=0
parity_correction=0
bcm_num_cos=8
l2_mem_entries=32768
l3_mem_entries=16384
l3_alpm_enable=2
ipv6_lpm_128b_enable=1
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 72 ports with 48 10G ports and 6 40G ports for breakout mode
pbmp_oversubscribe=0x1fffffffffffffffffe
pbmp_xport_xe=0x1fffffffffffffffffe
rate_ext_mdio_divisor=96
#SFP+ 1-4 from WC3
portmap_1=13:10
portmap_2=14:10
portmap_3=15:10
portmap_4=16:10
#SFP+ 5-8 from WC5
portmap_5=21:10
portmap_6=22:10
portmap_7=23:10
portmap_8=24:10
#SFP+ 9-12 from WC6
portmap_9=25:10
portmap_10=26:10
portmap_11=27:10
portmap_12=28:10
#SFP+ 13-16 from WC7
portmap_13=29:10
portmap_14=30:10
portmap_15=31:10
portmap_16=32:10
#SFP+ 17-20 from WC11
portmap_17=45:10
portmap_18=46:10
portmap_19=47:10
portmap_20=48:10
#SFP+ 21-24 from WC12
portmap_21=49:10
portmap_22=50:10
portmap_23=51:10
portmap_24=52:10
#SFP+ 25-28 from WC13
portmap_25=53:10
portmap_26=54:10
portmap_27=55:10
portmap_28=56:10
#SFP+ 29-32 from WC14
portmap_29=57:10
portmap_30=58:10
portmap_31=59:10
portmap_32=60:10
#SFP+ 33-36 from WC15
portmap_33=61:10
portmap_34=62:10
portmap_35=63:10
portmap_36=64:10
#SFP+ 37-40 from WC16
portmap_37=65:10
portmap_38=66:10
portmap_39=67:10
portmap_40=68:10
#SFP+ 41-44 from WC17
portmap_41=69:10
portmap_42=70:10
portmap_43=71:10
portmap_44=72:10
#SFP+ 45-48 from WC18
portmap_45=73:10
portmap_46=74:10
portmap_47=75:10
portmap_48=76:10
# QSFP+ 49/WC24/port 49
portmap_49=97:10
portmap_50=98:10
portmap_51=99:10
portmap_52=100:10
# QSFP+ 51/WC25/port 50
portmap_53=101:10
portmap_54=102:10
portmap_55=103:10
portmap_56=104:10
# QSFP+ 53/WC20/port 51
portmap_57=81:10
portmap_58=82:10
portmap_59=83:10
portmap_60=84:10
# QSFP+ 50/WC26/port 52
portmap_61=105:10
portmap_62=106:10
portmap_63=107:10
portmap_64=108:10
# QSFP+ 52/WC27/port 53
portmap_65=109:10
portmap_66=110:10
portmap_67=111:10
portmap_68=112:10
# QSFP+ 54/WC19/port 54
portmap_69=77:10
portmap_70=78:10
portmap_71=79:10
portmap_72=80:10
# 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

View File

@ -0,0 +1 @@
Accton-AS5812-54X t1

View File

@ -0,0 +1,3 @@
CONSOLE_PORT=0x2f8
CONSOLE_DEV=1
CONSOLE_SPEED=115200

View File

@ -0,0 +1,162 @@
# LED setting for active
# -----------------------------------------------------------------------------
# for as5812_54x (48xg+6qxg)
#
# on green - if link up
# off - if link down
# blink - if active
# -----------------------------------------------------------------------------
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63
m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0
m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1
m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2
m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3
m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4
m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5
m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6
m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23
m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24
m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25
m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26
m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27
m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28
m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29
m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30
m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63
led 0 stop
led 0 prog \
06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \
61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \
D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \
06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \
96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \
04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \
0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00
led 0 start
led 1 stop
led 1 prog \
06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \
61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \
67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \
67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \
67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \
D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \
63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \
FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \
85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \
A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \
57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00
led 1 start

View File

@ -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)

View File

@ -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: "57-0038",
2: "58-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

View File

@ -0,0 +1,311 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
import os
import pickle
from ctypes import create_string_buffer
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 = 1
PORT_END = 72
PORTS_IN_BLOCK = 72
QSFP_PORT_START = 48
QSFP_PORT_END = 72
BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{1}-0050/"
BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
BASE_CPLD2_PATH = "/sys/bus/i2c/devices/{0}-0061/"
BASE_CPLD3_PATH = "/sys/bus/i2c/devices/{0}-0062/"
I2C_BUS_ORDER = -1
#The sidebands of QSFP is different.
#present is in-order.
#But lp_mode and reset are not.
qsfp_sb_map = [1, 3, 5, 2, 4, 6]
_port_to_is_present = {}
_port_to_lp_mode = {}
_port_to_eeprom_mapping = {}
_port_to_i2c_mapping = {
1: [1, 2],
2: [2, 3],
3: [3, 4],
4: [4, 5],
5: [5, 6],
6: [6, 7],
7: [7, 8],
8: [8, 9],
9: [9, 10],
10: [10, 11],
11: [11, 12],
12: [12, 13],
13: [13, 14],
14: [14, 15],
15: [15, 16],
16: [16, 17],
17: [17, 18],
18: [18, 19],
19: [19, 20],
20: [20, 21],
21: [21, 22],
22: [22, 23],
23: [23, 24],
24: [24, 25],
25: [25, 26],
26: [26, 27],
27: [27, 28],
28: [28, 29],
29: [29, 30],
30: [30, 31],
31: [31, 32],
32: [32, 33],
33: [33, 34],
34: [34, 35],
35: [35, 36],
36: [36, 37],
37: [37, 38],
38: [38, 39],
39: [39, 40],
40: [40, 41],
41: [41, 42],
42: [42, 43],
43: [43, 44],
44: [44, 45],
45: [45, 46],
46: [46, 47],
47: [47, 48],
48: [48, 49],
49: [49, 50],#QSFP49
50: [49, 50],
51: [49, 50],
52: [49, 50],
53: [50, 52],#QSFP50
54: [50, 52],
55: [50, 52],
56: [50, 52],
57: [51, 54],#QSFP51
58: [51, 54],
59: [51, 54],
60: [51, 54],
61: [52, 51],#QSFP52
62: [52, 51],
63: [52, 51],
64: [52, 51],
65: [53, 53],#QSFP53
66: [53, 53],
67: [53, 53],
68: [53, 53],
69: [54, 55],#QSFP54
70: [54, 55],
71: [54, 55],
72: [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(self.port_start, self.port_end+1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(
self._port_to_i2c_mapping[x][1]
)
SfpUtilBase.__init__(self)
#Two i2c buses might get flipped order, check them both.
def update_i2c_order(self):
if os.path.exists("/tmp/accton_util.p"):
self.I2C_BUS_ORDER = pickle.load(open("/tmp/accton_util.p", "rb"))
else:
if self.I2C_BUS_ORDER < 0:
eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
if os.path.exists(eeprom_path):
self.I2C_BUS_ORDER = 0
eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
if os.path.exists(eeprom_path):
self.I2C_BUS_ORDER = 1
return self.I2C_BUS_ORDER
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
order = self.update_i2c_order()
if port_num <= 24:
present_path = self.BASE_CPLD2_PATH.format(order)
else:
present_path = self.BASE_CPLD3_PATH.format(order)
present_path = present_path + "module_present_" + 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 qsfp_sb_remap(self, port_num):
qsfp_start = self.qsfp_port_start
qsfp_index = self._port_to_i2c_mapping[port_num][0] - qsfp_start
qsfp_index = self.qsfp_sb_map[qsfp_index-1]
return qsfp_start+qsfp_index
def get_low_power_mode_cpld(self, port_num):
if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
return False
order = self.update_i2c_order()
lp_mode_path = self.BASE_CPLD3_PATH.format(order)
lp_mode_path = lp_mode_path + "module_lp_mode_"
q = self.qsfp_sb_remap(port_num)
lp_mode_path = lp_mode_path + str(q)
try:
val_file = open(lp_mode_path)
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):
if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
return False
if not self.get_presence(port_num):
return self.get_low_power_mode_cpld(port_num)
try:
eeprom = None
eeprom = open(self.port_to_eeprom_mapping[port_num], "rb")
eeprom.seek(93)
lpmode = ord(eeprom.read(1))
if not (lpmode & 0x1): # 'Power override' bit is 0
return self.get_low_power_mode_cpld(port_num)
else:
if ((lpmode & 0x2) == 0x2):
return True # Low Power Mode if "Power set" bit is 1
else:
return False # High Power Mode if "Power set" bit is 0
except IOError as err:
print "Error: unable to open file: %s" % str(err)
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
def set_low_power_mode(self, port_num, lpmode):
if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
return False
try:
eeprom = None
if not self.get_presence(port_num):
return False # Port is not present, unable to set the eeprom
# Fill in write buffer
regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode
buffer = create_string_buffer(1)
buffer[0] = chr(regval)
# Write to eeprom
eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b")
eeprom.seek(93)
eeprom.write(buffer[0])
return True
except IOError as err:
print "Error: unable to open file: %s" % str(err)
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
def reset(self, port_num):
if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
return False
order = self.update_i2c_order()
lp_mode_path = self.BASE_CPLD3_PATH.format(order)
mod_rst_path = lp_mode_path + "module_reset_"
q = self.qsfp_sb_remap(port_num)
mod_rst_path = mod_rst_path + str(q)
try:
reg_file = open(mod_rst_path, 'r+')
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
#toggle reset
reg_file.seek(0)
reg_file.write('0')
time.sleep(1)
reg_file.seek(0)
reg_file.write('1')
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

View File

@ -24,6 +24,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(ACCTON_AS7726_32X_PLATFORM_MODULE) \
$(ACCTON_AS4630_54PE_PLATFORM_MODULE) \
$(ACCTON_MINIPACK_PLATFORM_MODULE) \
$(ACCTON_AS5812_54X_PLATFORM_MODULE) \
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7264Q28B_PLATFORM_MODULE) \

View File

@ -11,6 +11,7 @@ ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION = 1.1
ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1
export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION
@ -23,6 +24,7 @@ export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION
export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION
export ACCTON_AS5812_54X_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
@ -71,4 +73,8 @@ ACCTON_MINIPACK_PLATFORM_MODULE = sonic-platform-accton-minipack_$(ACCTON_MINIPA
$(ACCTON_MINIPACK_PLATFORM_MODULE)_PLATFORM = x86_64-accton_minipack-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_MINIPACK_PLATFORM_MODULE)))
ACCTON_AS5812_54X_PLATFORM_MODULE = sonic-platform-accton-as5812-54x_$(ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS5812_54X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5812_54x-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5812_54X_PLATFORM_MODULE)))
SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE)

View File

@ -37,6 +37,7 @@
#include <linux/stat.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#include <linux/printk.h>
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
@ -103,6 +104,8 @@ MODULE_DEVICE_TABLE(i2c, as5712_54x_cpld_mux_id);
#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_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index
#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index
enum as5712_54x_cpld1_sysfs_attributes {
CPLD_VERSION,
@ -308,6 +311,18 @@ enum as5712_54x_cpld1_sysfs_attributes {
TRANSCEIVER_TXFAULT_ATTR_ID(46),
TRANSCEIVER_TXFAULT_ATTR_ID(47),
TRANSCEIVER_TXFAULT_ATTR_ID(48),
TRANSCEIVER_LPMODE_ATTR_ID(49),
TRANSCEIVER_LPMODE_ATTR_ID(50),
TRANSCEIVER_LPMODE_ATTR_ID(51),
TRANSCEIVER_LPMODE_ATTR_ID(52),
TRANSCEIVER_LPMODE_ATTR_ID(53),
TRANSCEIVER_LPMODE_ATTR_ID(54),
TRANSCEIVER_RESET_ATTR_ID(49),
TRANSCEIVER_RESET_ATTR_ID(50),
TRANSCEIVER_RESET_ATTR_ID(51),
TRANSCEIVER_RESET_ATTR_ID(52),
TRANSCEIVER_RESET_ATTR_ID(53),
TRANSCEIVER_RESET_ATTR_ID(54),
};
/* sysfs attributes for hwmon
@ -320,6 +335,10 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t set_mode_reset(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,
@ -336,11 +355,21 @@ static int as5712_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8
static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \
static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \
static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index)
#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \
&sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \
&sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \
&sensor_dev_attr_module_tx_fault_##index.dev_attr.attr
#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO | S_IWUSR, show_status, set_lp_mode, MODULE_LPMODE_##index); \
static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR | S_IRUGO, show_status, set_mode_reset, MODULE_RESET_##index)
#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \
&sensor_dev_attr_module_lp_mode_##index.dev_attr.attr, \
&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 */
@ -449,6 +478,12 @@ DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(45);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53);
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54);
static struct attribute *as5712_54x_cpld1_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
@ -581,6 +616,12 @@ static struct attribute *as5712_54x_cpld3_attributes[] = {
DECLARE_SFP_TRANSCEIVER_ATTR(46),
DECLARE_SFP_TRANSCEIVER_ATTR(47),
DECLARE_SFP_TRANSCEIVER_ATTR(48),
DECLARE_QSFP_TRANSCEIVER_ATTR(49),
DECLARE_QSFP_TRANSCEIVER_ATTR(50),
DECLARE_QSFP_TRANSCEIVER_ATTR(51),
DECLARE_QSFP_TRANSCEIVER_ATTR(52),
DECLARE_QSFP_TRANSCEIVER_ATTR(53),
DECLARE_QSFP_TRANSCEIVER_ATTR(54),
NULL
};
@ -795,6 +836,14 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da,
reg = 0x11;
mask = 0x1 << (attr->index - MODULE_RXLOS_41);
break;
case MODULE_LPMODE_49 ... MODULE_LPMODE_54:
reg = 0x16;
mask = 0x1 << (attr->index - MODULE_LPMODE_49);
break;
case MODULE_RESET_49 ... MODULE_RESET_54:
reg = 0x15;
mask = 0x1 << (attr->index - MODULE_RESET_49);
break;
default:
return 0;
}
@ -890,6 +939,108 @@ exit:
return status;
}
static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
long on;
int status= -ENOENT;
u8 reg = 0x16, mask = 0;
if(attr->index < MODULE_LPMODE_49 || attr->index > MODULE_LPMODE_54)
return status;
status = kstrtol(buf, 10, &on);
if (status) {
return status;
}
/* Read current status */
mutex_lock(&data->update_lock);
status = as5712_54x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
mask = 0x1 << (attr->index - MODULE_LPMODE_49);
/* Update lp_mode status */
if (on) {
status |= mask;
}
else {
status &= ~mask;
}
status = as5712_54x_cpld_write_internal(client, reg, status);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
long on;
int status= -ENOENT;
u8 reg = 0x15, mask = 0;
if(attr->index < MODULE_RESET_49 || attr->index > MODULE_RESET_54)
return status;
status = kstrtol(buf, 10, &on);
if (status) {
return status;
}
/* Read current status */
mutex_lock(&data->update_lock);
status = as5712_54x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
mask = 0x1 << (attr->index - MODULE_RESET_49);
/* Update tx_disable status */
if (on) {
status |= mask;
}
else {
status &= ~mask;
}
status = as5712_54x_cpld_write_internal(client, reg, status);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
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)
{

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 Accton Technology Corporation
# Copyright (C) 2019 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
@ -19,7 +19,7 @@
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
#
# 05/08/2019: Roy Lee, changed for as5712-54x.
# ------------------------------------------------------------------
try:
@ -53,7 +53,6 @@ class accton_as5712_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."""
@ -77,9 +76,9 @@ class accton_as5712_monitor(object):
logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
def manage_fans(self):
FAN_LEV1_UP_TEMP = 57500 # temperature
FAN_LEV1_UP_TEMP = 57700 # temperature
FAN_LEV1_DOWN_TEMP = 0 # unused
FAN_LEV1_SPEED_PERC = 100 # percentage*/
FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/
FAN_LEV2_UP_TEMP = 53000
FAN_LEV2_DOWN_TEMP = 52700
@ -151,8 +150,9 @@ class accton_as5712_monitor(object):
self._new_perc = FAN_LEV1_SPEED_PERC
logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp)
if self._ori_perc == self._new_perc:
logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, self._ori_perc)
cur_perc = fan.get_fan_duty_cycle(fan.get_idx_fan_start())
if cur_perc == self._new_perc:
logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc)
return True
set_stat = fan.set_fan_duty_cycle(fan.get_idx_fan_start(), self._new_perc)
@ -161,10 +161,9 @@ class accton_as5712_monitor(object):
else:
logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc)
logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', self._ori_perc, self._ori_temp)
self._ori_perc = self._new_perc
logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp)
self._ori_temp = new_temp
logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', self._ori_perc, self._ori_temp)
logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp)
return True
@ -199,7 +198,7 @@ def main(argv):
# Loop forever, doing something useful hopefully:
while True:
monitor.manage_fans()
time.sleep(1)
time.sleep(10)
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,238 @@
#!/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 <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
#
# ------------------------------------------------------------------
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 = 6
FAN_NODE_FAULT_IDX_OF_MAP = 1
FAN_NODE_SPEED_IDX_OF_MAP = 2
FAN_NODE_DIR_IDX_OF_MAP = 3
FAN_NODE_DUTY_IDX_OF_MAP = 4
FANR_NODE_FAULT_IDX_OF_MAP = 5
FANR_NODE_SPEED_IDX_OF_MAP = 6
BASE_VAL_PATH = '/sys/devices/platform/as5812_54x_fan/{0}'
#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 = {}
_fan_to_device_node_mapping = {
(FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault',
(FAN_NUM_1_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan1_speed_rpm',
(FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction',
(FAN_NUM_1_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan1_duty_cycle_percentage',
(FAN_NUM_1_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr1_fault',
(FAN_NUM_1_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr1_speed_rpm',
(FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault',
(FAN_NUM_2_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan2_speed_rpm',
(FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction',
(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
(FAN_NUM_2_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr2_fault',
(FAN_NUM_2_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr2_speed_rpm',
(FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault',
(FAN_NUM_3_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan3_speed_rpm',
(FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction',
(FAN_NUM_3_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan3_duty_cycle_percentage',
(FAN_NUM_3_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr3_fault',
(FAN_NUM_3_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr3_speed_rpm',
(FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault',
(FAN_NUM_4_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan4_speed_rpm',
(FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction',
(FAN_NUM_4_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan4_duty_cycle_percentage',
(FAN_NUM_4_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr4_fault',
(FAN_NUM_4_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr4_speed_rpm',
(FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault',
(FAN_NUM_5_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan5_speed_rpm',
(FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction',
(FAN_NUM_5_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan5_duty_cycle_percentage',
(FAN_NUM_5_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr5_fault',
(FAN_NUM_5_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr5_speed_rpm',
}
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, fan_num):
return self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP)
def set_fan_duty_cycle(self, fan_num, val):
return self._set_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP, val)
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()

View File

@ -0,0 +1,121 @@
#!/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 <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
#
# ------------------------------------------------------------------
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: ['61', '48'],
THERMAL_NUM_2_IDX: ['62', '49'],
THERMAL_NUM_3_IDX: ['63', '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 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()

View File

@ -0,0 +1,17 @@
ifneq ($(KERNELRELEASE),)
obj-m:= i2c-mux-accton_as5812_54x_cpld.o \
accton_as5812_54x_fan.o leds-accton_as5812_54x.o accton_as5812_54x_psu.o \
cpr_4011_4mxx.o ym2651y.o
else
ifeq (,$(KERNEL_SRC))
$(error KERNEL_SRC is not defined)
else
KERNELDIR:=$(KERNEL_SRC)
endif
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order
endif

View File

@ -0,0 +1,457 @@
/*
* A hwmon driver for the Accton as5710 54x fan contrl
*
* Copyright (C) 2013 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* 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 <linux/module.h>
#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#define DRVNAME "as5812_54x_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 0x1F
#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 LOCAL_DEBUG 0
static struct accton_as5812_54x_fan *fan_data = NULL;
struct accton_as5812_54x_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_as5812_54x_fan_update_device(struct device *dev);
static int accton_as5812_54x_fan_read_value(u8 reg);
static int accton_as5812_54x_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 as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as5812_54x_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_as5812_54x_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_as5812_54x_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]);
if (LOCAL_DEBUG)
printk ("[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]);
if (LOCAL_DEBUG)
printk ("[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]);
if (LOCAL_DEBUG)
printk ("[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*/
if (LOCAL_DEBUG)
printk ("[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]);
if (LOCAL_DEBUG)
printk ("[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]);
if (LOCAL_DEBUG)
printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
default:
if (LOCAL_DEBUG)
printk ("[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_as5812_54x_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_as5812_54x_fan_group = {
.attrs = accton_as5812_54x_fan_attributes,
};
static int accton_as5812_54x_fan_read_value(u8 reg)
{
return as5812_54x_cpld_read(0x60, reg);
}
static int accton_as5812_54x_fan_write_value(u8 reg, u8 value)
{
return as5812_54x_cpld_write(0x60, reg, value);
}
static void accton_as5812_54x_fan_update_device(struct device *dev)
{
int speed, r_speed, fault, r_fault, ctrl_speed, direction;
int i;
mutex_lock(&fan_data->update_lock);
if (LOCAL_DEBUG)
printk ("Starting accton_as5812_54x_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;
if (LOCAL_DEBUG)
printk ("Starting accton_as5812_54x_fan update 2 \n");
fault = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_STATUS_OFFSET);
r_fault = accton_as5812_54x_fan_read_value(CPLD_REG_FANR_STATUS_OFFSET);
direction = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_DIRECTION_OFFSET);
ctrl_speed = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET);
if ( (fault < 0) || (r_fault < 0) || (direction < 0) || (ctrl_speed < 0) )
{
if (LOCAL_DEBUG)
printk ("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
goto _exit; /* error */
}
if (LOCAL_DEBUG)
printk ("[fan:] fault:%d, r_fault=%d, direction=%d, ctrl_speed=%d \n",fault, r_fault, direction, 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;
if (LOCAL_DEBUG)
printk ("[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 = accton_as5812_54x_fan_read_value(fan_speed_reg[i]);
r_speed = accton_as5812_54x_fan_read_value(fanr_speed_reg[i]);
if ( (speed < 0) || (r_speed < 0) )
{
if (LOCAL_DEBUG)
printk ("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
goto _exit; /* error */
}
if (LOCAL_DEBUG)
printk ("[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_as5812_54x_fan_probe(struct platform_device *pdev)
{
int status = -1;
/* Register sysfs hooks */
status = sysfs_create_group(&pdev->dev.kobj, &accton_as5812_54x_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_as5812_54x_fan\n");
return 0;
exit_remove:
sysfs_remove_group(&pdev->dev.kobj, &accton_as5812_54x_fan_group);
exit:
return status;
}
static int accton_as5812_54x_fan_remove(struct platform_device *pdev)
{
hwmon_device_unregister(fan_data->hwmon_dev);
sysfs_remove_group(&fan_data->pdev->dev.kobj, &accton_as5812_54x_fan_group);
return 0;
}
static struct platform_driver accton_as5812_54x_fan_driver = {
.probe = accton_as5812_54x_fan_probe,
.remove = accton_as5812_54x_fan_remove,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init accton_as5812_54x_fan_init(void)
{
int ret;
ret = platform_driver_register(&accton_as5812_54x_fan_driver);
if (ret < 0) {
goto exit;
}
fan_data = kzalloc(sizeof(struct accton_as5812_54x_fan), GFP_KERNEL);
if (!fan_data) {
ret = -ENOMEM;
platform_driver_unregister(&accton_as5812_54x_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_as5812_54x_fan_driver);
kfree(fan_data);
goto exit;
}
exit:
return ret;
}
static void __exit accton_as5812_54x_fan_exit(void)
{
platform_device_unregister(fan_data->pdev);
platform_driver_unregister(&accton_as5812_54x_fan_driver);
kfree(fan_data);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as5812_54x_fan driver");
MODULE_LICENSE("GPL");
module_init(accton_as5812_54x_fan_init);
module_exit(accton_as5812_54x_fan_exit);

View File

@ -0,0 +1,371 @@
/*
* An hwmon driver for accton as5812_54x Power Module
*
* Copyright (C) 2015 Accton Technology Corporation.
* Copyright (C) Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, 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 <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#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 as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg);
static int as5812_54x_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 as5812_54x_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 as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev);
enum as5812_54x_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 *as5812_54x_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 as5812_54x_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 as5812_54x_psu_data *data = as5812_54x_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 as5812_54x_psu_data *data = as5812_54x_psu_update_device(dev);
if (!data->valid) {
return 0;
}
if (!IS_PRESENT(data->index, data->status)) {
return 0;
}
if (as5812_54x_psu_model_name_get(dev) < 0) {
return -ENXIO;
}
return sprintf(buf, "%s\n", data->model_name);
}
static const struct attribute_group as5812_54x_psu_group = {
.attrs = as5812_54x_psu_attributes,
};
static int as5812_54x_psu_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as5812_54x_psu_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as5812_54x_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, &as5812_54x_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, &as5812_54x_psu_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as5812_54x_psu_remove(struct i2c_client *client)
{
struct as5812_54x_psu_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as5812_54x_psu_group);
kfree(data);
return 0;
}
enum psu_index
{
as5812_54x_psu1,
as5812_54x_psu2
};
static const struct i2c_device_id as5812_54x_psu_id[] = {
{ "as5812_54x_psu1", as5812_54x_psu1 },
{ "as5812_54x_psu2", as5812_54x_psu2 },
{}
};
MODULE_DEVICE_TABLE(i2c, as5812_54x_psu_id);
static struct i2c_driver as5812_54x_psu_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as5812_54x_psu",
},
.probe = as5812_54x_psu_probe,
.remove = as5812_54x_psu_remove,
.id_table = as5812_54x_psu_id,
.address_list = normal_i2c,
};
static int as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(result < 0))
goto abort;
if (unlikely(result != data_len)) {
result = -EIO;
goto abort;
}
result = 0;
abort:
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 as5812_54x_psu_model_name_get(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_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 = as5812_54x_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 as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_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 as5812_54x update\n");
data->valid = 0;
/* Read psu status */
status = as5812_54x_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;
}
static int __init as5812_54x_psu_init(void)
{
return i2c_add_driver(&as5812_54x_psu_driver);
}
static void __exit as5812_54x_psu_exit(void)
{
i2c_del_driver(&as5812_54x_psu_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton as5812_54x_psu driver");
MODULE_LICENSE("GPL");
module_init(as5812_54x_psu_init);
module_exit(as5812_54x_psu_exit);

View File

@ -0,0 +1,825 @@
/*
* An hwmon driver for accton as5812_54x sfp
*
* Copyright (C) Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, 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 <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#define NUM_OF_SFF_PORT 54
#define SFP_PORT_MAX 48
#define I2C_ADDR_CPLD1 0x60
#define I2C_ADDR_CPLD2 0x61
#define I2C_ADDR_CPLD3 0x62
#define CPLD3_OFFSET_QSFP_MOD_RST 0x15
#define CPLD3_OFFSET_QSFP_LPMODE 0x16
#define BIT_INDEX(i) (1ULL << (i))
#if 0
static ssize_t show_status(struct device *dev, struct device_attribute *da,char *buf);
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, char *buf);
static int as5812_54x_sfp_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as5812_54x_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as5812_54x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#endif
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
/* Each client has this additional data
*/
struct as5812_54x_sfp_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
int port; /* Front port index */
char eeprom[256]; /* eeprom data */
u64 status[4]; /* bit0:port0, bit1:port1 and so on */
/* index 0 => is_present
1 => tx_fail
2 => tx_disable
3 => rx_loss */
};
/* The table maps active port to cpld port.
* Array index 0 is for active port 1,
* index 1 for active port 2, and so on.
* The array content implies cpld port index.
*/
static const u8 cpld_to_front_port_table[] =
{ 1, 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, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 52, 50, 53, 51, 54};
#define CPLD_PORT_TO_FRONT_PORT(port) (cpld_to_front_port_table[port])
static struct as5812_54x_sfp_data *as5812_54x_sfp_update_device(struct device *dev, int update_eeprom);
static ssize_t show_port_number(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_eeprom(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t get_lp_mode(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
extern int as5812_54x_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as5812_54x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
enum as5812_54x_sfp_sysfs_attributes {
SFP_IS_PRESENT,
SFP_TX_FAULT,
SFP_TX_DISABLE,
SFP_RX_LOSS,
SFP_PORT_NUMBER,
SFP_EEPROM,
SFP_RX_LOS_ALL,
SFP_IS_PRESENT_ALL,
SFP_LP_MODE,
SFP_MOD_RST,
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_status, NULL, SFP_IS_PRESENT);
static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, show_status, NULL, SFP_TX_FAULT);
static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, show_status, set_tx_disable, SFP_TX_DISABLE);
static SENSOR_DEVICE_ATTR(sfp_rx_loss, S_IRUGO, show_status,NULL, SFP_RX_LOSS);
static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, SFP_PORT_NUMBER);
static SENSOR_DEVICE_ATTR(sfp_eeprom, S_IRUGO, show_eeprom, NULL, SFP_EEPROM);
static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, show_status,NULL, SFP_RX_LOS_ALL);
static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_status,NULL, SFP_IS_PRESENT_ALL);
static SENSOR_DEVICE_ATTR(sfp_lp_mode, S_IWUSR | S_IRUGO, get_lp_mode, set_lp_mode, SFP_LP_MODE);
static SENSOR_DEVICE_ATTR(sfp_mod_rst, S_IWUSR | S_IRUGO, get_mode_reset, set_mode_reset, SFP_MOD_RST);
static struct attribute *as5812_54x_sfp_attributes[] = {
&sensor_dev_attr_sfp_is_present.dev_attr.attr,
&sensor_dev_attr_sfp_tx_fault.dev_attr.attr,
&sensor_dev_attr_sfp_rx_loss.dev_attr.attr,
&sensor_dev_attr_sfp_tx_disable.dev_attr.attr,
&sensor_dev_attr_sfp_eeprom.dev_attr.attr,
&sensor_dev_attr_sfp_port_number.dev_attr.attr,
&sensor_dev_attr_sfp_rx_los_all.dev_attr.attr,
&sensor_dev_attr_sfp_is_present_all.dev_attr.attr,
&sensor_dev_attr_sfp_lp_mode.dev_attr.attr,
&sensor_dev_attr_sfp_mod_rst.dev_attr.attr,
NULL
};
static ssize_t show_port_number(struct device *dev, struct device_attribute *da,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port));
}
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 as5812_54x_sfp_data *data;
u8 val;
int values[7];
/* Error-check the CPLD read results. */
#define VALIDATED_READ(_buf, _rv, _read_expr, _invert) \
do { \
_rv = (_read_expr); \
if(_rv < 0) { \
return sprintf(_buf, "READ ERROR\n"); \
} \
if(_invert) { \
_rv = ~_rv; \
} \
_rv &= 0xFF; \
} while(0)
if(attr->index == SFP_RX_LOS_ALL) {
/*
* Report the RX_LOS status for all ports.
* This does not depend on the currently active SFP selector.
*/
/* RX_LOS Ports 1-8 */
VALIDATED_READ(buf, values[0], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x0F), 0);
/* RX_LOS Ports 9-16 */
VALIDATED_READ(buf, values[1], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x10), 0);
/* RX_LOS Ports 17-24 */
VALIDATED_READ(buf, values[2], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x11), 0);
/* RX_LOS Ports 25-32 */
VALIDATED_READ(buf, values[3], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x0F), 0);
/* RX_LOS Ports 33-40 */
VALIDATED_READ(buf, values[4], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x10), 0);
/* RX_LOS Ports 41-48 */
VALIDATED_READ(buf, values[5], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x11), 0);
/** Return values 1 -> 48 in order */
return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x\n",
values[0], values[1], values[2],
values[3], values[4], values[5]);
}
if(attr->index == SFP_IS_PRESENT_ALL) {
/*
* Report the SFP_PRESENCE status for all ports.
* This does not depend on the currently active SFP selector.
*/
/* SFP_PRESENT Ports 1-8 */
VALIDATED_READ(buf, values[0], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x6), 1);
/* SFP_PRESENT Ports 9-16 */
VALIDATED_READ(buf, values[1], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x7), 1);
/* SFP_PRESENT Ports 17-24 */
VALIDATED_READ(buf, values[2], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x8), 1);
/* SFP_PRESENT Ports 25-32 */
VALIDATED_READ(buf, values[3], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x6), 1);
/* SFP_PRESENT Ports 33-40 */
VALIDATED_READ(buf, values[4], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x7), 1);
/* SFP_PRESENT Ports 41-48 */
VALIDATED_READ(buf, values[5], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x8), 1);
/* QSFP_PRESENT Ports 49-54 */
VALIDATED_READ(buf, values[6], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14), 1);
/* Return values 1 -> 54 in order */
return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
values[0], values[1], values[2],
values[3], values[4], values[5],
values[6] & 0x3F);
}
/*
* The remaining attributes are gathered on a per-selected-sfp basis.
*/
data = as5812_54x_sfp_update_device(dev, 0);
if (attr->index == SFP_IS_PRESENT) {
val = (data->status[attr->index] & BIT_INDEX(data->port)) ? 0 : 1;
}
else {
val = (data->status[attr->index] & BIT_INDEX(data->port)) ? 1 : 0;
}
return sprintf(buf, "%d", val);
}
static ssize_t get_lp_mode(struct device *dev, struct device_attribute *da,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
u8 cpld_val = 0;
int port_bit;
int status = -EINVAL;
/* Low power mode is not supported for SFP ports(1-48) */
if (data->port < SFP_PORT_MAX) {
return -EINVAL;
}
mutex_lock(&data->update_lock);
port_bit = data->port - SFP_PORT_MAX;
cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE);
cpld_val = cpld_val & 0x3F;
cpld_val = cpld_val & BIT_INDEX(port_bit);
status = snprintf(buf, PAGE_SIZE - 1, "%d\r\n", cpld_val>>port_bit);
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
u8 cpld_val = 0;
long mode;
int error, port_bit;
/* Tx disable is not supported for QSFP ports(49-54) */
if (data->port < SFP_PORT_MAX) {
return -EINVAL;
}
port_bit = data->port - SFP_PORT_MAX;
error = kstrtol(buf, 10, &mode);
if (error) {
return error;
}
mutex_lock(&data->update_lock);
cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE);
/* Update lp_mode status */
if (mode)
{
cpld_val |= BIT_INDEX(port_bit);
}
else
{
cpld_val &=~BIT_INDEX(port_bit);
}
as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE, cpld_val);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
u8 cpld_val = 0;
int port_bit;
int status = -EINVAL;
/* Low power mode is not supported for SFP ports(1-48) */
if (data->port < SFP_PORT_MAX) {
return -EINVAL;
}
mutex_lock(&data->update_lock);
port_bit = data->port - SFP_PORT_MAX;
cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST);
cpld_val = cpld_val & 0x3F;
cpld_val = cpld_val & BIT_INDEX(port_bit);
status = snprintf(buf, PAGE_SIZE - 1, "%d\r\n", cpld_val>>port_bit);
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
u8 cpld_val = 0;
long reset;
int error, port_bit;
/* Tx disable is not supported for QSFP ports(49-54) */
if (data->port < SFP_PORT_MAX) {
return -EINVAL;
}
port_bit = data->port - SFP_PORT_MAX;
error = kstrtol(buf, 10, &reset);
if (error) {
return error;
}
mutex_lock(&data->update_lock);
cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST);
/* Update lp_mode status */
if (reset)
{
cpld_val |= BIT_INDEX(port_bit);
}
else
{
cpld_val &=~BIT_INDEX(port_bit);
}
as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST, cpld_val);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
unsigned short cpld_addr = 0;
u8 cpld_reg = 0, cpld_val = 0, cpld_bit = 0;
long disable;
int error;
/* Tx disable is not supported for QSFP ports(49-54) */
if (data->port >= SFP_PORT_MAX) {
return -EINVAL;
}
error = kstrtol(buf, 10, &disable);
if (error) {
return error;
}
mutex_lock(&data->update_lock);
if(data->port < 24) {
cpld_addr = I2C_ADDR_CPLD2;
cpld_reg = 0xC + data->port / 8;
cpld_bit = 1 << (data->port % 8);
}
else {
cpld_addr = I2C_ADDR_CPLD3;
cpld_reg = 0xC + (data->port - 24) / 8;
cpld_bit = 1 << (data->port % 8);
}
cpld_val = as5812_54x_i2c_cpld_read(cpld_addr, cpld_reg);
/* Update tx_disable status */
if (disable) {
data->status[SFP_TX_DISABLE] |= BIT_INDEX(data->port);
cpld_val |= cpld_bit;
}
else {
data->status[SFP_TX_DISABLE] &= ~BIT_INDEX(data->port);
cpld_val &= ~cpld_bit;
}
as5812_54x_i2c_cpld_write(cpld_addr, cpld_reg, cpld_val);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t show_eeprom(struct device *dev, struct device_attribute *da,
char *buf)
{
struct as5812_54x_sfp_data *data = as5812_54x_sfp_update_device(dev, 1);
if (!data->valid) {
return 0;
}
if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) != 0) {
return 0;
}
memcpy(buf, data->eeprom, sizeof(data->eeprom));
return sizeof(data->eeprom);
}
static const struct attribute_group as5812_54x_sfp_group = {
.attrs = as5812_54x_sfp_attributes,
};
static int as5812_54x_sfp_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as5812_54x_sfp_data *data;
int status;
extern int platform_accton_as5812_54x(void);
if(!platform_accton_as5812_54x()) {
return -ENODEV;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as5812_54x_sfp_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
mutex_init(&data->update_lock);
data->port = dev_id->driver_data;
i2c_set_clientdata(client, data);
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &as5812_54x_sfp_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: sfp '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &as5812_54x_sfp_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as5812_54x_sfp_remove(struct i2c_client *client)
{
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as5812_54x_sfp_group);
kfree(data);
return 0;
}
enum port_numbers {
as5812_54x_sfp1, as5812_54x_sfp2, as5812_54x_sfp3, as5812_54x_sfp4,
as5812_54x_sfp5, as5812_54x_sfp6, as5812_54x_sfp7, as5812_54x_sfp8,
as5812_54x_sfp9, as5812_54x_sfp10, as5812_54x_sfp11,as5812_54x_sfp12,
as5812_54x_sfp13, as5812_54x_sfp14, as5812_54x_sfp15,as5812_54x_sfp16,
as5812_54x_sfp17, as5812_54x_sfp18, as5812_54x_sfp19,as5812_54x_sfp20,
as5812_54x_sfp21, as5812_54x_sfp22, as5812_54x_sfp23,as5812_54x_sfp24,
as5812_54x_sfp25, as5812_54x_sfp26, as5812_54x_sfp27,as5812_54x_sfp28,
as5812_54x_sfp29, as5812_54x_sfp30, as5812_54x_sfp31,as5812_54x_sfp32,
as5812_54x_sfp33, as5812_54x_sfp34, as5812_54x_sfp35,as5812_54x_sfp36,
as5812_54x_sfp37, as5812_54x_sfp38, as5812_54x_sfp39,as5812_54x_sfp40,
as5812_54x_sfp41, as5812_54x_sfp42, as5812_54x_sfp43,as5812_54x_sfp44,
as5812_54x_sfp45, as5812_54x_sfp46, as5812_54x_sfp47,as5812_54x_sfp48,
as5812_54x_sfp49, as5812_54x_sfp52, as5812_54x_sfp50,as5812_54x_sfp53,
as5812_54x_sfp51, as5812_54x_sfp54
};
static const struct i2c_device_id as5812_54x_sfp_id[] = {
{ "as5812_54x_sfp1", as5812_54x_sfp1 }, { "as5812_54x_sfp2", as5812_54x_sfp2 },
{ "as5812_54x_sfp3", as5812_54x_sfp3 }, { "as5812_54x_sfp4", as5812_54x_sfp4 },
{ "as5812_54x_sfp5", as5812_54x_sfp5 }, { "as5812_54x_sfp6", as5812_54x_sfp6 },
{ "as5812_54x_sfp7", as5812_54x_sfp7 }, { "as5812_54x_sfp8", as5812_54x_sfp8 },
{ "as5812_54x_sfp9", as5812_54x_sfp9 }, { "as5812_54x_sfp10", as5812_54x_sfp10 },
{ "as5812_54x_sfp11", as5812_54x_sfp11 }, { "as5812_54x_sfp12", as5812_54x_sfp12 },
{ "as5812_54x_sfp13", as5812_54x_sfp13 }, { "as5812_54x_sfp14", as5812_54x_sfp14 },
{ "as5812_54x_sfp15", as5812_54x_sfp15 }, { "as5812_54x_sfp16", as5812_54x_sfp16 },
{ "as5812_54x_sfp17", as5812_54x_sfp17 }, { "as5812_54x_sfp18", as5812_54x_sfp18 },
{ "as5812_54x_sfp19", as5812_54x_sfp19 }, { "as5812_54x_sfp20", as5812_54x_sfp20 },
{ "as5812_54x_sfp21", as5812_54x_sfp21 }, { "as5812_54x_sfp22", as5812_54x_sfp22 },
{ "as5812_54x_sfp23", as5812_54x_sfp23 }, { "as5812_54x_sfp24", as5812_54x_sfp24 },
{ "as5812_54x_sfp25", as5812_54x_sfp25 }, { "as5812_54x_sfp26", as5812_54x_sfp26 },
{ "as5812_54x_sfp27", as5812_54x_sfp27 }, { "as5812_54x_sfp28", as5812_54x_sfp28 },
{ "as5812_54x_sfp29", as5812_54x_sfp29 }, { "as5812_54x_sfp30", as5812_54x_sfp30 },
{ "as5812_54x_sfp31", as5812_54x_sfp31 }, { "as5812_54x_sfp32", as5812_54x_sfp32 },
{ "as5812_54x_sfp33", as5812_54x_sfp33 }, { "as5812_54x_sfp34", as5812_54x_sfp34 },
{ "as5812_54x_sfp35", as5812_54x_sfp35 }, { "as5812_54x_sfp36", as5812_54x_sfp36 },
{ "as5812_54x_sfp37", as5812_54x_sfp37 }, { "as5812_54x_sfp38", as5812_54x_sfp38 },
{ "as5812_54x_sfp39", as5812_54x_sfp39 }, { "as5812_54x_sfp40", as5812_54x_sfp40 },
{ "as5812_54x_sfp41", as5812_54x_sfp41 }, { "as5812_54x_sfp42", as5812_54x_sfp42 },
{ "as5812_54x_sfp43", as5812_54x_sfp43 }, { "as5812_54x_sfp44", as5812_54x_sfp44 },
{ "as5812_54x_sfp45", as5812_54x_sfp45 }, { "as5812_54x_sfp46", as5812_54x_sfp46 },
{ "as5812_54x_sfp47", as5812_54x_sfp47 }, { "as5812_54x_sfp48", as5812_54x_sfp48 },
{ "as5812_54x_sfp49", as5812_54x_sfp49 }, { "as5812_54x_sfp50", as5812_54x_sfp50 },
{ "as5812_54x_sfp51", as5812_54x_sfp51 }, { "as5812_54x_sfp52", as5812_54x_sfp52 },
{ "as5812_54x_sfp53", as5812_54x_sfp53 }, { "as5812_54x_sfp54", as5812_54x_sfp54 },
{}
};
MODULE_DEVICE_TABLE(i2c, as5812_54x_sfp_id);
static struct i2c_driver as5812_54x_sfp_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as5812_54x_sfp",
},
.probe = as5812_54x_sfp_probe,
.remove = as5812_54x_sfp_remove,
.id_table = as5812_54x_sfp_id,
.address_list = normal_i2c,
};
static int as5812_54x_sfp_read_byte(struct i2c_client *client, u8 command, u8 *data)
{
int result = i2c_smbus_read_byte_data(client, command);
if (unlikely(result < 0)) {
dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, result);
goto abort;
}
*data = (u8)result;
result = 0;
abort:
return result;
}
#define ALWAYS_UPDATE_DEVICE 1
static struct as5812_54x_sfp_data *as5812_54x_sfp_update_device(struct device *dev, int update_eeprom)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (ALWAYS_UPDATE_DEVICE || time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int status = -1;
int i = 0, j = 0;
data->valid = 0;
//dev_dbg(&client->dev, "Starting as5812_54x sfp status update\n");
memset(data->status, 0, sizeof(data->status));
/* Read status of port 1~48(SFP port) */
for (i = 0; i < 2; i++) {
for (j = 0; j < 12; j++) {
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
goto exit;
}
data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8);
}
}
/*
* Bring QSFPs out of reset,
* This is a temporary fix until the QSFP+_MOD_RST register
* can be exposed through the driver.
*/
as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, 0x15, 0x3F);
/* Read present status of port 49-54(QSFP port) */
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
}
else {
data->status[SFP_IS_PRESENT] |= (u64)status << 48;
}
if (update_eeprom) {
/* Read eeprom data based on port number */
memset(data->eeprom, 0, sizeof(data->eeprom));
/* Check if the port is present */
if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) == 0) {
/* read eeprom */
for (i = 0; i < sizeof(data->eeprom); i++) {
status = as5812_54x_sfp_read_byte(client, i, data->eeprom + i);
if (status < 0) {
dev_dbg(&client->dev, "unable to read eeprom from port(%d)\n",
CPLD_PORT_TO_FRONT_PORT(data->port));
goto exit;
}
}
}
}
data->valid = 1;
data->last_updated = jiffies;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
module_i2c_driver(as5812_54x_sfp_driver);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton as5812_54x_sfp driver");
MODULE_LICENSE("GPL");
#if 0
int i = 0, j = 0;
data->valid = 0;
//dev_dbg(&client->dev, "Starting as5812_54x sfp update\n");
memset(data->status, 0, sizeof(data->status));
/* Read status of port 1~48(SFP port) */
for (i = 0; i < 2; i++) {
for (j = 0; j < 12; j++) {
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
continue;
}
data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8);
}
}
/* Read present status of port 49-54(QSFP port) */
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
}
else {
data->status[SFP_IS_PRESENT] |= (u64)status << 48;
}
#endif
/* Reserver to prevent from CPLD port mapping is changed
*/
#if 0
BIT_INDEX(port_present_index[data->port])
/* The bit index of is_present field read from CPLD
* Array index 0 is for as5812_54x_sfp1,
* index 1 is for as5812_54x_sfp2, and so on.
*/
static const int port_present_index[] = {
4, 5, 6, 7, 9, 8, 11, 10,
0, 1, 2, 3, 12, 13, 14, 15,
16, 17, 18, 19, 28, 29, 30, 31,
20, 21, 22, 23, 24, 25, 26, 27
};
#endif
#if 0
static struct as5812_54x_sfp_data *as5812_54x_sfp_update_status(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as5812_54x_sfp_data *data = i2c_get_clientdata(client);
int status = -1;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->status_last_updated + HZ + HZ / 2)
|| !data->status_valid) {
int status = -1;
int i = 0, j = 0;
data->status_valid = 0;
//dev_dbg(&client->dev, "Starting as5812_54x sfp status update\n");
memset(data->status, 0, sizeof(data->status));
/* Read status of port 1~48(SFP port) */
for (i = 0; i < 2; i++) {
for (j = 0; j < 12; j++) {
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
goto exit;
}
data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8);
}
}
/*
* Bring QSFPs out of reset,
* This is a temporary fix until the QSFP+_MOD_RST register
* can be exposed through the driver.
*/
as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, 0x15, 0x3F);
/* Read present status of port 49-54(QSFP port) */
status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14);
if (status < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status);
}
else {
data->status[SFP_IS_PRESENT] |= (u64)status << 48;
}
data->status_valid = 1;
data->status_last_updated = jiffies;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
static struct as5812_54x_sfp_data *as5812_54x_sfp_update_eeprom(struct device *dev)
{
struct as5812_54x_sfp_data *data = NULL;
data = as5812_54x_sfp_update_status(dev);
if (data == NULL || data->status_valid == 0) {
data->eeprom_valid = 0;
return data;
}
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->eeprom_last_updated + HZ + HZ / 2)
|| !data->eeprom_valid) {
int status = -1;
int i = 0;
/* Read eeprom data based on port number */
memset(data->eeprom, 0, sizeof(data->eeprom));
/* Check if the port is present */
if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) == 0) {
/* read eeprom */
for (i = 0; i < sizeof(data->eeprom)/I2C_SMBUS_BLOCK_MAX; i++) {
status = as5812_54x_sfp_read_block(client, i*I2C_SMBUS_BLOCK_MAX,
data->eeprom+(i*I2C_SMBUS_BLOCK_MAX),
I2C_SMBUS_BLOCK_MAX);
if (status < 0) {
dev_dbg(&client->dev, "unable to read eeprom from port(%d)\n",
CPLD_PORT_TO_FRONT_PORT(data->port));
goto exit;
}
}
}
data->eeprom_last_updated = jiffies;
data->eeprom_valid = 1;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
#endif

View File

@ -0,0 +1,400 @@
/*
* An hwmon driver for the CPR-4011-4Mxx Redundant Power Module
*
* Copyright (C) Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, 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 <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#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_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);
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,
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:
value = data->p_in;
break;
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[] = { {0x88, &data->v_in},
{0x8b, &data->v_out},
{0x89, &data->i_in},
{0x8c, &data->i_out},
{0x96, &data->p_out},
{0x97, &data->p_in},
{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);
}
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);
}
else {
*(regs_word[i].value) = status;
}
}
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 <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("CPR_4011_4MXX driver");
MODULE_LICENSE("GPL");
module_init(cpr_4011_4mxx_init);
module_exit(cpr_4011_4mxx_exit);

View File

@ -0,0 +1,594 @@
/*
* A LED driver for the accton_as5812_54x_led
*
* Copyright (C) 2013 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/leds.h>
#include <linux/slab.h>
extern int as5812_54x_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as5812_54x_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 "as5812_54x_led"
struct accton_as5812_54x_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_as5812_54x_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_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 0x0C
#define LED_TYPE_FAN3_REG_MASK 0x30
#define LED_TYPE_FAN4_REG_MASK 0xC0
#define LED_TYPE_FAN5_REG_MASK 0x03
#define LED_TYPE_FAN6_REG_MASK 0x0C
#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 */
0x16, /* FAN1-4 LED */
0x17, /* FAN4-6 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;
};
static 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 << 2},
{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 2},
{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 2},
{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 << 6},
{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 6},
{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 6},
{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_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, 2},
{'2', LED_TYPE_FAN2, 2},
{'3', LED_TYPE_FAN3, 2},
{'4', LED_TYPE_FAN4, 2},
{'5', LED_TYPE_FAN5, 3}
};
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 ((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;
reg_val = led_type_mode_data[i].mode_mask |
(reg_val & (~led_type_mode_data[i].type_mask));
}
return reg_val;
}
static int accton_as5812_54x_led_read_value(u8 reg)
{
return as5812_54x_cpld_read(0x60, reg);
}
static int accton_as5812_54x_led_write_value(u8 reg, u8 value)
{
return as5812_54x_cpld_write(0x60, reg, value);
}
static void accton_as5812_54x_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_as5812_54x_led update\n");
/* Update LED data
*/
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
int status = accton_as5812_54x_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_as5812_54x_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_as5812_54x_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_as5812_54x_led_write_value(reg, reg_val);
/* to prevent the slow-update issue */
ledctl->valid = 0;
exit:
mutex_unlock(&ledctl->update_lock);
}
static void accton_as5812_54x_led_psu_1_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1);
}
static enum led_brightness accton_as5812_54x_led_psu_1_get(struct led_classdev *cdev)
{
accton_as5812_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]);
}
static void accton_as5812_54x_led_psu_2_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2);
}
static enum led_brightness accton_as5812_54x_led_psu_2_get(struct led_classdev *cdev)
{
accton_as5812_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
}
static void accton_as5812_54x_led_fan_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN);
}
static enum led_brightness accton_as5812_54x_led_fan_get(struct led_classdev *cdev)
{
accton_as5812_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
}
static void accton_as5812_54x_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;i<ncount;i++)
{
nsize=strlen(led_cdev->name);
if (led_cdev->name[nsize-1] == fanx_info[i].cname)
{
led_type1 = fanx_info[i].type;
reg_id = fanx_info[i].reg_id;
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1);
return;
}
}
}
static enum led_brightness accton_as5812_54x_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;i<ncount;i++)
{
nsize=strlen(cdev->name);
if (cdev->name[nsize-1] == fanx_info[i].cname)
{
led_type1 = fanx_info[i].type;
reg_id = fanx_info[i].reg_id;
accton_as5812_54x_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_as5812_54x_led_diag_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG);
}
static enum led_brightness accton_as5812_54x_led_diag_get(struct led_classdev *cdev)
{
accton_as5812_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
}
static void accton_as5812_54x_led_loc_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC);
}
static enum led_brightness accton_as5812_54x_led_loc_get(struct led_classdev *cdev)
{
accton_as5812_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]);
}
static struct led_classdev accton_as5812_54x_leds[] = {
[LED_TYPE_PSU1] = {
.name = "accton_as5812_54x_led::psu1",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_psu_1_set,
.brightness_get = accton_as5812_54x_led_psu_1_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU2] = {
.name = "accton_as5812_54x_led::psu2",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_psu_2_set,
.brightness_get = accton_as5812_54x_led_psu_2_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN] = {
.name = "accton_as5812_54x_led::fan",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fan_set,
.brightness_get = accton_as5812_54x_led_fan_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN1] = {
.name = "accton_as5812_54x_led::fan1",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fanx_set,
.brightness_get = accton_as5812_54x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN2] = {
.name = "accton_as5812_54x_led::fan2",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fanx_set,
.brightness_get = accton_as5812_54x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN3] = {
.name = "accton_as5812_54x_led::fan3",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fanx_set,
.brightness_get = accton_as5812_54x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN4] = {
.name = "accton_as5812_54x_led::fan4",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fanx_set,
.brightness_get = accton_as5812_54x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN5] = {
.name = "accton_as5812_54x_led::fan5",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_fanx_set,
.brightness_get = accton_as5812_54x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_DIAG] = {
.name = "accton_as5812_54x_led::diag",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_diag_set,
.brightness_get = accton_as5812_54x_led_diag_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_LOC] = {
.name = "accton_as5812_54x_led::loc",
.default_trigger = "unused",
.brightness_set = accton_as5812_54x_led_loc_set,
.brightness_get = accton_as5812_54x_led_loc_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
};
static int accton_as5812_54x_led_suspend(struct platform_device *dev,
pm_message_t state)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) {
led_classdev_suspend(&accton_as5812_54x_leds[i]);
}
return 0;
}
static int accton_as5812_54x_led_resume(struct platform_device *dev)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) {
led_classdev_resume(&accton_as5812_54x_leds[i]);
}
return 0;
}
static int accton_as5812_54x_led_probe(struct platform_device *pdev)
{
int ret, i;
for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) {
ret = led_classdev_register(&pdev->dev, &accton_as5812_54x_leds[i]);
if (ret < 0)
break;
}
/* Check if all LEDs were successfully registered */
if (i != ARRAY_SIZE(accton_as5812_54x_leds)){
int j;
/* only unregister the LEDs that were successfully registered */
for (j = 0; j < i; j++) {
led_classdev_unregister(&accton_as5812_54x_leds[i]);
}
}
return ret;
}
static int accton_as5812_54x_led_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) {
led_classdev_unregister(&accton_as5812_54x_leds[i]);
}
return 0;
}
static struct platform_driver accton_as5812_54x_led_driver = {
.probe = accton_as5812_54x_led_probe,
.remove = accton_as5812_54x_led_remove,
.suspend = accton_as5812_54x_led_suspend,
.resume = accton_as5812_54x_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init accton_as5812_54x_led_init(void)
{
int ret;
ret = platform_driver_register(&accton_as5812_54x_led_driver);
if (ret < 0) {
goto exit;
}
ledctl = kzalloc(sizeof(struct accton_as5812_54x_led_data), GFP_KERNEL);
if (!ledctl) {
ret = -ENOMEM;
platform_driver_unregister(&accton_as5812_54x_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_as5812_54x_led_driver);
kfree(ledctl);
goto exit;
}
exit:
return ret;
}
static void __exit accton_as5812_54x_led_exit(void)
{
platform_device_unregister(ledctl->pdev);
platform_driver_unregister(&accton_as5812_54x_led_driver);
kfree(ledctl);
}
module_init(accton_as5812_54x_led_init);
module_exit(accton_as5812_54x_led_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as5812_54x_led driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,683 @@
/*
* An hwmon driver for the 3Y Power YM-2651Y Power Module
*
* Copyright (C) 2014 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, 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 <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#define MAX_FAN_DUTY_CYCLE 100
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
enum chips {
YM2651,
YM2401,
};
/* Each client has this additional data
*/
struct ym2651y_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 chip; /* chip id */
u8 capability; /* Register value */
u16 status_word; /* Register value */
u8 fan_fault; /* Register value */
u8 over_temp; /* Register value */
u16 v_out; /* Register value */
u16 i_out; /* Register value */
u16 p_out; /* Register value */
u8 vout_mode; /* Register value */
u16 temp; /* Register value */
u16 fan_speed; /* Register value */
u16 fan_duty_cycle[2]; /* Register value */
u8 fan_dir[5]; /* Register value */
u8 pmbus_revision; /* Register value */
u8 mfr_id[10]; /* Register value */
u8 mfr_model[16]; /* Register value */
u8 mfr_revsion[3]; /* Register value */
u16 mfr_vin_min; /* Register value */
u16 mfr_vin_max; /* Register value */
u16 mfr_iin_max; /* Register value */
u16 mfr_iout_max; /* Register value */
u16 mfr_pin_max; /* Register value */
u16 mfr_pout_max; /* Register value */
u16 mfr_vout_min; /* Register value */
u16 mfr_vout_max; /* Register value */
};
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_word(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_linear(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 show_fan_fault(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
char *buf);
static struct ym2651y_data *ym2651y_update_device(struct device *dev);
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value);
enum ym2651y_sysfs_attributes {
PSU_POWER_ON = 0,
PSU_TEMP_FAULT,
PSU_POWER_GOOD,
PSU_FAN1_FAULT,
PSU_FAN_DIRECTION,
PSU_OVER_TEMP,
PSU_V_OUT,
PSU_I_OUT,
PSU_P_OUT,
PSU_TEMP1_INPUT,
PSU_FAN1_SPEED,
PSU_FAN1_DUTY_CYCLE,
PSU_PMBUS_REVISION,
PSU_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
PSU_MFR_VIN_MIN,
PSU_MFR_VIN_MAX,
PSU_MFR_VOUT_MIN,
PSU_MFR_VOUT_MAX,
PSU_MFR_IIN_MAX,
PSU_MFR_IOUT_MAX,
PSU_MFR_PIN_MAX,
PSU_MFR_POUT_MAX
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON);
static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD);
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP);
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
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_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
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_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
static SENSOR_DEVICE_ATTR(psu_pmbus_revision,S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX);
static struct attribute *ym2651y_attributes[] = {
&sensor_dev_attr_psu_power_on.dev_attr.attr,
&sensor_dev_attr_psu_temp_fault.dev_attr.attr,
&sensor_dev_attr_psu_power_good.dev_attr.attr,
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
&sensor_dev_attr_psu_over_temp.dev_attr.attr,
&sensor_dev_attr_psu_v_out.dev_attr.attr,
&sensor_dev_attr_psu_i_out.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_speed_rpm.dev_attr.attr,
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr,
NULL
};
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
if (!data->valid) {
return 0;
}
return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) :
sprintf(buf, "0\n");
}
static ssize_t show_word(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u16 status = 0;
if (!data->valid) {
return 0;
}
switch (attr->index) {
case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */
status = (data->status_word & 0x40) ? 0 : 1;
break;
case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */
status = (data->status_word & 0x4) >> 2;
break;
case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */
status = (data->status_word & 0x800) ? 0 : 1;
break;
}
return sprintf(buf, "%d\n", status);
}
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 ym2651y_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;
ym2651y_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 ym2651y_data *data = ym2651y_update_device(dev);
u16 value = 0;
int exponent, mantissa;
int multiplier = 1000;
if (!data->valid) {
return 0;
}
switch (attr->index) {
case PSU_V_OUT:
value = data->v_out;
break;
case PSU_I_OUT:
value = data->i_out;
break;
case PSU_P_OUT:
value = data->p_out;
break;
case PSU_TEMP1_INPUT:
value = data->temp;
break;
case PSU_FAN1_SPEED:
value = data->fan_speed;
multiplier = 1;
break;
case PSU_FAN1_DUTY_CYCLE:
value = data->fan_duty_cycle[0];
multiplier = 1;
break;
case PSU_MFR_VIN_MIN:
value = data->mfr_vin_min;
break;
case PSU_MFR_VIN_MAX:
value = data->mfr_vin_max;
break;
case PSU_MFR_VOUT_MIN:
value = data->mfr_vout_min;
break;
case PSU_MFR_VOUT_MAX:
value = data->mfr_vout_max;
break;
case PSU_MFR_PIN_MAX:
value = data->mfr_pin_max;
break;
case PSU_MFR_POUT_MAX:
value = data->mfr_pout_max;
break;
case PSU_MFR_IOUT_MAX:
value = data->mfr_iout_max;
break;
case PSU_MFR_IIN_MAX:
value = data->mfr_iin_max;
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 ym2651y_data *data = ym2651y_update_device(dev);
u8 shift;
if (!data->valid) {
return 0;
}
shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
return sprintf(buf, "%d\n", data->fan_fault >> shift);
}
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
char *buf)
{
struct ym2651y_data *data = ym2651y_update_device(dev);
if (!data->valid) {
return 0;
}
return sprintf(buf, "%d\n", data->over_temp >> 7);
}
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u8 *ptr = NULL;
if (!data->valid) {
return 0;
}
switch (attr->index) {
case PSU_FAN_DIRECTION: /* psu_fan_dir */
ptr = data->fan_dir + 1; /* Skip the first byte since it is the length of string. */
break;
case PSU_MFR_ID: /* psu_mfr_id */
ptr = data->mfr_id + 1; /* The first byte is the count byte of string. */;
break;
case PSU_MFR_MODEL: /* psu_mfr_model */
ptr = data->mfr_model + 1; /* The first byte is the count byte of string. */
break;
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion + 1; /* The first byte is the count byte of string. */
break;
default:
return 0;
}
return sprintf(buf, "%s\n", ptr);
}
static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da,
char *buf)
{
struct ym2651y_data *data = ym2651y_update_device(dev);
int exponent, mantissa;
int multiplier = 1000;
if (!data->valid) {
return 0;
}
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 ssize_t show_vout(struct device *dev, struct device_attribute *da,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ym2651y_data *data = i2c_get_clientdata(client);
if (data->chip == YM2401) {
return show_vout_by_mode(dev, da, buf);
}
return show_linear(dev, da, buf);
}
static const struct attribute_group ym2651y_group = {
.attrs = ym2651y_attributes,
};
static int ym2651y_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct ym2651y_data *data;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->chip = dev_id->driver_data;
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &ym2651y_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, &ym2651y_group);
exit_free:
kfree(data);
exit:
return status;
}
static int ym2651y_remove(struct i2c_client *client)
{
struct ym2651y_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
kfree(data);
return 0;
}
static const struct i2c_device_id ym2651y_id[] = {
{ "ym2651", YM2651 },
{ "ym2401", YM2401 },
{}
};
MODULE_DEVICE_TABLE(i2c, ym2651y_id);
static struct i2c_driver ym2651y_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "ym2651",
},
.probe = ym2651y_probe,
.remove = ym2651y_remove,
.id_table = ym2651y_id,
.address_list = normal_i2c,
};
static int ym2651y_read_byte(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int ym2651y_read_word(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_word_data(client, reg);
}
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value)
{
return i2c_smbus_write_word_data(client, reg, value);
}
static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(result < 0))
goto abort;
if (unlikely(result != data_len)) {
result = -EIO;
goto abort;
}
result = 0;
abort:
return result;
}
struct reg_data_byte {
u8 reg;
u8 *value;
};
struct reg_data_word {
u8 reg;
u16 *value;
};
static struct ym2651y_data *ym2651y_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ym2651y_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, length;
u8 command, buf;
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
{0x20, &data->vout_mode},
{0x7d, &data->over_temp},
{0x81, &data->fan_fault},
{0x98, &data->pmbus_revision}};
struct reg_data_word regs_word[] = { {0x79, &data->status_word},
{0x8b, &data->v_out},
{0x8c, &data->i_out},
{0x96, &data->p_out},
{0x8d, &data->temp},
{0x3b, &(data->fan_duty_cycle[0])},
{0x3c, &(data->fan_duty_cycle[1])},
{0x90, &data->fan_speed},
{0xa0, &data->mfr_vin_min},
{0xa1, &data->mfr_vin_max},
{0xa2, &data->mfr_iin_max},
{0xa3, &data->mfr_pin_max},
{0xa4, &data->mfr_vout_min},
{0xa5, &data->mfr_vout_max},
{0xa6, &data->mfr_iout_max},
{0xa7, &data->mfr_pout_max}};
dev_dbg(&client->dev, "Starting ym2651 update\n");
data->valid = 0;
/* Read byte data */
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
status = ym2651y_read_byte(client, regs_byte[i].reg);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_byte[i].reg, status);
goto exit;
}
else {
*(regs_byte[i].value) = status;
}
}
/* Read word data */
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
status = ym2651y_read_word(client, regs_word[i].reg);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_word[i].reg, status);
goto exit;
}
else {
*(regs_word[i].value) = status;
}
}
/* Read fan_direction */
command = 0xC3;
status = ym2651y_read_block(client, command, data->fan_dir,
ARRAY_SIZE(data->fan_dir)-1);
data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
/* Read mfr_id */
command = 0x99;
status = ym2651y_read_block(client, command, data->mfr_id,
ARRAY_SIZE(data->mfr_id)-1);
data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
/* Read mfr_model */
command = 0x9a;
length = 1;
/* Read first byte to determine the length of data */
status = ym2651y_read_block(client, command, &buf, length);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
status = ym2651y_read_block(client, command, data->mfr_model, buf+1);
data->mfr_model[buf+1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
/* Read mfr_revsion */
command = 0x9b;
status = ym2651y_read_block(client, command, data->mfr_revsion,
ARRAY_SIZE(data->mfr_revsion)-1);
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
data->last_updated = jiffies;
data->valid = 1;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
static int __init ym2651y_init(void)
{
return i2c_add_driver(&ym2651y_driver);
}
static void __exit ym2651y_exit(void)
{
i2c_del_driver(&ym2651y_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("3Y Power YM-2651Y driver");
MODULE_LICENSE("GPL");
module_init(ym2651y_init);
module_exit(ym2651y_exit);

View File

@ -0,0 +1,17 @@
[Unit]
Description=Accton AS5812-54X Platform Monitoring service
Before=pmon.service
After=sysinit.target
DefaultDependencies=no
[Service]
Type=oneshot
ExecStartPre=/usr/local/bin/accton_as5812_util.py install
ExecStart=/usr/local/bin/accton_as5812_monitor.py
RemainAfterExit=yes
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python
import os
import sys
from setuptools import setup
os.listdir
setup(
name='as5812_54x',
version='1.0',
description='Module to initialize Accton AS5812-54X platforms',
packages=['as5812_54x'],
package_dir={'as5812_54x': 'as5812-54x/classes'},
)

View File

@ -0,0 +1,117 @@
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 <http://www.gnu.org/licenses/>.
Contents of this package:
patch - files under patch/ is for kernel and ONIE installer
for the kernel:
config-accton-as5812_54x.patch
for kernel configuration.
driver-i2c-muxes-pca954x-always-deselect.patch
for i2c_mux deselects after transaction.
driver-patches-for-accton-as5812-fan-psu-cpld.patch
for as5812's fan/psu/cpld/led/sfp drivers.
for ONIE:
onie_installer-accton-AS5812-54X.patch
for console port setting and copy util script o rootfs.
module - Contains source code of as5812 kernel driver modules.
The late Sonic building scripts, pushed @Dec 5 2016, will automatically
create a docker container and run building process under it.
User is not necessary to handle docker environment creation.
1. Download sonic-buildimage environment.
- Run "git clone https://github.com/Azure/sonic-buildimage".
- cd to sonic-buildimage and run "git submodule update --init --recursive".
2. Build kernel
- cd ./src/sonic-linux-kernel
- Copy patches and series from patch/kernel of this release to
sonic-linux-kernel/patch.
- Build kernel by "make".
- The built kernel package, linux-image-3.16.0-5-amd64_3.16.51-3+deb8u1_amd64.deb
, is generated.
3. Build installer
- Change directory back to sonic-buildimage/.
- Get onie_installer-accton-AS5812-54X.patch" from patch/installer.
- Change setting for AS5812-54X by patching build_image.sh.
"patch -p1 < onie_installer-accton-AS5812-54X.patch"
!!NOTICE, patching onie_installer-accton-AS5812-54X.patch comments out the
"git status" checking at build_image.sh.
- The account and password of installed OS can be given at rules/config.
The default user and password are "admin" & "YourPaSsWoRd" respectively.
- Run "make configure PLATFORM=broadcom"
- Copy the built kernel debian package to target/debs/.
The file is linux-image-3.16.0-5-amd64_*_amd64.deb under directory
src/sonic-linux-kernel/.
- Run "make target/sonic-generic.bin"
- Get the installer, target/sonic-generic.bin, to target machine and install.
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 AS5812-54X has 2 parts,
kernel drivers and operational script.
The kernel drivers of peripherals are under module/ directory.
1. These drivers are patched into kernel by
driver-patches-for-accton-as5812-fan-psu-cpld.patch
Or you can build the driver under module/ by setting environment variable,
KERNEL_SRC, to proper linux built directory and run make.
It may be sonic-linux-kernel/linux-3.*/debian/build/build_amd64_none_amd64/.
2. A operational script, accton_as5812_util.py, for device initializatian and
peripheral accessing should be installed at /usr/bin.
This script is generated by onie_installer-accton-AS5812-54X.patch.
It's done by patching onie_installer-accton-AS5812-54X.patch at build-image.
Run "accton_as5812_util.py install" to install drivers.
To initialize the system, run "accton_as5812_util.py install".
To clean up the drivers & devices, run "accton_as5812_util.py clean".
To dump information of sensors, run "accton_as5812_util.py show".
To dump SFP EEPROM, run "accton_as5812_util.py sff".
To set fan speed, run "accton_as5812_util.py set fan".
To enable/disable SFP emission, run "accton_as5812_util.py set sfp".
To set system LEDs' color, run "accton_as5812_util.py set led"
For more information, run "accton_as5812_util.py --help".
====================================================================
Besides applying accton_as5812_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 48 SFP+ and 6 QSFP modules are equipped.
Before operating on PSU and QSFP+, please make sure it is well plugged.
Otherwise, operation is going to fail.

View File

@ -0,0 +1,204 @@
#!/usr/bin/env python
#
# Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
# 05/08/2019: Roy Lee, changed for as5812-54x.
# ------------------------------------------------------------------
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
import signal
from tabulate import tabulate
from as5812_54x.fanutil import FanUtil
from as5812_54x.thermalutil import ThermalUtil
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
# Deafults
VERSION = '1.0'
FUNCTION_NAME = 'accton_as5812_monitor'
DUTY_MAX = 100
global log_file
global log_level
# Make a class we can use to capture stdout and sterr in the log
class accton_as5812_monitor(object):
# static temp var
_ori_temp = 0
_new_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):
FAN_LEV1_UP_TEMP = 57700 # temperature
FAN_LEV1_DOWN_TEMP = 0 # unused
FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/
FAN_LEV2_UP_TEMP = 53000
FAN_LEV2_DOWN_TEMP = 52700
FAN_LEV2_SPEED_PERC = 80
FAN_LEV3_UP_TEMP = 49500
FAN_LEV3_DOWN_TEMP = 47700
FAN_LEV3_SPEED_PERC = 65
FAN_LEV4_UP_TEMP = 0 # unused
FAN_LEV4_DOWN_TEMP = 42700
FAN_LEV4_SPEED_PERC = 40
thermal = ThermalUtil()
fan = FanUtil()
temp1 = thermal.get_thermal_1_val()
if temp1 is None:
return False
temp2 = thermal.get_thermal_2_val()
if temp2 is None:
return False
new_temp = (temp1 + temp2) / 2
for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
fan_stat = fan.get_fan_status(x)
if fan_stat is None:
return False
if fan_stat is False:
self._new_perc = FAN_LEV1_SPEED_PERC
logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', self._new_perc, x)
break
logging.debug('INFO. fan_stat is True (fan_num:%d)', x)
if fan_stat is not None and fan_stat is not False:
diff = new_temp - self._ori_temp
if diff == 0:
logging.debug('INFO. RETURN. THERMAL temp not changed. %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp)
return True
else:
if diff >= 0:
is_up = True
logging.debug('INFO. THERMAL temp UP %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp)
else:
is_up = False
logging.debug('INFO. THERMAL temp DOWN %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp)
if is_up is True:
if new_temp >= FAN_LEV1_UP_TEMP:
self._new_perc = FAN_LEV1_SPEED_PERC
elif new_temp >= FAN_LEV2_UP_TEMP:
self._new_perc = FAN_LEV2_SPEED_PERC
elif new_temp >= FAN_LEV3_UP_TEMP:
self._new_perc = FAN_LEV3_SPEED_PERC
else:
self._new_perc = FAN_LEV4_SPEED_PERC
logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp)
else:
if new_temp <= FAN_LEV4_DOWN_TEMP:
self._new_perc = FAN_LEV4_SPEED_PERC
elif new_temp <= FAN_LEV3_DOWN_TEMP:
self._new_perc = FAN_LEV3_SPEED_PERC
elif new_temp <= FAN_LEV2_DOWN_TEMP:
self._new_perc = FAN_LEV2_SPEED_PERC
else:
self._new_perc = FAN_LEV1_SPEED_PERC
logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp)
cur_perc = fan.get_fan_duty_cycle(fan.get_idx_fan_start())
if cur_perc == self._new_perc:
logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc)
return True
set_stat = fan.set_fan_duty_cycle(fan.get_idx_fan_start(), self._new_perc)
if set_stat is True:
logging.debug('INFO: PASS. set_fan_duty_cycle (%d)', self._new_perc)
else:
logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc)
logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp)
self._ori_temp = new_temp
logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp)
return True
def handler(signum, frame):
fan = FanUtil()
logging.debug('INFO:Cause signal %d, set fan speed max.', signum)
fan.set_fan_duty_cycle(fan.get_idx_fan_start(), DUTY_MAX)
sys.exit(0)
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 <log_file>]' % sys.argv[0]
return 0
for opt, arg in opts:
if opt == '-h':
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
elif opt in ('-d', '--debug'):
log_level = logging.DEBUG
elif opt in ('-l', '--lfile'):
log_file = arg
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
monitor = accton_as5812_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:])

View File

@ -0,0 +1,686 @@
#!/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 <http://www.gnu.org/licenses/>.
"""
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
import pickle
from collections import namedtuple
PROJECT_NAME = 'as5812_54x'
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':3, 'psu':2, 'sfp':54}
led_prefix ='/sys/devices/platform/as5812_54x_led/leds/accton_'+PROJECT_NAME+'_led::'
fan_prefix ='/sys/devices/platform/as5812_54x_'
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': ['61-0048','62-0049', '63-004a'] ,
'psu': ['57-0050','58-0053'],
'sfp': ['-0050']}
i2c_nodes = {
'thermal': ['hwmon/hwmon*/temp1_input'] ,
'psu': ['psu_present ', 'psu_power_good'] ,
'sfp': ['sfp_is_present ', 'sfp_tx_disable']}
QSFP_START = 48
I2C_BUS_ORDER = -1
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, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 52, 54, 51, 53, 55]
port_cpld_path = [ "/sys/bus/i2c/devices/0-0061/"
,'/sys/bus/i2c/devices/0-0062/']
mknod =[
'echo as5812_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo as5812_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo as5812_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device',
# PSU-1
'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device',
'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device',
'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device',
# PSU-2
'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device',
'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device',
'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-63/new_device',
#EERPOM
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device',
]
mknod2 =[
'echo as5812_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo as5812_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo as5812_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-0/new_device',
# PSU-1
'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device',
'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device',
'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device',
# PSU-2
'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device',
'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device',
'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-63/new_device',
#EERPOM
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device',
]
FORCE = 0
logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG)
logging.basicConfig(level=logging.INFO)
if DEBUG == True:
print sys.argv[0]
print 'ARGV :', sys.argv[1:]
def main():
global DEBUG
global args
global FORCE
if len(sys.argv)<2:
show_help()
options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
'debug',
'force',
])
if DEBUG == True:
print options
print args
print len(sys.argv)
for opt, arg in options:
if opt in ('-h', '--help'):
show_help()
elif opt in ('-d', '--debug'):
DEBUG = True
logging.basicConfig(level=logging.INFO)
elif opt in ('-f', '--force'):
FORCE = 1
else:
logging.info('no option')
for arg in args:
if arg == 'install':
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-48 {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 i2c-mux-accton_as5812_54x_cpld',
'modprobe cpr_4011_4mxx',
'modprobe ym2651y',
'modprobe accton_as5812_54x_fan',
'modprobe leds-accton_as5812_54x',
'modprobe accton_as5812_54x_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 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 update_i2c_order():
global I2C_BUS_ORDER
order = i2c_order_check()
pickle.dump(order, open("/tmp/accton_util.p", "wb")) # save it
I2C_BUS_ORDER = order
print "[%s]Detected I2C_BUS_ORDER:%d" % (os.path.basename(__file__), I2C_BUS_ORDER)
def get_i2c_order():
global I2C_BUS_ORDER
if I2C_BUS_ORDER < 0:
if os.path.exists("/tmp/accton_util.p"):
I2C_BUS_ORDER = pickle.load(open("/tmp/accton_util.p", "rb"))
else:
update_i2c_order()
def device_install():
global FORCE
global I2C_BUS_ORDER
update_i2c_order()
order = I2C_BUS_ORDER
# if 0x76 is not exist @i2c-0, use reversed bus order
if order:
for i in range(0,len(mknod2)):
#for pca954x 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 pca954x 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)):
if i < QSFP_START:
status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
else:
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
global I2C_BUS_ORDER
get_i2c_order()
order = I2C_BUS_ORDER
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 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)] = []
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]):
node = key+str(k+1)
path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j]
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 get_cpld_path(index):
global I2C_BUS_ORDER
if I2C_BUS_ORDER < 0:
get_i2c_order()
if I2C_BUS_ORDER !=0 :
return port_cpld_path[index].replace("0-", "1-")
else:
return port_cpld_path[index]
def cpld_path_of_port(port_index):
if port_index < 1 and port_index > DEVICE_NO['sfp']:
return None
if port_index < 25:
return get_cpld_path(0)
else:
return get_cpld_path(1)
def get_path_sfp_tx_dis(port_index):
cpld_p = cpld_path_of_port(port_index)
if cpld_p == None:
return False, ''
else:
dev = cpld_p+"module_tx_disable_"+str(port_index)
return True, dev
def get_path_sfp_presence(port_index):
cpld_p = cpld_path_of_port(port_index)
if cpld_p == None:
return False, ''
else:
dev = cpld_p+"module_present_"+str(port_index)
return True, dev
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:
#There no tx_disable for QSFP port
if int(args[1]) > QSFP_START 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
port_index = int(args[1])
ret, dev = get_path_sfp_tx_dis(port_index)
if ret == False:
return False
else:
ret, log = log_os_system("echo "+args[2]+" >"+ dev, 1)
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 print_1_device_traversal(i, j, k):
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:
return func+"="+log+" "
else:
return func+"="+"X"+" "
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+":",
if i == 'sfp':
port_index = int(filter(str.isdigit, j))
for k in (ALL_DEVICE[i][j]):
if k.find('tx_disable')!= -1:
ret, k = get_path_sfp_tx_dis(port_index)
if ret == False:
continue
log = print_1_device_traversal(i, j, k)
print log,
if k.find('present')!= -1:
ret, k = get_path_sfp_presence(port_index)
if ret == False:
continue
log = print_1_device_traversal(i, j, k)
print log,
else:
for k in (ALL_DEVICE[i][j]):
log = print_1_device_traversal(i, j, k)
print log,
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()

View File

@ -49,3 +49,6 @@ Package: sonic-platform-accton-minipack
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp
Package: sonic-platform-accton-as5812-54x
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -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 as6712-32x as7726-32x as4630-54pe minipack
MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service