[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:
parent
df149cd1fc
commit
4d212debc7
73
device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/port_config.ini
Executable file
73
device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/port_config.ini
Executable 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
|
1
device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/sai.profile
Executable file
1
device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/sai.profile
Executable file
@ -0,0 +1 @@
|
||||
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as5812-72x10G.config.bcm
|
@ -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
|
1
device/accton/x86_64-accton_as5812_54x-r0/default_sku
Normal file
1
device/accton/x86_64-accton_as5812_54x-r0/default_sku
Normal file
@ -0,0 +1 @@
|
||||
Accton-AS5812-54X t1
|
3
device/accton/x86_64-accton_as5812_54x-r0/installer.conf
Normal file
3
device/accton/x86_64-accton_as5812_54x-r0/installer.conf
Normal file
@ -0,0 +1,3 @@
|
||||
CONSOLE_PORT=0x2f8
|
||||
CONSOLE_DEV=1
|
||||
CONSOLE_SPEED=115200
|
162
device/accton/x86_64-accton_as5812_54x-r0/led_proc_init.soc
Normal file
162
device/accton/x86_64-accton_as5812_54x-r0/led_proc_init.soc
Normal 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
|
24
device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py
Normal file
24
device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py
Normal 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)
|
61
device/accton/x86_64-accton_as5812_54x-r0/plugins/psuutil.py
Executable file
61
device/accton/x86_64-accton_as5812_54x-r0/plugins/psuutil.py
Executable 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
|
311
device/accton/x86_64-accton_as5812_54x-r0/plugins/sfputil.py
Executable file
311
device/accton/x86_64-accton_as5812_54x-r0/plugins/sfputil.py
Executable 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
|
||||
|
@ -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) \
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
@ -78,16 +79,16 @@ struct chip_desc {
|
||||
/* Provide specs for the PCA954x types we know about */
|
||||
static const struct chip_desc chips[] = {
|
||||
[as5712_54x_cpld1] = {
|
||||
.nchans = NUM_OF_CPLD1_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
.nchans = NUM_OF_CPLD1_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
},
|
||||
[as5712_54x_cpld2] = {
|
||||
.nchans = NUM_OF_CPLD2_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
.nchans = NUM_OF_CPLD2_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
},
|
||||
[as5712_54x_cpld3] = {
|
||||
.nchans = NUM_OF_CPLD3_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
.nchans = NUM_OF_CPLD3_CHANS,
|
||||
.deselectChan = CPLD_DESELECT_CHANNEL,
|
||||
}
|
||||
};
|
||||
|
||||
@ -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,22 +311,38 @@ 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
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
char *buf);
|
||||
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
char *buf);
|
||||
static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
char *buf);
|
||||
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
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);
|
||||
const char *buf, size_t count);
|
||||
static ssize_t show_version(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
char *buf);
|
||||
static int as5712_54x_cpld_read_internal(struct i2c_client *client, u8 reg);
|
||||
static int as5712_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
@ -589,7 +630,7 @@ static const struct attribute_group as5712_54x_cpld3_group = {
|
||||
};
|
||||
|
||||
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
char *buf)
|
||||
{
|
||||
int i, status, num_regs = 0;
|
||||
u8 values[4] = {0};
|
||||
@ -604,7 +645,7 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
status = as5712_54x_cpld_read_internal(client, regs[i]);
|
||||
|
||||
|
||||
if (status < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@ -617,12 +658,12 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
/* Return values 1 -> 54 in order */
|
||||
if (data->type == as5712_54x_cpld2) {
|
||||
status = sprintf(buf, "%.2x %.2x %.2x\n",
|
||||
values[0], values[1], values[2]);
|
||||
values[0], values[1], values[2]);
|
||||
}
|
||||
else { /* as5712_54x_cpld3 */
|
||||
values[3] &= 0x3F;
|
||||
status = sprintf(buf, "%.2x %.2x %.2x %.2x\n",
|
||||
values[0], values[1], values[2], values[3]);
|
||||
values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -633,7 +674,7 @@ exit:
|
||||
}
|
||||
|
||||
static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
char *buf)
|
||||
{
|
||||
int i, status;
|
||||
u8 values[3] = {0};
|
||||
@ -646,7 +687,7 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
status = as5712_54x_cpld_read_internal(client, regs[i]);
|
||||
|
||||
|
||||
if (status < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@ -665,7 +706,7 @@ exit:
|
||||
}
|
||||
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@ -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;
|
||||
}
|
||||
@ -818,7 +867,7 @@ exit:
|
||||
}
|
||||
|
||||
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@ -881,7 +930,7 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
|
||||
@ -890,8 +939,110 @@ 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)
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
@ -923,7 +1074,7 @@ exit:
|
||||
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
|
||||
for this as they will try to lock adapter a second time */
|
||||
static int as5712_54x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
struct i2c_client *client, u8 val)
|
||||
struct i2c_client *client, u8 val)
|
||||
{
|
||||
unsigned long orig_jiffies;
|
||||
unsigned short flags;
|
||||
@ -939,22 +1090,22 @@ static int as5712_54x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
/* Retry automatically on arbitration loss */
|
||||
orig_jiffies = jiffies;
|
||||
for (res = 0, try = 0; try <= adap->retries; try++) {
|
||||
res = adap->algo->smbus_xfer(adap, client->addr, flags,
|
||||
I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (res != -EAGAIN)
|
||||
break;
|
||||
if (time_after(jiffies,
|
||||
orig_jiffies + adap->timeout))
|
||||
break;
|
||||
}
|
||||
res = adap->algo->smbus_xfer(adap, client->addr, flags,
|
||||
I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
if (res != -EAGAIN)
|
||||
break;
|
||||
if (time_after(jiffies,
|
||||
orig_jiffies + adap->timeout))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
{
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
@ -972,7 +1123,7 @@ static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
}
|
||||
|
||||
static int as5712_54x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
u32 chan)
|
||||
{
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
@ -1028,13 +1179,13 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c
|
||||
{
|
||||
int val = 0;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, 0x1);
|
||||
|
||||
if (val < 0) {
|
||||
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
|
||||
}
|
||||
|
||||
|
||||
return sprintf(buf, "%d", val);
|
||||
}
|
||||
|
||||
@ -1042,7 +1193,7 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c
|
||||
* I2C init/probing/exit functions
|
||||
*/
|
||||
static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int num, force, class;
|
||||
@ -1055,8 +1206,8 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
return -ENODEV;
|
||||
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
chips[id->driver_data].nchans, sizeof(*data), 0,
|
||||
as5712_54x_cpld_mux_select_chan, as5712_54x_cpld_mux_deselect_mux);
|
||||
chips[id->driver_data].nchans, sizeof(*data), 0,
|
||||
as5712_54x_cpld_mux_select_chan, as5712_54x_cpld_mux_deselect_mux);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1076,8 +1227,8 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
goto add_mux_failed;
|
||||
}
|
||||
}
|
||||
@ -1099,7 +1250,7 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (group) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
@ -1109,12 +1260,12 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
|
||||
if (chips[data->type].nchans) {
|
||||
dev_info(&client->dev,
|
||||
"registered %d multiplexed busses for I2C %s\n",
|
||||
num, client->name);
|
||||
"registered %d multiplexed busses for I2C %s\n",
|
||||
num, client->name);
|
||||
}
|
||||
else {
|
||||
dev_info(&client->dev,
|
||||
"device %s registered\n", client->name);
|
||||
"device %s registered\n", client->name);
|
||||
}
|
||||
|
||||
as5712_54x_cpld_add_client(client);
|
||||
|
@ -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:])
|
||||
|
238
platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py
Executable file
238
platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py
Executable 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()
|
@ -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()
|
17
platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/Makefile
Executable file
17
platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/Makefile
Executable 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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
683
platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c
Executable file
683
platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c
Executable 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);
|
||||
|
@ -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
|
16
platform/broadcom/sonic-platform-modules-accton/as5812-54x/setup.py
Executable file
16
platform/broadcom/sonic-platform-modules-accton/as5812-54x/setup.py
Executable 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'},
|
||||
)
|
||||
|
117
platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/README
Executable file
117
platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/README
Executable 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.
|
||||
|
@ -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:])
|
@ -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()
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user