[platform]Accton, add platform as6712-32x. (#2178)

* [platform] Add 6712 dpkg on building.
Signed-off-by: roy_lee <roy_lee@accton.com>

* [platform] remove scache_filename for it failed the bcm checker.
Signed-off-by: roy_lee <roy_lee@accton.com>

* [plaform] add platform/device as6712-32x.
Signed-off-by: roy_lee <roy_lee@accton.com>

* [platform] fix error on private data reference at cpld.c.
Signed-off-by: roy_lee <roy_lee@accton.com>
This commit is contained in:
Roy Lee 2018-10-27 08:10:47 +08:00 committed by lguohan
parent 483bd9bbd8
commit 7f76d3bf74
29 changed files with 4695 additions and 1 deletions

View File

@ -0,0 +1,33 @@
# name lanes alias
Ethernet0 49,50,51,52 fortyGigE1
Ethernet4 53,54,55,56 fortyGigE2
Ethernet8 57,58,59,60 fortyGigE3
Ethernet12 61,62,63,64 fortyGigE4
Ethernet16 65,66,67,68 fortyGigE5
Ethernet20 69,70,71,72 fortyGigE6
Ethernet24 73,74,75,76 fortyGigE7
Ethernet28 77,78,79,80 fortyGigE8
Ethernet32 33,34,35,36 fortyGigE9
Ethernet36 37,38,39,40 fortyGigE10
Ethernet40 41,42,43,44 fortyGigE11
Ethernet44 45,46,47,48 fortyGigE12
Ethernet48 81,82,83,84 fortyGigE13
Ethernet52 85,86,87,88 fortyGigE14
Ethernet56 89,90,91,92 fortyGigE15
Ethernet60 93,94,95,96 fortyGigE16
Ethernet64 97,98,99,100 fortyGigE17
Ethernet68 101,102,103,104 fortyGigE18
Ethernet72 105,106,107,108 fortyGigE19
Ethernet76 109,110,111,112 fortyGigE20
Ethernet80 17,18,19,20 fortyGigE21
Ethernet84 21,22,23,24 fortyGigE22
Ethernet88 25,26,27,28 fortyGigE23
Ethernet92 29,30,31,32 fortyGigE24
Ethernet96 113,114,115,116 fortyGigE25
Ethernet100 117,118,119,120 fortyGigE26
Ethernet104 121,122,123,124 fortyGigE27
Ethernet108 125,126,127,128 fortyGigE28
Ethernet112 1,2,3,4 fortyGigE29
Ethernet116 5,6,7,8 fortyGigE30
Ethernet120 9,10,11,12 fortyGigE31
Ethernet124 13,14,15,16 fortyGigE32

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as6712-32x40G.config.bcm

View File

@ -0,0 +1,132 @@
os=unix
bcm_stat_flags=0
parity_enable=0
parity_correction=0
l2_mem_entries=163840
l3_mem_entries=81920
mmu_lossless=0
lls_num_l2uc=12
module_64ports=0
#SFI
serdes_if_type=9
port_init_cl72=0
phy_an_c73=5 # TSCMOD_CL73_CL37
#sdk6.5.5 only supports 156(default) or 125
#xgxs_lcpll_xtal_refclk=1
tslam_dma_enable=1
table_dma_enable=1
#for 32x40G ports for breakout mode
pbmp_oversubscribe=0x1fffffffe
pbmp_xport_xe=0x1fffffffe
rate_ext_mdio_divisor=96
#QSFP+ 1 from WC0
portmap_1=1:40
#QSFP+ 2 from WC1
portmap_2=5:40
#QSFP+ 3 from WC2
portmap_3=9:40
#QSFP+ 4 from WC3
portmap_4=13:40
#QSFP+ 5 from WC4
portmap_5=17:40
#QSFP+ 6 from WC5
portmap_6=21:40
#QSFP+ 7 from WC6
portmap_7=25:40
#QSFP+ 8 from WC7
portmap_8=29:40
#QSFP+ 9 from WC8
portmap_9=33:40
#QSFP+ 10 from WC9
portmap_10=37:40
#QSFP+ 11 from WC10
portmap_11=41:40
#QSFP+ 12 from WC11
portmap_12=45:40
#QSFP+ 13 from WC12
portmap_13=49:40
#QSFP+ 14 from WC13
portmap_14=53:40
#QSFP+ 15 from WC14
portmap_15=57:40
#QSFP+ 16 from WC15
portmap_16=61:40
#QSFP+ 17 from WC16
portmap_17=65:40
#QSFP+ 18 from WC17
portmap_18=69:40
#QSFP+ 19 from WC18
portmap_19=73:40
#QSFP+ 20 from WC19
portmap_20=77:40
#QSFP+ 21 from WC20
portmap_21=81:40
#QSFP+ 22 from WC21
portmap_22=85:40
#QSFP+ 23 from WC22
portmap_23=89:40
#QSFP+ 24 from WC23
portmap_24=93:40
#QSFP+ 25 from WC24
portmap_25=97:40
#QSFP+ 26 from WC25
portmap_26=101:40
#QSFP+ 27 from WC26
portmap_27=105:40
#QSFP+ 28 from WC27
portmap_28=109:40
#QSFP+ 29 from WC28
portmap_29=113:40
#QSFP+ 30 from WC29
portmap_30=117:40
#QSFP+ 31 from WC30
portmap_31=121:40
#QSFP+ 32 from WC31
portmap_32=125:40
# L3 ECMP
# - In Trident2, VP LAGs share the same table as ECMP group table.
# The first N entries are reserved for VP LAGs, where N is the value of the
# config property "max_vp_lags". By default this was set to 256
l3_max_ecmp_mode=1
max_vp_lags=0
stable_size=0x2000000

View File

@ -0,0 +1 @@
Accton-AS6712-32X t1

View File

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

View File

@ -0,0 +1,104 @@
# LED setting for active
# -----------------------------------------------------------------------------
# for as6712_32x (32 qxg)
# -----------------------------------------------------------------------------
s CMIC_LEDUP0_DATA_RAM 0
s CMIC_LEDUP1_DATA_RAM 0
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=1
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=2
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=3
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=4
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=5
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=6
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=7
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=8
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=9
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=10
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=11
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=12
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=13
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=14
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=15
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=63
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=62
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=61
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=60
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=59
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=58
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=57
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=56
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=55
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=54
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=53
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=52
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=51
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=50
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=49
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=48
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=46
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=45
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=44
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=43
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=42
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=41
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=40
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=39
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=38
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=37
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=36
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=35
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=34
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=33
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=32
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=31
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=30
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=29
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=28
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=27
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=26
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=25
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=24
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=23
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=22
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=21
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=20
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=19
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=18
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=17
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=16
led 0 stop
led 0 prog \
02 F9 42 80 02 F7 42 00 02 F8 42 00 02 F4 42 90 02 \
F3 42 10 67 6A 67 6A 67 38 67 6A 67 6A 67 6A 67 6A \
67 6A 67 6A 86 F8 06 F3 D6 F8 74 14 86 F0 3E F4 67 \
6A 57 67 7E 57 06 F8 88 80 4A 00 27 97 75 35 90 4A \
00 27 4A 01 27 B7 97 71 4F 77 32 06 F5 D6 F0 74 62 \
02 F5 4A 07 37 4E 07 02 F0 42 00 4E 07 02 F5 4A 07 \
71 32 77 35 16 F7 06 F9 17 4D DA 07 74 7B 12 F7 52 \
00 86 F9 57 86 F7 57 16 F7 06 F9 07 4D DA 07 74 8F \
12 F7 52 00 86 F9 57 86 F7 57 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00
led 0 start
led 1 stop
led 1 prog \
02 F9 42 80 02 F7 42 00 02 F8 42 01 02 F4 42 90 02 \
F3 42 11 67 6A 67 6A 67 38 67 6A 67 6A 67 6A 67 6A \
67 6A 67 6A 86 F8 06 F3 D6 F8 74 14 86 F0 3E F4 67 \
6A 57 67 7E 57 06 F8 88 80 4A 00 27 97 75 35 90 4A \
00 27 4A 01 27 B7 97 71 4F 77 32 06 F5 D6 F0 74 62 \
02 F5 4A 07 37 4E 07 02 F0 42 00 4E 07 02 F5 4A 07 \
71 32 77 35 16 F7 06 F9 17 4D DA 07 74 7B 12 F7 52 \
00 86 F9 57 86 F7 57 16 F7 06 F9 07 4D DA 07 74 8F \
12 F7 52 00 86 F9 57 86 F7 57 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00
led 1 start

View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
try:
import exceptions
import binascii
import time
import optparse
import warnings
import os
import sys
from sonic_eeprom import eeprom_base
from sonic_eeprom import eeprom_tlvinfo
import subprocess
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
_TLV_INFO_MAX_LEN = 256
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
#Two i2c buses might get flipped order, check them both.
if not os.path.exists(self.eeprom_path):
self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python
#############################################################################
# Accton
#
# Module contains an implementation of SONiC PSU Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
import os.path
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.psu_path = "/sys/bus/i2c/devices/"
self.psu_presence = "/psu_present"
self.psu_oper_status = "/psu_power_good"
self.psu_mapping = {
1: "35-0038",
2: "36-003b",
}
def get_num_psus(self):
return len(self.psu_mapping)
def get_psu_status(self, index):
if index is None:
return False
status = 0
node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status
try:
with open(node, 'r') as power_status:
status = int(power_status.read())
except IOError:
return False
return status == 1
def get_psu_presence(self, index):
if index is None:
return False
status = 0
node = self.psu_path + self.psu_mapping[index] + self.psu_presence
try:
with open(node, 'r') as presence_status:
status = int(presence_status.read())
except IOError:
return False
return status == 1

View File

@ -0,0 +1,215 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
import os
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 0
PORT_END = 31
PORTS_IN_BLOCK = 32
QSFP_PORT_START = 0
QSFP_PORT_END = 32
I2C_DEV_PATH = "/sys/bus/i2c/devices/"
BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{1}-0050/"
BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
CPLD_ADDRESS = ['-0062', '-0064']
_port_to_is_present = {}
_port_to_lp_mode = {}
_port_to_eeprom_mapping = {}
_port_to_i2c_mapping = {
0: [1, 2],
1: [2, 3],
2: [3, 4],
3: [4, 5],
4: [5, 6],
5: [6, 7],
6: [7, 8],
7: [8, 9],
8: [9, 10],
9: [10, 11],
10: [11, 12],
11: [12, 13],
12: [13, 14],
13: [14, 15],
14: [15, 16],
15: [16, 17],
16: [17, 18],
17: [18, 19],
18: [19, 20],
19: [20, 21],
20: [21, 22],
21: [22, 23],
22: [23, 24],
23: [24, 25],
24: [25, 26],
25: [26, 27],
26: [27, 28],
27: [28, 29],
28: [29, 30],
29: [30, 31],
30: [31, 32],
31: [32, 33],
32: [33, 34],
33: [34, 35],
34: [35, 36],
35: [36, 37],
36: [37, 38],
37: [38, 39],
38: [39, 40],
39: [40, 41],
40: [41, 42],
41: [42, 43],
42: [43, 44],
43: [44, 45],
44: [45, 46],
45: [46, 47],
46: [47, 48],
47: [48, 49],
48: [49, 50],#QSFP49
49: [49, 50],
50: [49, 50],
51: [49, 50],
52: [50, 52],#QSFP50
53: [50, 52],
54: [50, 52],
55: [50, 52],
56: [51, 54],#QSFP51
57: [51, 54],
58: [51, 54],
59: [51, 54],
60: [52, 51],#QSFP52
61: [52, 51],
62: [52, 51],
63: [52, 51],
64: [53, 53], #QSFP53
65: [53, 53],
66: [53, 53],
67: [53, 53],
68: [54, 55],#QSFP54
69: [54, 55],
70: [54, 55],
71: [54, 55],
}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_port_start(self):
return self.QSFP_PORT_START
@property
def qsfp_port_end(self):
return self.QSFP_PORT_END
@property
def qsfp_ports(self):
return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def __init__(self):
eeprom_path = self.BASE_OOM_PATH + "eeprom"
for x in range(0, self.port_end+1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(
self._port_to_i2c_mapping[x][1]
)
SfpUtilBase.__init__(self)
def get_cpld_dev_path(self, port_num):
if port_num < 16:
cpld_num = 0
else:
cpld_num = 1
#cpld can be at either bus 0 or bus 1.
cpld_path = self.I2C_DEV_PATH + str(0) + self.CPLD_ADDRESS[cpld_num]
if not os.path.exists(cpld_path):
cpld_path = self.I2C_DEV_PATH + str(1) + self.CPLD_ADDRESS[cpld_num]
return cpld_path
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
cpld_path = self.get_cpld_dev_path(port_num)
present_path = cpld_path + "/module_present_"
present_path += str(self._port_to_i2c_mapping[port_num][0])
self.__port_to_is_present = present_path
try:
val_file = open(self.__port_to_is_present)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
# content is a string, either "0" or "1"
if content == "1":
return True
return False
def get_low_power_mode(self, port_num):
raise NotImplementedError
def set_low_power_mode(self, port_num, lpmode):
raise NotImplementedError
def reset(self, port_num):
if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end:
return False
cpld_path = self.get_cpld_dev_path(port_num)
_path = cpld_path + "/module_reset_"
_path += str(self._port_to_i2c_mapping[port_num][0])
try:
reg_file = open(_path, 'w')
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
reg_file.seek(0)
reg_file.write('1')
time.sleep(1)
reg_file.seek(0)
reg_file.write('0')
reg_file.close()
return True
def get_transceiver_change_event(self):
"""
TODO: This function need to be implemented
when decide to support monitoring SFP(Xcvrd)
on this platform.
"""
raise NotImplementedError

View File

@ -0,0 +1,23 @@
# libsensors configuration file for AS6712-32X
# ------------------------------------------------
chip "cpr_4011_4mxx-i2c-*-3c"
label in1 "PSU1_VIN"
label in2 "PSU1_VOUT"
label curr1 "PSU1_IIN"
label curr2 "PSU1_IOUT"
label power1 "PSU1_PIN"
label power2 "PSU1_POUT"
label fan1 "PSU1_FAN"
label temp1 "PSU1_TEMP"
chip "cpr_4011_4mxx-i2c-*-3f"
label in1 "PSU2_VIN"
label in2 "PSU2_VOUT"
label curr1 "PSU2_IIN"
label curr2 "PSU2_IOUT"
label power1 "PSU2_PIN"
label power2 "PSU2_POUT"
label fan1 "PSU2_FAN"
label temp1 "PSU2_TEMP"

View File

@ -20,6 +20,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(ACCTON_AS7312_54X_PLATFORM_MODULE) \
$(ACCTON_AS7326_56X_PLATFORM_MODULE) \
$(ACCTON_AS7716_32XB_PLATFORM_MODULE) \
$(ACCTON_AS6712_32X_PLATFORM_MODULE) \
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7264Q28B_PLATFORM_MODULE) \

View File

@ -7,6 +7,7 @@ ACCTON_AS7716_32X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1
export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION
@ -15,6 +16,7 @@ export ACCTON_AS7716_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION
export ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION
export ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION
export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION
ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton
@ -46,4 +48,8 @@ ACCTON_AS7716_32XB_PLATFORM_MODULE = sonic-platform-accton-as7716-32xb_$(ACCTON_
$(ACCTON_AS7716_32XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7716_32xb-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7716_32XB_PLATFORM_MODULE)))
ACCTON_AS6712_32X_PLATFORM_MODULE = sonic-platform-accton-as6712-32x_$(ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS6712_32X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as6712_32x-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS6712_32X_PLATFORM_MODULE)))
SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE)

View File

@ -0,0 +1,253 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 Accton Technology Corporation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
# 1/10/2018: Jostar modify for as7716_32
# 3/32/2018: Roy Lee modify for as7326_56x
# ------------------------------------------------------------------
try:
import time
import logging
from collections import namedtuple
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
class FanUtil(object):
"""Platform-specific FanUtil class"""
FAN_NUM_ON_MAIN_BROAD = 5
FAN_NUM_1_IDX = 1
FAN_NUM_2_IDX = 2
FAN_NUM_3_IDX = 3
FAN_NUM_4_IDX = 4
FAN_NUM_5_IDX = 5
FAN_NODE_NUM_OF_MAP = 2
FAN_NODE_FAULT_IDX_OF_MAP = 1
#FAN_NODE_SPEED_IDX_OF_MAP = 2
FAN_NODE_DIR_IDX_OF_MAP = 2
#FAN_NODE_DUTY_IDX_OF_MAP = 4
#FANR_NODE_FAULT_IDX_OF_MAP = 5
#BASE_VAL_PATH = '/sys/bus/i2c/devices/11-0066/{0}'
#FAN_DUTY_PATH = '/sys/bus/i2c/devices/11-0066/fan_duty_cycle_percentage'
BASE_VAL_PATH = '/sys/devices/platform/as6712_32x_fan/{0}'
FAN_DUTY_PATH = '/sys/devices/platform/as6712_32x_fan/fan1_duty_cycle_percentage'
#logfile = ''
#loglevel = logging.INFO
""" Dictionary where
key1 = fan id index (integer) starting from 1
key2 = fan node index (interger) starting from 1
value = path to fan device file (string) """
_fan_to_device_path_mapping = {}
#fan1_direction
#fan1_fault
#fan1_present
#(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
_fan_to_device_node_mapping = {
(FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault',
(FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction',
(FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault',
(FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction',
(FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault',
(FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction',
(FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault',
(FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction',
(FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault',
(FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction',
}
def _get_fan_to_device_node(self, fan_num, node_num):
return self._fan_to_device_node_mapping[(fan_num, node_num)]
def _get_fan_node_val(self, fan_num, node_num):
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
return None
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
logging.debug('GET. Parameter error. node_num:%d', node_num)
return None
device_path = self.get_fan_to_device_path(fan_num, node_num)
try:
val_file = open(device_path, 'r')
except IOError as e:
logging.error('GET. unable to open file: %s', str(e))
return None
content = val_file.readline().rstrip()
if content == '':
logging.debug('GET. content is NULL. device_path:%s', device_path)
return None
try:
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
return int(content)
def _set_fan_node_val(self, fan_num, node_num, val):
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
return None
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
logging.debug('GET. Parameter error. node_num:%d', node_num)
return None
content = str(val)
if content == '':
logging.debug('GET. content is NULL. device_path:%s', device_path)
return None
device_path = self.get_fan_to_device_path(fan_num, node_num)
try:
val_file = open(device_path, 'w')
except IOError as e:
logging.error('GET. unable to open file: %s', str(e))
return None
val_file.write(content)
try:
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
return True
def __init__(self):
fan_path = self.BASE_VAL_PATH
for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1):
for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1):
self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format(
self._fan_to_device_node_mapping[(fan_num, node_num)])
def get_num_fans(self):
return self.FAN_NUM_ON_MAIN_BROAD
def get_idx_fan_start(self):
return self.FAN_NUM_1_IDX
def get_num_nodes(self):
return self.FAN_NODE_NUM_OF_MAP
def get_idx_node_start(self):
return self.FAN_NODE_FAULT_IDX_OF_MAP
def get_size_node_map(self):
return len(self._fan_to_device_node_mapping)
def get_size_path_map(self):
return len(self._fan_to_device_path_mapping)
def get_fan_to_device_path(self, fan_num, node_num):
return self._fan_to_device_path_mapping[(fan_num, node_num)]
def get_fan_fault(self, fan_num):
return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP)
#def get_fan_speed(self, fan_num):
# return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP)
def get_fan_dir(self, fan_num):
return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP)
def get_fan_duty_cycle(self):
#duty_path = self.FAN_DUTY_PATH
try:
val_file = open(self.FAN_DUTY_PATH)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
return int(content)
#self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP)
#static u32 reg_val_to_duty_cycle(u8 reg_val)
#{
# reg_val &= FAN_DUTY_CYCLE_REG_MASK;
# return ((u32)(reg_val+1) * 625 + 75)/ 100;
#}
#
def set_fan_duty_cycle(self, val):
try:
fan_file = open(self.FAN_DUTY_PATH, 'r+')
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
#val = ((val + 1 ) * 625 +75 ) / 100
fan_file.write(str(val))
fan_file.close()
return True
#def get_fanr_fault(self, fan_num):
# return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP)
def get_fanr_speed(self, fan_num):
return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP)
def get_fan_status(self, fan_num):
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
logging.debug('GET. Parameter error. fan_num, %d', fan_num)
return None
if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0:
logging.debug('GET. FAN fault. fan_num, %d', fan_num)
return False
#if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0:
# logging.debug('GET. FANR fault. fan_num, %d', fan_num)
# return False
return True
#def main():
# fan = FanUtil()
#
# print 'get_size_node_map : %d' % fan.get_size_node_map()
# print 'get_size_path_map : %d' % fan.get_size_path_map()
# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
# print fan.get_fan_to_device_path(x, y)
#
#if __name__ == '__main__':
# main()

View File

@ -0,0 +1,124 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 Accton Technology Corporation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
# 1/10/2018:Jostar modify for as7716_32x
# 3/23/2018: Roy Lee modify for as7326_56x
# ------------------------------------------------------------------
try:
import time
import logging
import glob
from collections import namedtuple
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
class ThermalUtil(object):
"""Platform-specific ThermalUtil class"""
THERMAL_NUM_ON_MAIN_BROAD = 3
THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD
THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD
THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD
BASE_VAL_PATH = '/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input'
""" Dictionary where
key1 = thermal id index (integer) starting from 1
value = path to fan device file (string) """
_thermal_to_device_path_mapping = {}
_thermal_to_device_node_mapping = {
THERMAL_NUM_1_IDX: ['38', '48'],
THERMAL_NUM_2_IDX: ['39', '49'],
THERMAL_NUM_3_IDX: ['40', '4a'],
}
def __init__(self):
thermal_path = self.BASE_VAL_PATH
for x in range(self.THERMAL_NUM_1_IDX, self.THERMAL_NUM_ON_MAIN_BROAD+1):
self._thermal_to_device_path_mapping[x] = thermal_path.format(
self._thermal_to_device_node_mapping[x][0],
self._thermal_to_device_node_mapping[x][1])
def _get_thermal_node_val(self, thermal_num):
if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_ON_MAIN_BROAD:
logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
return None
device_path = self.get_thermal_to_device_path(thermal_num)
for filename in glob.glob(device_path):
try:
val_file = open(filename, 'r')
except IOError as e:
logging.error('GET. unable to open file: %s', str(e))
return None
content = val_file.readline().rstrip()
if content == '':
logging.debug('GET. content is NULL. device_path:%s', device_path)
return None
try:
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
return int(content)
def get_num_thermals(self):
return self.THERMAL_NUM_ON_MAIN_BROAD
def get_idx_thermal_start(self):
return self.THERMAL_NUM_1_IDX
def get_size_node_map(self):
return len(self._thermal_to_device_node_mapping)
def get_size_path_map(self):
return len(self._thermal_to_device_path_mapping)
def get_thermal_to_device_path(self, thermal_num):
return self._thermal_to_device_path_mapping[thermal_num]
def get_thermal_1_val(self):
return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX)
def get_thermal_2_val(self):
return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX)
def get_thermal_temp(self):
return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX))
#def main():
# thermal = ThermalUtil()
#
# print 'get_size_node_map : %d' % thermal.get_size_node_map()
# print 'get_size_path_map : %d' % thermal.get_size_path_map()
# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
# print thermal.get_thermal_to_device_path(x)
#
#if __name__ == '__main__':
# main()

View File

@ -0,0 +1,2 @@
obj-m:= accton_as6712_32x_psu.o accton-as6712-32x-cpld.o \
accton_as6712_32x_fan.o cpr_4011_4mxx.o leds-accton_as6712_32x.o

View File

@ -0,0 +1,887 @@
/*
* I2C multiplexer
*
* Copyright (C) 2014 Accton Technology Corporation.
*
* This module supports the accton cpld that hold the channel select
* mechanism for other i2c slave devices, such as SFP.
* This includes the:
* Accton as6712_32x CPLD1/CPLD2/CPLD3
*
* Based on:
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
* Copyright (C) 2006
*
* Based on:
* pca954x.c from Ken Harrenstien
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
*
* Based on:
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
* and
* pca9540.c from Jean Delvare <khali@linux-fr.org>.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/version.h>
#include <linux/stat.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
#define NUM_OF_CPLD1_CHANS 0x0
#define NUM_OF_CPLD2_CHANS 0x10
#define NUM_OF_CPLD3_CHANS 0x10
#define CPLD_CHANNEL_SELECT_REG 0x2
#define CPLD_DESELECT_CHANNEL 0xFF
#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
enum cpld_mux_type {
as6712_32x_cpld2,
as6712_32x_cpld3,
as6712_32x_cpld1
};
struct as6712_32x_cpld_data {
enum cpld_mux_type type;
struct i2c_client *client;
u8 last_chan; /* last register value */
struct device *hwmon_dev;
struct mutex update_lock;
};
struct chip_desc {
u8 nchans;
u8 deselectChan;
};
/* Provide specs for the PCA954x types we know about */
static const struct chip_desc chips[] = {
[as6712_32x_cpld1] = {
.nchans = NUM_OF_CPLD1_CHANS,
.deselectChan = NUM_OF_CPLD1_CHANS,
},
[as6712_32x_cpld2] = {
.nchans = NUM_OF_CPLD2_CHANS,
.deselectChan = NUM_OF_CPLD2_CHANS,
},
[as6712_32x_cpld3] = {
.nchans = NUM_OF_CPLD3_CHANS,
.deselectChan = NUM_OF_CPLD3_CHANS,
}
};
static const struct i2c_device_id as6712_32x_cpld_mux_id[] = {
{ "as6712_32x_cpld1", as6712_32x_cpld1 },
{ "as6712_32x_cpld2", as6712_32x_cpld2 },
{ "as6712_32x_cpld3", as6712_32x_cpld3 },
{ }
};
MODULE_DEVICE_TABLE(i2c, as6712_32x_cpld_mux_id);
#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index
#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index
#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index
#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index
enum as6712_32x_cpld_sysfs_attributes {
CPLD_VERSION,
ACCESS,
MODULE_PRESENT_ALL,
MODULE_RXLOS_ALL,
/* transceiver attributes */
TRANSCEIVER_PRESENT_ATTR_ID(1),
TRANSCEIVER_PRESENT_ATTR_ID(2),
TRANSCEIVER_PRESENT_ATTR_ID(3),
TRANSCEIVER_PRESENT_ATTR_ID(4),
TRANSCEIVER_PRESENT_ATTR_ID(5),
TRANSCEIVER_PRESENT_ATTR_ID(6),
TRANSCEIVER_PRESENT_ATTR_ID(7),
TRANSCEIVER_PRESENT_ATTR_ID(8),
TRANSCEIVER_PRESENT_ATTR_ID(9),
TRANSCEIVER_PRESENT_ATTR_ID(10),
TRANSCEIVER_PRESENT_ATTR_ID(11),
TRANSCEIVER_PRESENT_ATTR_ID(12),
TRANSCEIVER_PRESENT_ATTR_ID(13),
TRANSCEIVER_PRESENT_ATTR_ID(14),
TRANSCEIVER_PRESENT_ATTR_ID(15),
TRANSCEIVER_PRESENT_ATTR_ID(16),
TRANSCEIVER_PRESENT_ATTR_ID(17),
TRANSCEIVER_PRESENT_ATTR_ID(18),
TRANSCEIVER_PRESENT_ATTR_ID(19),
TRANSCEIVER_PRESENT_ATTR_ID(20),
TRANSCEIVER_PRESENT_ATTR_ID(21),
TRANSCEIVER_PRESENT_ATTR_ID(22),
TRANSCEIVER_PRESENT_ATTR_ID(23),
TRANSCEIVER_PRESENT_ATTR_ID(24),
TRANSCEIVER_PRESENT_ATTR_ID(25),
TRANSCEIVER_PRESENT_ATTR_ID(26),
TRANSCEIVER_PRESENT_ATTR_ID(27),
TRANSCEIVER_PRESENT_ATTR_ID(28),
TRANSCEIVER_PRESENT_ATTR_ID(29),
TRANSCEIVER_PRESENT_ATTR_ID(30),
TRANSCEIVER_PRESENT_ATTR_ID(31),
TRANSCEIVER_PRESENT_ATTR_ID(32),
/*Reset*/
TRANSCEIVER_RESET_ATTR_ID(1),
TRANSCEIVER_RESET_ATTR_ID(2),
TRANSCEIVER_RESET_ATTR_ID(3),
TRANSCEIVER_RESET_ATTR_ID(4),
TRANSCEIVER_RESET_ATTR_ID(5),
TRANSCEIVER_RESET_ATTR_ID(6),
TRANSCEIVER_RESET_ATTR_ID(7),
TRANSCEIVER_RESET_ATTR_ID(8),
TRANSCEIVER_RESET_ATTR_ID(9),
TRANSCEIVER_RESET_ATTR_ID(10),
TRANSCEIVER_RESET_ATTR_ID(11),
TRANSCEIVER_RESET_ATTR_ID(12),
TRANSCEIVER_RESET_ATTR_ID(13),
TRANSCEIVER_RESET_ATTR_ID(14),
TRANSCEIVER_RESET_ATTR_ID(15),
TRANSCEIVER_RESET_ATTR_ID(16),
TRANSCEIVER_RESET_ATTR_ID(17),
TRANSCEIVER_RESET_ATTR_ID(18),
TRANSCEIVER_RESET_ATTR_ID(19),
TRANSCEIVER_RESET_ATTR_ID(20),
TRANSCEIVER_RESET_ATTR_ID(21),
TRANSCEIVER_RESET_ATTR_ID(22),
TRANSCEIVER_RESET_ATTR_ID(23),
TRANSCEIVER_RESET_ATTR_ID(24),
TRANSCEIVER_RESET_ATTR_ID(25),
TRANSCEIVER_RESET_ATTR_ID(26),
TRANSCEIVER_RESET_ATTR_ID(27),
TRANSCEIVER_RESET_ATTR_ID(28),
TRANSCEIVER_RESET_ATTR_ID(29),
TRANSCEIVER_RESET_ATTR_ID(30),
TRANSCEIVER_RESET_ATTR_ID(31),
TRANSCEIVER_RESET_ATTR_ID(32),
};
/* sysfs attributes for hwmon
*/
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t set_status(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t show_version(struct device *dev, struct device_attribute *da,
char *buf);
static int as6712_32x_cpld_read_internal(struct i2c_client *client, u8 reg);
static int as6712_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
/* transceiver attributes */
#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index)
#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr
#define DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR|S_IRUGO, show_status, set_status, MODULE_RESET_##index)
#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr
static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
/* transceiver attributes */
static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(6);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(7);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(8);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(9);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(10);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(11);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(12);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(13);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(14);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(15);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(16);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(17);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(18);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(19);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(20);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(21);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(22);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(23);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(24);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(25);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(26);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(27);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(28);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(29);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(30);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(31);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(32);
static struct attribute *as6712_32x_cpld1_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
NULL
};
static const struct attribute_group as6712_32x_cpld1_group = {
.attrs = as6712_32x_cpld1_attributes,
};
static struct attribute *as6712_32x_cpld2_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
/* transceiver attributes */
&sensor_dev_attr_module_present_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(1),
DECLARE_TRANSCEIVER_PRESENT_ATTR(2),
DECLARE_TRANSCEIVER_PRESENT_ATTR(3),
DECLARE_TRANSCEIVER_PRESENT_ATTR(4),
DECLARE_TRANSCEIVER_PRESENT_ATTR(5),
DECLARE_TRANSCEIVER_PRESENT_ATTR(6),
DECLARE_TRANSCEIVER_PRESENT_ATTR(7),
DECLARE_TRANSCEIVER_PRESENT_ATTR(8),
DECLARE_TRANSCEIVER_PRESENT_ATTR(9),
DECLARE_TRANSCEIVER_PRESENT_ATTR(10),
DECLARE_TRANSCEIVER_PRESENT_ATTR(11),
DECLARE_TRANSCEIVER_PRESENT_ATTR(12),
DECLARE_TRANSCEIVER_PRESENT_ATTR(13),
DECLARE_TRANSCEIVER_PRESENT_ATTR(14),
DECLARE_TRANSCEIVER_PRESENT_ATTR(15),
DECLARE_TRANSCEIVER_PRESENT_ATTR(16),
DECLARE_TRANSCEIVER_RESET_ATTR(1),
DECLARE_TRANSCEIVER_RESET_ATTR(2),
DECLARE_TRANSCEIVER_RESET_ATTR(3),
DECLARE_TRANSCEIVER_RESET_ATTR(4),
DECLARE_TRANSCEIVER_RESET_ATTR(5),
DECLARE_TRANSCEIVER_RESET_ATTR(6),
DECLARE_TRANSCEIVER_RESET_ATTR(7),
DECLARE_TRANSCEIVER_RESET_ATTR(8),
DECLARE_TRANSCEIVER_RESET_ATTR(9),
DECLARE_TRANSCEIVER_RESET_ATTR(10),
DECLARE_TRANSCEIVER_RESET_ATTR(11),
DECLARE_TRANSCEIVER_RESET_ATTR(12),
DECLARE_TRANSCEIVER_RESET_ATTR(13),
DECLARE_TRANSCEIVER_RESET_ATTR(14),
DECLARE_TRANSCEIVER_RESET_ATTR(15),
DECLARE_TRANSCEIVER_RESET_ATTR(16),
NULL
};
static const struct attribute_group as6712_32x_cpld2_group = {
.attrs = as6712_32x_cpld2_attributes,
};
static struct attribute *as6712_32x_cpld3_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
/* transceiver attributes */
&sensor_dev_attr_module_present_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(17),
DECLARE_TRANSCEIVER_PRESENT_ATTR(18),
DECLARE_TRANSCEIVER_PRESENT_ATTR(19),
DECLARE_TRANSCEIVER_PRESENT_ATTR(20),
DECLARE_TRANSCEIVER_PRESENT_ATTR(21),
DECLARE_TRANSCEIVER_PRESENT_ATTR(22),
DECLARE_TRANSCEIVER_PRESENT_ATTR(23),
DECLARE_TRANSCEIVER_PRESENT_ATTR(24),
DECLARE_TRANSCEIVER_PRESENT_ATTR(25),
DECLARE_TRANSCEIVER_PRESENT_ATTR(26),
DECLARE_TRANSCEIVER_PRESENT_ATTR(27),
DECLARE_TRANSCEIVER_PRESENT_ATTR(28),
DECLARE_TRANSCEIVER_PRESENT_ATTR(29),
DECLARE_TRANSCEIVER_PRESENT_ATTR(30),
DECLARE_TRANSCEIVER_PRESENT_ATTR(31),
DECLARE_TRANSCEIVER_PRESENT_ATTR(32),
DECLARE_TRANSCEIVER_RESET_ATTR(17),
DECLARE_TRANSCEIVER_RESET_ATTR(18),
DECLARE_TRANSCEIVER_RESET_ATTR(19),
DECLARE_TRANSCEIVER_RESET_ATTR(20),
DECLARE_TRANSCEIVER_RESET_ATTR(21),
DECLARE_TRANSCEIVER_RESET_ATTR(22),
DECLARE_TRANSCEIVER_RESET_ATTR(23),
DECLARE_TRANSCEIVER_RESET_ATTR(24),
DECLARE_TRANSCEIVER_RESET_ATTR(25),
DECLARE_TRANSCEIVER_RESET_ATTR(26),
DECLARE_TRANSCEIVER_RESET_ATTR(27),
DECLARE_TRANSCEIVER_RESET_ATTR(28),
DECLARE_TRANSCEIVER_RESET_ATTR(29),
DECLARE_TRANSCEIVER_RESET_ATTR(30),
DECLARE_TRANSCEIVER_RESET_ATTR(31),
DECLARE_TRANSCEIVER_RESET_ATTR(32),
NULL
};
static const struct attribute_group as6712_32x_cpld3_group = {
.attrs = as6712_32x_cpld3_attributes,
};
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int i, status;
u8 values[2] = {0};
u8 regs[] = {0xA, 0xB};
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
mutex_lock(&data->update_lock);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
status = as6712_32x_cpld_read_internal(client, regs[i]);
if (status < 0) {
goto exit;
}
values[i] = ~(u8)status;
}
mutex_unlock(&data->update_lock);
/* Return values 1 -> 32 in order */
return sprintf(buf, "%.2x %.2x\n", values[0], values[1]);
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t set_status(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
int status = 0;
u8 reg = 0, mask = 0;
u32 val, para;
if (sscanf(buf, "%d", &para) != 1) {
return -EINVAL;
}
switch (attr->index) {
case MODULE_RESET_1 ... MODULE_RESET_32:
reg = 0x4 + (((attr->index - MODULE_PRESENT_1)/8)%2);
mask = 0x1 << ((attr->index - MODULE_PRESENT_1)%8);
break;
default:
return 0;
}
mutex_lock(&data->update_lock);
status = as6712_32x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
val = status & ~mask;
if (!para) { /*0 means reset*/
val |= mask;
}
status = as6712_32x_cpld_write_internal(client, reg, val);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
int status = 0;
u8 reg = 0, mask = 0;
switch (attr->index) {
case MODULE_PRESENT_1 ... MODULE_PRESENT_8:
reg = 0xA;
mask = 0x1 << (attr->index - MODULE_PRESENT_1);
break;
case MODULE_PRESENT_9 ... MODULE_PRESENT_16:
reg = 0xB;
mask = 0x1 << (attr->index - MODULE_PRESENT_9);
break;
case MODULE_PRESENT_17 ... MODULE_PRESENT_24:
reg = 0xA;
mask = 0x1 << (attr->index - MODULE_PRESENT_17);
break;
case MODULE_PRESENT_25 ... MODULE_PRESENT_32:
reg = 0xB;
mask = 0x1 << (attr->index - MODULE_PRESENT_25);
break;
case MODULE_RESET_1 ... MODULE_RESET_32:
reg = 0x4 + (((attr->index - MODULE_PRESENT_1)/8)%2);
mask = 0x1 << ((attr->index - MODULE_PRESENT_1)%8);
break;
default:
return 0;
}
mutex_lock(&data->update_lock);
status = as6712_32x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", !(status & mask));
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
int status;
u32 addr, val;
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
return -EINVAL;
}
if (addr > 0xFF || val > 0xFF) {
return -EINVAL;
}
mutex_lock(&data->update_lock);
status = as6712_32x_cpld_write_internal(client, addr, val);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
for this as they will try to lock adapter a second time */
static int as6712_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
{
unsigned long orig_jiffies;
unsigned short flags;
union i2c_smbus_data data;
int try;
s32 res = -EIO;
data.byte = val;
flags = client->flags;
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adap->algo->smbus_xfer) {
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (res = 0, try = 0; try <= adap->retries; try++) {
res = adap->algo->smbus_xfer(adap, client->addr, flags,
I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG,
I2C_SMBUS_BYTE_DATA, &data);
if (res != -EAGAIN)
break;
if (time_after(jiffies,
orig_jiffies + adap->timeout))
break;
}
}
return res;
}
static int as6712_32x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
u32 chan)
{
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
u8 regval;
int ret = 0;
regval = chan;
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = as6712_32x_cpld_mux_reg_write(muxc->parent, client, regval);
data->last_chan = regval;
}
return ret;
}
static int as6712_32x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
u32 chan)
{
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
/* Deselect active channel */
data->last_chan = chips[data->type].deselectChan;
return as6712_32x_cpld_mux_reg_write(muxc->parent, client, data->last_chan);
}
static void as6712_32x_cpld_add_client(struct i2c_client *client)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
if (!node) {
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
return;
}
node->client = client;
mutex_lock(&list_lock);
list_add(&node->list, &cpld_client_list);
mutex_unlock(&list_lock);
}
static void as6712_32x_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int found = 0;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client == client) {
found = 1;
break;
}
}
if (found) {
list_del(list_node);
kfree(cpld_node);
}
mutex_unlock(&list_lock);
}
static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0x1);
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
}
return sprintf(buf, "%d", val);
}
/*
* I2C init/probing/exit functions
*/
static int as6712_32x_cpld_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
int force, class;
struct i2c_mux_core *muxc;
struct as6712_32x_cpld_data *data;
int chan = 0;
int ret = -ENODEV;
const struct attribute_group *group = NULL;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
muxc = i2c_mux_alloc(adap, &client->dev,
chips[id->driver_data].nchans,
sizeof(*data), 0,
as6712_32x_cpld_mux_select_chan,
as6712_32x_cpld_mux_deselect_mux);
if (!muxc)
return -ENOMEM;
i2c_set_clientdata(client, muxc);
data = i2c_mux_priv(muxc);
data->client = client;
mutex_init(&data->update_lock);
if (data->type == as6712_32x_cpld2 || data->type == as6712_32x_cpld3) {
data->type = id->driver_data;
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
/* Now create an adapter for each channel */
for (chan = 0; chan < chips[data->type].nchans; chan++) {
force = 0; /* dynamic adap number */
class = 0; /* no class by default */
ret = i2c_mux_add_adapter(muxc, force, chan, class);
if (ret) {
ret = -ENODEV;
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
goto exit_mux_register;
}
}
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
chan, client->name);
}
/* Register sysfs hooks */
switch (data->type) {
case as6712_32x_cpld1:
group = &as6712_32x_cpld1_group;
break;
case as6712_32x_cpld2:
group = &as6712_32x_cpld2_group;
break;
case as6712_32x_cpld3:
group = &as6712_32x_cpld3_group;
break;
default:
break;
}
if (group) {
ret = sysfs_create_group(&client->dev.kobj, group);
if (ret) {
goto exit_mux_register;
}
}
if (chips[data->type].nchans) {
dev_info(&client->dev,
"registered %d multiplexed busses for I2C %s\n",
chan, client->name);
}
else {
dev_info(&client->dev,
"device %s registered\n", client->name);
}
as6712_32x_cpld_add_client(client);
return 0;
exit_mux_register:
i2c_mux_del_adapters(muxc);
kfree(data);
return ret;
}
static int as6712_32x_cpld_mux_remove(struct i2c_client *client)
{
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct as6712_32x_cpld_data *data = i2c_mux_priv(muxc);
const struct attribute_group *group = NULL;
as6712_32x_cpld_remove_client(client);
/* Remove sysfs hooks */
switch (data->type) {
case as6712_32x_cpld1:
group = &as6712_32x_cpld1_group;
break;
case as6712_32x_cpld2:
group = &as6712_32x_cpld2_group;
break;
case as6712_32x_cpld3:
group = &as6712_32x_cpld3_group;
break;
default:
break;
}
if (group) {
sysfs_remove_group(&client->dev.kobj, group);
}
i2c_mux_del_adapters(muxc);
return 0;
}
static int as6712_32x_cpld_read_internal(struct i2c_client *client, u8 reg)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_read_byte_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int as6712_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_write_byte_data(client, reg, value);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as6712_32x_cpld_read_internal(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as6712_32x_cpld_read);
int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as6712_32x_cpld_write_internal(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as6712_32x_cpld_write);
static struct i2c_driver as6712_32x_cpld_mux_driver = {
.driver = {
.name = "as6712_32x_cpld",
.owner = THIS_MODULE,
},
.probe = as6712_32x_cpld_mux_probe,
.remove = as6712_32x_cpld_mux_remove,
.id_table = as6712_32x_cpld_mux_id,
};
static int __init as6712_32x_cpld_mux_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&as6712_32x_cpld_mux_driver);
}
static void __exit as6712_32x_cpld_mux_exit(void)
{
i2c_del_driver(&as6712_32x_cpld_mux_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("Accton as6712-32x CPLD driver");
MODULE_LICENSE("GPL");
module_init(as6712_32x_cpld_mux_init);
module_exit(as6712_32x_cpld_mux_exit);

View File

@ -0,0 +1,463 @@
/*
* A hwmon driver for the Accton as6712 32x fan contrl
*
* Copyright (C) 2014 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>
#include <linux/delay.h>
#define DRVNAME "as6712_32x_fan"
#define FAN_MAX_NUMBER 5
#define FAN_SPEED_CPLD_TO_RPM_STEP 150
#define FAN_SPEED_PRECENT_TO_CPLD_STEP 5
#define FAN_DUTY_CYCLE_MIN 0 /* 10% ??*/
#define FAN_DUTY_CYCLE_MAX 100 /* 100% */
#define CPLD_REG_FAN_STATUS_OFFSET 0xC
#define CPLD_REG_FANR_STATUS_OFFSET 0x17
#define CPLD_REG_FAN_DIRECTION_OFFSET 0x1E
#define CPLD_FAN1_REG_SPEED_OFFSET 0x10
#define CPLD_FAN2_REG_SPEED_OFFSET 0x11
#define CPLD_FAN3_REG_SPEED_OFFSET 0x12
#define CPLD_FAN4_REG_SPEED_OFFSET 0x13
#define CPLD_FAN5_REG_SPEED_OFFSET 0x14
#define CPLD_FANR1_REG_SPEED_OFFSET 0x18
#define CPLD_FANR2_REG_SPEED_OFFSET 0x19
#define CPLD_FANR3_REG_SPEED_OFFSET 0x1A
#define CPLD_FANR4_REG_SPEED_OFFSET 0x1B
#define CPLD_FANR5_REG_SPEED_OFFSET 0x1C
#define CPLD_REG_FAN_PWM_CYCLE_OFFSET 0xD
#define CPLD_FAN1_INFO_BIT_MASK 0x1
#define CPLD_FAN2_INFO_BIT_MASK 0x2
#define CPLD_FAN3_INFO_BIT_MASK 0x4
#define CPLD_FAN4_INFO_BIT_MASK 0x8
#define CPLD_FAN5_INFO_BIT_MASK 0x10
#define PROJECT_NAME
#define DEBUG_MODE 0
#if (DEBUG_MODE == 1)
#define DEBUG_PRINT(format, ...) printk(format, __VA_ARGS__)
#else
#define DEBUG_PRINT(format, ...)
#endif
static struct accton_as6712_32x_fan *fan_data = NULL;
struct accton_as6712_32x_fan {
struct platform_device *pdev;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* != 0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 status[FAN_MAX_NUMBER]; /* inner first fan status */
u32 speed[FAN_MAX_NUMBER]; /* inner first fan speed */
u8 direction[FAN_MAX_NUMBER]; /* reconrd the direction of inner first and second fans */
u32 duty_cycle[FAN_MAX_NUMBER]; /* control the speed of inner first and second fans */
u8 r_status[FAN_MAX_NUMBER]; /* inner second fan status */
u32 r_speed[FAN_MAX_NUMBER]; /* inner second fan speed */
};
/*******************/
#define MAKE_FAN_MASK_OR_REG(name,type) \
CPLD_FAN##type##1_##name, \
CPLD_FAN##type##2_##name, \
CPLD_FAN##type##3_##name, \
CPLD_FAN##type##4_##name, \
CPLD_FAN##type##5_##name,
/* fan related data
*/
static const u8 fan_info_mask[] = {
MAKE_FAN_MASK_OR_REG(INFO_BIT_MASK,)
};
static const u8 fan_speed_reg[] = {
MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,)
};
static const u8 fanr_speed_reg[] = {
MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,R)
};
/*******************/
#define DEF_FAN_SET(id) \
FAN##id##_FAULT, \
FAN##id##_SPEED, \
FAN##id##_DUTY_CYCLE, \
FAN##id##_DIRECTION, \
FANR##id##_FAULT, \
FANR##id##_SPEED,
enum sysfs_fan_attributes {
DEF_FAN_SET(1)
DEF_FAN_SET(2)
DEF_FAN_SET(3)
DEF_FAN_SET(4)
DEF_FAN_SET(5)
};
/*******************/
static void accton_as6712_32x_fan_update_device(struct device *dev);
static int accton_as6712_32x_fan_read_value(u8 reg);
static int accton_as6712_32x_fan_write_value(u8 reg, u8 value);
static ssize_t fan_set_duty_cycle(struct device *dev,
struct device_attribute *da,const char *buf, size_t count);
static ssize_t fan_show_value(struct device *dev,
struct device_attribute *da, char *buf);
static ssize_t show_name(struct device *dev,
struct device_attribute *da, char *buf);
extern int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
/*******************/
#define _MAKE_SENSOR_DEVICE_ATTR(prj, id, id2) \
static SENSOR_DEVICE_ATTR(prj##fan##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \
static SENSOR_DEVICE_ATTR(prj##fan##id##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, \
fan_set_duty_cycle, FAN##id##_DUTY_CYCLE); \
static SENSOR_DEVICE_ATTR(prj##fan##id##_direction, S_IRUGO, fan_show_value, NULL, FAN##id##_DIRECTION); \
static SENSOR_DEVICE_ATTR(prj##fanr##id##_fault, S_IRUGO, fan_show_value, NULL, FANR##id##_FAULT); \
static SENSOR_DEVICE_ATTR(prj##fanr##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \
static SENSOR_DEVICE_ATTR(prj##fan##id##_input, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \
static SENSOR_DEVICE_ATTR(prj##fan##id2##_input, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \
static SENSOR_DEVICE_ATTR(prj##fan##id##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT); \
static SENSOR_DEVICE_ATTR(prj##fan##id2##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT);
#define MAKE_SENSOR_DEVICE_ATTR(prj,id, id2) _MAKE_SENSOR_DEVICE_ATTR(prj,id, id2)
MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,1 ,11)
MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,2 ,12)
MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,3 ,13)
MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,4 ,14)
MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME ,5 ,15)
static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
/*******************/
#define _MAKE_FAN_ATTR(prj, id, id2) \
&sensor_dev_attr_##prj##fan##id##_speed_rpm.dev_attr.attr, \
&sensor_dev_attr_##prj##fan##id##_duty_cycle_percentage.dev_attr.attr,\
&sensor_dev_attr_##prj##fan##id##_direction.dev_attr.attr, \
&sensor_dev_attr_##prj##fanr##id##_fault.dev_attr.attr, \
&sensor_dev_attr_##prj##fanr##id##_speed_rpm.dev_attr.attr, \
&sensor_dev_attr_##prj##fan##id##_input.dev_attr.attr, \
&sensor_dev_attr_##prj##fan##id2##_input.dev_attr.attr, \
&sensor_dev_attr_##prj##fan##id##_fault.dev_attr.attr, \
&sensor_dev_attr_##prj##fan##id2##_fault.dev_attr.attr,
#define MAKE_FAN_ATTR(prj, id, id2) _MAKE_FAN_ATTR(prj, id, id2)
static struct attribute *accton_as6712_32x_fan_attributes[] = {
/* fan related attributes */
MAKE_FAN_ATTR(PROJECT_NAME,1 ,11)
MAKE_FAN_ATTR(PROJECT_NAME,2 ,12)
MAKE_FAN_ATTR(PROJECT_NAME,3 ,13)
MAKE_FAN_ATTR(PROJECT_NAME,4 ,14)
MAKE_FAN_ATTR(PROJECT_NAME,5 ,15)
&sensor_dev_attr_name.dev_attr.attr,
NULL
};
/*******************/
/* fan related functions
*/
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
ssize_t ret = 0;
int data_index, type_index;
accton_as6712_32x_fan_update_device(dev);
if (fan_data->valid == 0) {
return ret;
}
type_index = attr->index%FAN2_FAULT;
data_index = attr->index/FAN2_FAULT;
switch (type_index) {
case FAN1_FAULT:
ret = sprintf(buf, "%d\n", fan_data->status[data_index]);
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
case FAN1_SPEED:
ret = sprintf(buf, "%d\n", fan_data->speed[data_index]);
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
case FAN1_DUTY_CYCLE:
ret = sprintf(buf, "%d\n", fan_data->duty_cycle[data_index]);
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
case FAN1_DIRECTION:
ret = sprintf(buf, "%d\n", fan_data->direction[data_index]); /* presnet, need to modify*/
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
case FANR1_FAULT:
ret = sprintf(buf, "%d\n", fan_data->r_status[data_index]);
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
case FANR1_SPEED:
ret = sprintf(buf, "%d\n", fan_data->r_speed[data_index]);
DEBUG_PRINT("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index);
break;
default:
DEBUG_PRINT("[Check !!][%s][%d] \n", __FUNCTION__, __LINE__);
break;
}
return ret;
}
static ssize_t show_name(struct device *dev, struct device_attribute *da,
char *buf)
{
return sprintf(buf, "%s\n", DRVNAME);
}
/*******************/
static ssize_t fan_set_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
int error, value;
error = kstrtoint(buf, 10, &value);
if (error)
return error;
if (value < FAN_DUTY_CYCLE_MIN || value > FAN_DUTY_CYCLE_MAX)
return -EINVAL;
accton_as6712_32x_fan_write_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET, value/FAN_SPEED_PRECENT_TO_CPLD_STEP);
fan_data->valid = 0;
return count;
}
static const struct attribute_group accton_as6712_32x_fan_group = {
.attrs = accton_as6712_32x_fan_attributes,
};
static int accton_as6712_32x_fan_read_value(u8 reg)
{
return as6712_32x_cpld_read(0x60, reg);
}
static int accton_as6712_32x_fan_write_value(u8 reg, u8 value)
{
return as6712_32x_cpld_write(0x60, reg, value);
}
static void accton_as6712_32x_fan_update_device(struct device *dev)
{
int speed, r_speed, fault, r_fault, direction, ctrl_speed;
int i;
int retry_count;
mutex_lock(&fan_data->update_lock);
DEBUG_PRINT("Starting accton_as6712_32x_fan update \n");
if (!(time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) || !fan_data->valid)) {
/* do nothing */
goto _exit;
}
fan_data->valid = 0;
DEBUG_PRINT("Starting accton_as6712_32x_fan update 2 \n");
fault = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_STATUS_OFFSET);
r_fault = accton_as6712_32x_fan_read_value(CPLD_REG_FANR_STATUS_OFFSET);
direction = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_DIRECTION_OFFSET);
ctrl_speed = accton_as6712_32x_fan_read_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET);
if ( (fault < 0) || (r_fault < 0) || (ctrl_speed < 0) )
{
DEBUG_PRINT("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
goto _exit; /* error */
}
DEBUG_PRINT("[fan:] fault:%d, r_fault=%d, ctrl_speed=%d \n",fault, r_fault, ctrl_speed);
for (i = 0; i < FAN_MAX_NUMBER; i++)
{
/* Update fan data
*/
/* fan fault
* 0: normal, 1:abnormal
* Each FAN-tray module has two fans.
*/
fan_data->status[i] = (fault & fan_info_mask[i]) >> i;
DEBUG_PRINT("[fan%d:] fail=%d \n",i, fan_data->status[i]);
fan_data->r_status[i] = (r_fault & fan_info_mask[i]) >> i;
fan_data->direction[i] = (direction & fan_info_mask[i]) >> i;
fan_data->duty_cycle[i] = ctrl_speed * FAN_SPEED_PRECENT_TO_CPLD_STEP;
/* fan speed
*/
speed = 0;
r_speed = 0;
retry_count = 3;
while (retry_count) {
retry_count--;
speed = accton_as6712_32x_fan_read_value(fan_speed_reg[i]);
r_speed = accton_as6712_32x_fan_read_value(fanr_speed_reg[i]);
if ( (speed < 0) || (r_speed < 0) )
{
DEBUG_PRINT("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__);
goto _exit; /* error */
}
if ( (speed == 0) || (r_speed == 0) )
{
msleep(50);
continue;
}
break;
}
DEBUG_PRINT("[fan%d:] speed:%d, r_speed=%d \n", i, speed, r_speed);
fan_data->speed[i] = speed * FAN_SPEED_CPLD_TO_RPM_STEP;
fan_data->r_speed[i] = r_speed * FAN_SPEED_CPLD_TO_RPM_STEP;
}
/* finish to update */
fan_data->last_updated = jiffies;
fan_data->valid = 1;
_exit:
mutex_unlock(&fan_data->update_lock);
}
static int accton_as6712_32x_fan_probe(struct platform_device *pdev)
{
int status = -1;
/* Register sysfs hooks */
status = sysfs_create_group(&pdev->dev.kobj, &accton_as6712_32x_fan_group);
if (status) {
goto exit;
}
fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(fan_data->hwmon_dev)) {
status = PTR_ERR(fan_data->hwmon_dev);
goto exit_remove;
}
dev_info(&pdev->dev, "accton_as6712_32x_fan\n");
return 0;
exit_remove:
sysfs_remove_group(&pdev->dev.kobj, &accton_as6712_32x_fan_group);
exit:
return status;
}
static int accton_as6712_32x_fan_remove(struct platform_device *pdev)
{
hwmon_device_unregister(fan_data->hwmon_dev);
sysfs_remove_group(&fan_data->pdev->dev.kobj, &accton_as6712_32x_fan_group);
return 0;
}
static struct platform_driver accton_as6712_32x_fan_driver = {
.probe = accton_as6712_32x_fan_probe,
.remove = accton_as6712_32x_fan_remove,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init accton_as6712_32x_fan_init(void)
{
int ret;
ret = platform_driver_register(&accton_as6712_32x_fan_driver);
if (ret < 0) {
goto exit;
}
fan_data = kzalloc(sizeof(struct accton_as6712_32x_fan), GFP_KERNEL);
if (!fan_data) {
ret = -ENOMEM;
platform_driver_unregister(&accton_as6712_32x_fan_driver);
goto exit;
}
mutex_init(&fan_data->update_lock);
fan_data->valid = 0;
fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(fan_data->pdev)) {
ret = PTR_ERR(fan_data->pdev);
platform_driver_unregister(&accton_as6712_32x_fan_driver);
kfree(fan_data);
goto exit;
}
exit:
return ret;
}
static void __exit accton_as6712_32x_fan_exit(void)
{
platform_device_unregister(fan_data->pdev);
platform_driver_unregister(&accton_as6712_32x_fan_driver);
kfree(fan_data);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as6712_32x_fan driver");
MODULE_LICENSE("GPL");
module_init(accton_as6712_32x_fan_init);
module_exit(accton_as6712_32x_fan_exit);

View File

@ -0,0 +1,364 @@
/*
* An hwmon driver for accton as6712_32x Power Module
*
* Copyright (C) 2014 Accton Technology Corporation.
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <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.
*/
#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>
#include <linux/delay.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 as6712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as6712_32x_cpld_read(unsigned short cpld_addr, u8 reg);
static int as6712_32x_psu_model_name_get(struct device *dev);
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Each client has this additional data
*/
struct as6712_32x_psu_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 index; /* PSU index */
u8 status; /* Status(present/power_good) register read from CPLD */
char model_name[14]; /* Model name, read from eeprom */
};
static struct as6712_32x_psu_data *as6712_32x_psu_update_device(struct device *dev);
enum as6712_32x_psu_sysfs_attributes {
PSU_INDEX,
PSU_PRESENT,
PSU_MODEL_NAME,
PSU_POWER_GOOD
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_INDEX);
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
static struct attribute *as6712_32x_psu_attributes[] = {
&sensor_dev_attr_psu_index.dev_attr.attr,
&sensor_dev_attr_psu_present.dev_attr.attr,
&sensor_dev_attr_psu_model_name.dev_attr.attr,
&sensor_dev_attr_psu_power_good.dev_attr.attr,
NULL
};
static ssize_t show_index(struct device *dev, struct device_attribute *da,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%d\n", data->index);
}
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct as6712_32x_psu_data *data = as6712_32x_psu_update_device(dev);
u8 status = 0;
if (!data->valid) {
return sprintf(buf, "0\n");
}
if (attr->index == PSU_PRESENT) {
status = IS_PRESENT(data->index, data->status);
}
else { /* PSU_POWER_GOOD */
status = IS_POWER_GOOD(data->index, data->status);
}
return sprintf(buf, "%d\n", status);
}
static ssize_t show_model_name(struct device *dev, struct device_attribute *da,
char *buf)
{
struct as6712_32x_psu_data *data = as6712_32x_psu_update_device(dev);
if (!data->valid) {
return 0;
}
if (!IS_PRESENT(data->index, data->status)) {
return 0;
}
if (as6712_32x_psu_model_name_get(dev) < 0) {
return -ENXIO;
}
return sprintf(buf, "%s\n", data->model_name);
}
static const struct attribute_group as6712_32x_psu_group = {
.attrs = as6712_32x_psu_attributes,
};
static int as6712_32x_psu_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as6712_32x_psu_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as6712_32x_psu_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->valid = 0;
data->index = dev_id->driver_data;
mutex_init(&data->update_lock);
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &as6712_32x_psu_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: psu '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &as6712_32x_psu_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as6712_32x_psu_remove(struct i2c_client *client)
{
struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as6712_32x_psu_group);
kfree(data);
return 0;
}
enum psu_index
{
as6712_32x_psu1,
as6712_32x_psu2
};
static const struct i2c_device_id as6712_32x_psu_id[] = {
{ "as6712_32x_psu1", as6712_32x_psu1 },
{ "as6712_32x_psu2", as6712_32x_psu2 },
{}
};
MODULE_DEVICE_TABLE(i2c, as6712_32x_psu_id);
static struct i2c_driver as6712_32x_psu_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as6712_32x_psu",
},
.probe = as6712_32x_psu_probe,
.remove = as6712_32x_psu_remove,
.id_table = as6712_32x_psu_id,
.address_list = normal_i2c,
};
static int as6712_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = 0;
int retry_count = 5;
while (retry_count) {
retry_count--;
result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(result < 0)) {
msleep(10);
continue;
}
if (unlikely(result != data_len)) {
result = -EIO;
msleep(10);
continue;
}
result = 0;
break;
}
return result;
}
enum psu_type {
PSU_YM_2401_JCR, /* AC110V - F2B */
PSU_YM_2401_JDR, /* AC110V - B2F */
PSU_CPR_4011_4M11, /* AC110V - F2B */
PSU_CPR_4011_4M21, /* AC110V - B2F */
PSU_CPR_6011_2M11, /* AC110V - F2B */
PSU_CPR_6011_2M21, /* AC110V - B2F */
PSU_UM400D_01G, /* DC48V - F2B */
PSU_UM400D01_01G /* DC48V - B2F */
};
struct model_name_info {
enum psu_type type;
u8 offset;
u8 length;
char* model_name;
};
struct model_name_info models[] = {
{PSU_YM_2401_JCR, 0x20, 11, "YM-2401JCR"},
{PSU_YM_2401_JDR, 0x20, 11, "YM-2401JDR"},
{PSU_CPR_4011_4M11, 0x26, 13, "CPR-4011-4M11"},
{PSU_CPR_4011_4M21, 0x26, 13, "CPR-4011-4M21"},
{PSU_CPR_6011_2M11, 0x26, 13, "CPR-6011-2M11"},
{PSU_CPR_6011_2M21, 0x26, 13, "CPR-6011-2M21"},
{PSU_UM400D_01G, 0x50, 9, "um400d01G"},
{PSU_UM400D01_01G, 0x50, 12, "um400d01-01G"},
};
static int as6712_32x_psu_model_name_get(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
int i, status;
for (i = 0; i < ARRAY_SIZE(models); i++) {
memset(data->model_name, 0, sizeof(data->model_name));
status = as6712_32x_psu_read_block(client, models[i].offset,
data->model_name, models[i].length);
if (status < 0) {
data->model_name[0] = '\0';
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n",
client->addr, models[i].offset);
return status;
}
else {
data->model_name[models[i].length] = '\0';
}
if (i == PSU_YM_2401_JCR || i == PSU_YM_2401_JDR) {
/* Skip the meaningless data byte 8*/
data->model_name[8] = data->model_name[9];
data->model_name[9] = data->model_name[10];
data->model_name[10] = '\0';
}
/* Determine if the model name is known, if not, read next index
*/
if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) {
return 0;
}
else {
data->model_name[0] = '\0';
}
}
return -ENODATA;
}
static struct as6712_32x_psu_data *as6712_32x_psu_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as6712_32x_psu_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int status = -1;
dev_dbg(&client->dev, "Starting as6812_32x update\n");
data->valid = 0;
/* Read psu status */
status = as6712_32x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET);
if (status < 0) {
dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status);
goto exit;
}
else {
data->status = status;
}
data->last_updated = jiffies;
data->valid = 1;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
module_i2c_driver(as6712_32x_psu_driver);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as6712_32x_psu driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,439 @@
/*
* 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_P_IN_UV,
PSU_P_OUT_UV,
PSU_TEMP1_INPUT,
PSU_FAN1_FAULT,
PSU_FAN1_DUTY_CYCLE,
PSU_FAN1_SPEED,
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN);
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN);
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN);
static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
/*Duplicate nodes for lm-sensors. 1 for input, 2 for output.*/
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_linear, NULL, PSU_V_IN);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_vout, NULL, PSU_V_OUT);
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_linear, NULL, PSU_I_IN);
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT);
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_linear, NULL, PSU_P_IN_UV);
static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
static struct attribute *cpr_4011_4mxx_attributes[] = {
&sensor_dev_attr_psu_v_in.dev_attr.attr,
&sensor_dev_attr_psu_v_out.dev_attr.attr,
&sensor_dev_attr_psu_i_in.dev_attr.attr,
&sensor_dev_attr_psu_i_out.dev_attr.attr,
&sensor_dev_attr_psu_p_in.dev_attr.attr,
&sensor_dev_attr_psu_p_out.dev_attr.attr,
&sensor_dev_attr_psu_temp1_input.dev_attr.attr,
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
&sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
/*Duplicate nodes for lm-sensors.*/
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_curr2_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_power2_input.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_fault.dev_attr.attr,
NULL
};
static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
{
u16 valid_data = data & mask;
bool is_negative = valid_data >> (valid_bit - 1);
return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data;
}
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1;
long speed;
int error;
error = kstrtol(buf, 10, &speed);
if (error)
return error;
if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE)
return -EINVAL;
mutex_lock(&data->update_lock);
data->fan_duty_cycle[nr] = speed;
cpr_4011_4mxx_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
u16 value = 0;
int exponent, mantissa;
int multiplier = 1000;
switch (attr->index) {
case PSU_V_IN:
value = data->v_in;
break;
case PSU_I_IN:
value = data->i_in;
break;
case PSU_I_OUT:
value = data->i_out;
break;
case PSU_P_IN_UV:
multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
/*Passing through*/
case PSU_P_IN:
value = data->p_in;
break;
case PSU_P_OUT_UV:
multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
/*Passing through*/
case PSU_P_OUT:
value = data->p_out;
break;
case PSU_TEMP1_INPUT:
value = data->temp_input[0];
break;
case PSU_FAN1_DUTY_CYCLE:
multiplier = 1;
value = data->fan_duty_cycle[0];
break;
case PSU_FAN1_SPEED:
multiplier = 1;
value = data->fan_speed[0];
break;
default:
break;
}
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
}
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
return sprintf(buf, "%d\n", data->fan_fault >> shift);
}
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
char *buf)
{
struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev);
int exponent, mantissa;
int multiplier = 1000;
exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
mantissa = data->v_out;
return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
}
static const struct attribute_group cpr_4011_4mxx_group = {
.attrs = cpr_4011_4mxx_attributes,
};
static int cpr_4011_4mxx_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct cpr_4011_4mxx_data *data;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct cpr_4011_4mxx_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->valid = 0;
mutex_init(&data->update_lock);
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &cpr_4011_4mxx_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: psu '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group);
exit_free:
kfree(data);
exit:
return status;
}
static int cpr_4011_4mxx_remove(struct i2c_client *client)
{
struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group);
kfree(data);
return 0;
}
static const struct i2c_device_id cpr_4011_4mxx_id[] = {
{ "cpr_4011_4mxx", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, cpr_4011_4mxx_id);
static struct i2c_driver cpr_4011_4mxx_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "cpr_4011_4mxx",
},
.probe = cpr_4011_4mxx_probe,
.remove = cpr_4011_4mxx_remove,
.id_table = cpr_4011_4mxx_id,
.address_list = normal_i2c,
};
static int cpr_4011_4mxx_read_byte(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int cpr_4011_4mxx_read_word(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_word_data(client, reg);
}
static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value)
{
return i2c_smbus_write_word_data(client, reg, value);
}
struct reg_data_byte {
u8 reg;
u8 *value;
};
struct reg_data_word {
u8 reg;
u16 *value;
};
static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int i, status;
struct reg_data_byte regs_byte[] = { {0x20, &data->vout_mode},
{0x81, &data->fan_fault}};
struct reg_data_word regs_word[] = { {0x96, &data->p_out}, /*p_out must be the first one.*/
{0x97, &data->p_in},
{0x8b, &data->v_out},
{0x89, &data->i_in},
{0x8c, &data->i_out},
{0x8d, &(data->temp_input[0])},
{0x8e, &(data->temp_input[1])},
{0x3b, &(data->fan_duty_cycle[0])},
{0x3c, &(data->fan_duty_cycle[1])},
{0x90, &(data->fan_speed[0])},
{0x91, &(data->fan_speed[1])}};
dev_dbg(&client->dev, "Starting cpr_4011_4mxx update\n");
/* Read byte data */
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
status = cpr_4011_4mxx_read_byte(client, regs_byte[i].reg);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_byte[i].reg, status);
*(regs_byte[i].value) = 0;
}
else {
*(regs_byte[i].value) = status;
}
}
/* Read word data */
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
status = cpr_4011_4mxx_read_word(client, regs_word[i].reg);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_word[i].reg, status);
*(regs_word[i].value) = 0;
}
else {
*(regs_word[i].value) = status;
}
/*Elimated false values. so p_out must be updated at first. */
if (data->p_out == 0) {
*(regs_word[i].value) = 0;
}
}
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static int __init cpr_4011_4mxx_init(void)
{
return i2c_add_driver(&cpr_4011_4mxx_driver);
}
static void __exit cpr_4011_4mxx_exit(void)
{
i2c_del_driver(&cpr_4011_4mxx_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("CPR_4011_4MXX driver");
MODULE_LICENSE("GPL");
module_init(cpr_4011_4mxx_init);
module_exit(cpr_4011_4mxx_exit);

View File

@ -0,0 +1,612 @@
/*
* A LED driver for the accton_as6712_32x_led
*
* Copyright (C) 2014 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.
*/
/*#define DEBUG*/
#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 as6712_32x_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as6712_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern void led_classdev_unregister(struct led_classdev *led_cdev);
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
extern void led_classdev_resume(struct led_classdev *led_cdev);
extern void led_classdev_suspend(struct led_classdev *led_cdev);
#define DRVNAME "as6712_32x_led"
struct accton_as6712_32x_led_data {
struct platform_device *pdev;
struct mutex update_lock;
char valid; /* != 0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 reg_val[4]; /* Register value, 0 = LOC/DIAG/FAN LED
1 = PSU1/PSU2 LED
2 = FAN1-4 LED
3 = FAN5-6 LED */
};
static struct accton_as6712_32x_led_data *ledctl = NULL;
/* LED related data
*/
#define LED_TYPE_PSU1_REG_MASK 0x03
#define LED_MODE_PSU1_GREEN_MASK 0x02
#define LED_MODE_PSU1_AMBER_MASK 0x01
#define LED_MODE_PSU1_OFF_MASK 0x03
#define LED_MODE_PSU1_AUTO_MASK 0x00
#define LED_TYPE_PSU2_REG_MASK 0x0C
#define LED_MODE_PSU2_GREEN_MASK 0x08
#define LED_MODE_PSU2_AMBER_MASK 0x04
#define LED_MODE_PSU2_OFF_MASK 0x0C
#define LED_MODE_PSU2_AUTO_MASK 0x00
#define LED_TYPE_DIAG_REG_MASK 0x0C
#define LED_MODE_DIAG_GREEN_MASK 0x08
#define LED_MODE_DIAG_AMBER_MASK 0x04
#define LED_MODE_DIAG_OFF_MASK 0x0C
#define LED_MODE_DIAG_BLINK_MASK 0x48
#define LED_TYPE_FAN_REG_MASK 0x03
#define LED_MODE_FAN_GREEN_MASK 0x02
#define LED_MODE_FAN_AMBER_MASK 0x01
#define LED_MODE_FAN_OFF_MASK 0x03
#define LED_MODE_FAN_AUTO_MASK 0x00
#define LED_TYPE_FAN1_REG_MASK 0x03
#define LED_TYPE_FAN2_REG_MASK 0xC0
#define LED_TYPE_FAN3_REG_MASK 0x30
#define LED_TYPE_FAN4_REG_MASK 0x0C
#define LED_TYPE_FAN5_REG_MASK 0x03
#define LED_MODE_FANX_GREEN_MASK 0x01
#define LED_MODE_FANX_RED_MASK 0x02
#define LED_MODE_FANX_OFF_MASK 0x00
#define LED_TYPE_LOC_REG_MASK 0x30
#define LED_MODE_LOC_ON_MASK 0x00
#define LED_MODE_LOC_OFF_MASK 0x10
#define LED_MODE_LOC_BLINK_MASK 0x20
static const u8 led_reg[] = {
0xA, /* LOC/DIAG/FAN LED*/
0xB, /* PSU1/PSU2 LED */
0xE, /* FAN2-5 LED */
0xF, /* FAN1 LED */
};
enum led_type {
LED_TYPE_PSU1,
LED_TYPE_PSU2,
LED_TYPE_DIAG,
LED_TYPE_FAN,
LED_TYPE_FAN1,
LED_TYPE_FAN2,
LED_TYPE_FAN3,
LED_TYPE_FAN4,
LED_TYPE_FAN5,
LED_TYPE_LOC
};
enum led_light_mode {
LED_MODE_OFF = 0,
LED_MODE_GREEN,
LED_MODE_AMBER,
LED_MODE_RED,
LED_MODE_GREEN_BLINK,
LED_MODE_AMBER_BLINK,
LED_MODE_RED_BLINK,
LED_MODE_AUTO,
};
struct led_type_mode {
enum led_type type;
int type_mask;
enum led_light_mode mode;
int mode_mask;
};
struct led_type_mode led_type_mode_data[] = {
{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU1_GREEN_MASK},
{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU1_AMBER_MASK},
{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU1_AUTO_MASK},
{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_OFF, LED_MODE_PSU1_OFF_MASK},
{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU2_GREEN_MASK},
{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU2_AMBER_MASK},
{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU2_AUTO_MASK},
{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_OFF, LED_MODE_PSU2_OFF_MASK},
{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_GREEN, LED_MODE_FAN_GREEN_MASK},
{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AMBER, LED_MODE_FAN_AMBER_MASK},
{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AUTO, LED_MODE_FAN_AUTO_MASK},
{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_OFF, LED_MODE_FAN_OFF_MASK},
{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0},
{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0},
{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0},
{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 6},
{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 6},
{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 6},
{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 4},
{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 4},
{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 4},
{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 2},
{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 2},
{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 2},
{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0},
{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0},
{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0},
{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_GREEN, LED_MODE_DIAG_GREEN_MASK},
{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_AMBER, LED_MODE_DIAG_AMBER_MASK},
{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_OFF, LED_MODE_DIAG_OFF_MASK},
{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_GREEN_BLINK, LED_MODE_DIAG_BLINK_MASK},
{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER, LED_MODE_LOC_ON_MASK},
{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_OFF, LED_MODE_LOC_OFF_MASK},
{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER_BLINK, LED_MODE_LOC_BLINK_MASK}
};
struct fanx_info_s {
u8 cname; /* device name */
enum led_type type;
u8 reg_id; /* map to led_reg & reg_val */
};
static struct fanx_info_s fanx_info[] = {
{'1', LED_TYPE_FAN1, 3},
{'2', LED_TYPE_FAN2, 2},
{'3', LED_TYPE_FAN3, 2},
{'4', LED_TYPE_FAN4, 2},
{'5', LED_TYPE_FAN5, 2},
};
static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) {
int i;
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
if (type != led_type_mode_data[i].type)
continue;
if (type == LED_TYPE_DIAG)
{ /* special case : bit 6 - meaning blinking */
if (0x40 & reg_val)
return LED_MODE_GREEN_BLINK;
}
if ((led_type_mode_data[i].type_mask & reg_val) ==
led_type_mode_data[i].mode_mask)
{
return led_type_mode_data[i].mode;
}
}
return 0;
}
static u8 led_light_mode_to_reg_val(enum led_type type,
enum led_light_mode mode, u8 reg_val) {
int i;
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
if (type != led_type_mode_data[i].type)
continue;
if (mode != led_type_mode_data[i].mode)
continue;
if (type == LED_TYPE_DIAG)
{
if (mode == LED_MODE_GREEN_BLINK)
{ /* special case : bit 6 - meaning blinking */
reg_val = 0x48 | (reg_val & ~0x4C);
break;
}
else
{ /* for diag led, other case must cancel bit 6 first */
reg_val = reg_val & ~0x40;
}
}
reg_val = led_type_mode_data[i].mode_mask |
(reg_val & (~led_type_mode_data[i].type_mask));
break;
}
return reg_val;
}
static int accton_as6712_32x_led_read_value(u8 reg)
{
return as6712_32x_cpld_read(0x60, reg);
}
static int accton_as6712_32x_led_write_value(u8 reg, u8 value)
{
return as6712_32x_cpld_write(0x60, reg, value);
}
static void accton_as6712_32x_led_update(void)
{
mutex_lock(&ledctl->update_lock);
if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
|| !ledctl->valid) {
int i;
dev_dbg(&ledctl->pdev->dev, "Starting accton_as6712_32x_led update\n");
/* Update LED data
*/
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
int status = accton_as6712_32x_led_read_value(led_reg[i]);
if (status < 0) {
ledctl->valid = 0;
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status);
goto exit;
}
else
{
ledctl->reg_val[i] = status;
}
}
ledctl->last_updated = jiffies;
ledctl->valid = 1;
}
exit:
mutex_unlock(&ledctl->update_lock);
}
static void accton_as6712_32x_led_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode,
u8 reg, enum led_type type)
{
int reg_val;
mutex_lock(&ledctl->update_lock);
reg_val = accton_as6712_32x_led_read_value(reg);
if (reg_val < 0) {
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val);
goto exit;
}
reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val);
accton_as6712_32x_led_write_value(reg, reg_val);
/* to prevent the slow-update issue */
ledctl->valid = 0;
exit:
mutex_unlock(&ledctl->update_lock);
}
static void accton_as6712_32x_led_psu_1_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1);
}
static enum led_brightness accton_as6712_32x_led_psu_1_get(struct led_classdev *cdev)
{
accton_as6712_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]);
}
static void accton_as6712_32x_led_psu_2_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2);
}
static enum led_brightness accton_as6712_32x_led_psu_2_get(struct led_classdev *cdev)
{
accton_as6712_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
}
static void accton_as6712_32x_led_fan_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN);
}
static enum led_brightness accton_as6712_32x_led_fan_get(struct led_classdev *cdev)
{
accton_as6712_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
}
static void accton_as6712_32x_led_fanx_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
enum led_type led_type1;
int reg_id;
int i, nsize;
int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s);
for(i=0;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_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1);
return;
}
}
}
static enum led_brightness accton_as6712_32x_led_fanx_get(struct led_classdev *cdev)
{
enum led_type led_type1;
int reg_id;
int i, nsize;
int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s);
for(i=0;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_as6712_32x_led_update();
return led_reg_val_to_light_mode(led_type1, ledctl->reg_val[reg_id]);
}
}
return led_reg_val_to_light_mode(LED_TYPE_FAN1, ledctl->reg_val[2]);
}
static void accton_as6712_32x_led_diag_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG);
}
static enum led_brightness accton_as6712_32x_led_diag_get(struct led_classdev *cdev)
{
accton_as6712_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
}
static void accton_as6712_32x_led_loc_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as6712_32x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC);
}
static enum led_brightness accton_as6712_32x_led_loc_get(struct led_classdev *cdev)
{
accton_as6712_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]);
}
static struct led_classdev accton_as6712_32x_leds[] = {
[LED_TYPE_PSU1] = {
.name = "accton_as6712_32x_led::psu1",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_psu_1_set,
.brightness_get = accton_as6712_32x_led_psu_1_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU2] = {
.name = "accton_as6712_32x_led::psu2",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_psu_2_set,
.brightness_get = accton_as6712_32x_led_psu_2_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN] = {
.name = "accton_as6712_32x_led::fan",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fan_set,
.brightness_get = accton_as6712_32x_led_fan_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN1] = {
.name = "accton_as6712_32x_led::fan1",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fanx_set,
.brightness_get = accton_as6712_32x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN2] = {
.name = "accton_as6712_32x_led::fan2",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fanx_set,
.brightness_get = accton_as6712_32x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN3] = {
.name = "accton_as6712_32x_led::fan3",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fanx_set,
.brightness_get = accton_as6712_32x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN4] = {
.name = "accton_as6712_32x_led::fan4",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fanx_set,
.brightness_get = accton_as6712_32x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_FAN5] = {
.name = "accton_as6712_32x_led::fan5",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_fanx_set,
.brightness_get = accton_as6712_32x_led_fanx_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_DIAG] = {
.name = "accton_as6712_32x_led::diag",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_diag_set,
.brightness_get = accton_as6712_32x_led_diag_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_LOC] = {
.name = "accton_as6712_32x_led::loc",
.default_trigger = "unused",
.brightness_set = accton_as6712_32x_led_loc_set,
.brightness_get = accton_as6712_32x_led_loc_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
};
static int accton_as6712_32x_led_suspend(struct platform_device *dev,
pm_message_t state)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
led_classdev_suspend(&accton_as6712_32x_leds[i]);
}
return 0;
}
static int accton_as6712_32x_led_resume(struct platform_device *dev)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
led_classdev_resume(&accton_as6712_32x_leds[i]);
}
return 0;
}
static int accton_as6712_32x_led_probe(struct platform_device *pdev)
{
int ret, i;
for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
ret = led_classdev_register(&pdev->dev, &accton_as6712_32x_leds[i]);
if (ret < 0)
break;
}
/* Check if all LEDs were successfully registered */
if (i != ARRAY_SIZE(accton_as6712_32x_leds)){
int j;
/* only unregister the LEDs that were successfully registered */
for (j = 0; j < i; j++) {
led_classdev_unregister(&accton_as6712_32x_leds[i]);
}
}
return ret;
}
static int accton_as6712_32x_led_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(accton_as6712_32x_leds); i++) {
led_classdev_unregister(&accton_as6712_32x_leds[i]);
}
return 0;
}
static struct platform_driver accton_as6712_32x_led_driver = {
.probe = accton_as6712_32x_led_probe,
.remove = accton_as6712_32x_led_remove,
.suspend = accton_as6712_32x_led_suspend,
.resume = accton_as6712_32x_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init accton_as6712_32x_led_init(void)
{
int ret;
ret = platform_driver_register(&accton_as6712_32x_led_driver);
if (ret < 0) {
goto exit;
}
ledctl = kzalloc(sizeof(struct accton_as6712_32x_led_data), GFP_KERNEL);
if (!ledctl) {
ret = -ENOMEM;
platform_driver_unregister(&accton_as6712_32x_led_driver);
goto exit;
}
mutex_init(&ledctl->update_lock);
ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(ledctl->pdev)) {
ret = PTR_ERR(ledctl->pdev);
platform_driver_unregister(&accton_as6712_32x_led_driver);
kfree(ledctl);
goto exit;
}
exit:
return ret;
}
static void __exit accton_as6712_32x_led_exit(void)
{
platform_device_unregister(ledctl->pdev);
platform_driver_unregister(&accton_as6712_32x_led_driver);
kfree(ledctl);
}
module_init(accton_as6712_32x_led_init);
module_exit(accton_as6712_32x_led_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as6712_32x_led driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,17 @@
[Unit]
Description=Accton AS6712-32X Platform Monitoring service
Before=pmon.service
After=sysinit.target
DefaultDependencies=no
[Service]
ExecStartPre=/usr/local/bin/accton_as6712_util.py install
ExecStart=/usr/local/bin/accton_as6712_monitor.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

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

View File

@ -0,0 +1,74 @@
Copyright (C) 2016 Accton Networks, Inc.
This program is free software: you can redistribute it and/or modify
It under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contents of this package:
module - Contains source code of as6712 kernel driver modules.
util - operational scripts.
Sonic creates a docker container and run building process under it.
If user tries to built new drivers, please get into that docker and
dpkg-buildpackage for them.
All Linux kernel code is licensed under the GPLv1. All other code is
licensed under the GPLv3. Please see the LICENSE file for copies of
both licenses.
The code for integacting with Accton AS6712-32X has 2 parts,
kernel drivers and operational script.
The kernel drivers of peripherals are under module/ directory.
1. These drivers can be built to individual ko during dpkg-buildpackage.
2. A operational script, accton_as6712_util.py, for device initializatian.
Run "accton_as6712_util.py install" to install drivers.
To initialize the system, run "accton_as6712_util.py install".
To clean up the drivers & devices, run "accton_as6712_util.py clean".
To dump information of sensors, run "accton_as6712_util.py show".
To dump SFP EEPROM, run "accton_as6712_util.py sff".
To set fan speed, run "accton_as6712_util.py set fan".
To enable/disable SFP emission, run "accton_as6712_util.py set sfp".
To set system LEDs' color, run "accton_as6712_util.py set led"
For more information, run "accton_as6712_util.py --help".
====================================================================
Besides applying accton_as6712_util.py to access peripherals, you can
access peripherals by sysfs nodes directly after the installation is run.
System LED:
There are 5 system LEDs at the lower-left corner of front panel.
They are loc, diag, fan, ps1, and ps2.
The sysfs interface color mappings are as follows:
Brightness:
0 => off
1 => green
2 => amber
3 => red
4 => blue
But not all colors are available for each LED.
Fan Control:
There are 10 fans inside 5 fan modules.
All fans share 1 duty setting, ranged from 0~100.
Thermal sensers:
3 temperature sensors are controlled by the lm75 kernel modules.
PSUs:
There 2 power supplies slot at the left/right side of the back.
Once if a PSU is not plugged, the status of it is shown failed.
There are 32 QSFP modules are equipped.
Before operating on PSU and QSFP+, please make sure it is well plugged.
Otherwise, operation is going to fail.

View File

@ -0,0 +1,208 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 Accton Technology Corporation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
# 1/10/2018: Jostar modify for as7716_32
# 4/10/2018: Roy Lee modify for as6712_32x
# ------------------------------------------------------------------
try:
import os
import sys, getopt
import subprocess
import click
import imp
import logging
import logging.config
import types
import time # this is only being used as part of the example
import traceback
from tabulate import tabulate
from as6712_32x.fanutil import FanUtil
from as6712_32x.thermalutil import ThermalUtil
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
# Deafults
VERSION = '1.0'
FUNCTION_NAME = 'accton_as6712_monitor'
global log_file
global log_level
# (LM75_1+ LM75_2+ LM75_3) is LM75 at i2c addresses 0x48, 0x49, and 0x4A.
# TMP = (LM75_1+ LM75_2+ LM75_3)/3
#1. If TMP < 35, All fans run with duty 30%.
#2. If TMP>=35 or the temperature of any one of fan is higher than 40,
# All fans run with duty 50%
#3. If TMP >= 40 or the temperature of any one of fan is higher than 45,
# All fans run with duty 65%.
#4. If TMP >= 45 or the temperature of any one of fan is higher than 50,
# All fans run with duty 100%.
#5. Any one of 5 fans is fault, set duty = 100%.
#6. Direction factor. If it is B2F direction, duty + 10%.
# MISC:
# 1.Check single LM75 before applied average.
# 2.If no matched fan speed is found from the policy,
# use FAN_DUTY_CYCLE_MIN as default speed
# Get current temperature
# 4.Decision 3: Decide new fan speed depend on fan direction/current fan speed/temperature
# Make a class we can use to capture stdout and sterr in the log
class accton_as6712_monitor(object):
# static temp var
_ori_temp = 0
_new_perc = 0
_ori_perc = 0
def __init__(self, log_file, log_level):
"""Needs a logger and a logger level."""
# set up logging to file
logging.basicConfig(
filename=log_file,
filemode='w',
level=log_level,
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
# set up logging to console
if log_level == logging.DEBUG:
console = logging.StreamHandler()
console.setLevel(log_level)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
def manage_fans(self):
max_duty = 100
fan_policy_f2b = {
0: [30, 0, 105000],
1: [50, 105000, 120000],
2: [65, 120000, 135000],
3: [max_duty, 135000, sys.maxsize],
}
fan_policy_b2f = {
0: [40, 0, 105000],
1: [60, 105000, 120000],
2: [75, 120000, 135000],
3: [max_duty, 135000, sys.maxsize],
}
fan_policy_single = {
0: 40000,
1: 45000,
2: 50000,
}
thermal = ThermalUtil()
fan = FanUtil()
for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
fan_status = fan.get_fan_status(x)
if fan_status is None:
logging.debug('INFO. SET new_perc to %d (FAN stauts is None. fan_num:%d)', max_duty, x)
return False
if fan_status is False:
logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', max_duty, x)
fan.set_fan_duty_cycle(max_duty)
return True
#logging.debug('INFO. fan_status is True (fan_num:%d)', x)
fan_dir=fan.get_fan_dir(1)
if fan_dir == 0:
fan_policy = fan_policy_f2b
else:
fan_policy = fan_policy_b2f
#Decide fan duty by if any of sensors > fan_policy_single.
new_duty_cycle = fan_policy[0][0]
for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
single_thm = thermal._get_thermal_node_val(x)
for y in range(0, len(fan_policy_single)):
if single_thm > fan_policy_single[y]:
if fan_policy[y+1][0] > new_duty_cycle:
new_duty_cycle = fan_policy[y+1][0]
logging.debug('INFO. Single thermal sensor %d with temp %d > %d , new_duty_cycle=%d',
x, single_thm, fan_policy_single[y], new_duty_cycle)
single_result = new_duty_cycle
#Find if current duty matched any of define duty.
#If not, set it to highest one.
cur_duty_cycle = fan.get_fan_duty_cycle()
for x in range(0, len(fan_policy)):
if cur_duty_cycle == fan_policy[x][0]:
break
if x == len(fan_policy) :
fan.set_fan_duty_cycle(fan_policy[0][0])
cur_duty_cycle = max_duty
#Decide fan duty by if sum of sensors falls into any of fan_policy{}
get_temp = thermal.get_thermal_temp()
new_duty_cycle = cur_duty_cycle
for x in range(0, len(fan_policy)):
y = len(fan_policy) - x -1 #checked from highest
if get_temp > fan_policy[y][1] and get_temp <= fan_policy[y][2] :
new_duty_cycle= fan_policy[y][0]
logging.debug('INFO. Sum of temp %d > %d , new_duty_cycle=%d', get_temp, fan_policy[y][1], new_duty_cycle)
sum_result = new_duty_cycle
if (sum_result>single_result):
new_duty_cycle = sum_result;
else:
new_duty_cycle = single_result
logging.debug('INFO. Final duty_cycle=%d', new_duty_cycle)
if(new_duty_cycle != cur_duty_cycle):
fan.set_fan_duty_cycle(new_duty_cycle)
return True
def main(argv):
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.INFO
if len(sys.argv) != 1:
try:
opts, args = getopt.getopt(argv,'hdl:',['lfile='])
except getopt.GetoptError:
print 'Usage: %s [-d] [-l <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
monitor = accton_as6712_monitor(log_file, log_level)
# Loop forever, doing something useful hopefully:
while True:
monitor.manage_fans()
time.sleep(10)
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,627 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 Accton Networks, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Description:
# Due to adoption of optoe drivers, sideband signals of SFPs are moved
# into cpld drivers. Add a new dict, cpld_of_module, for mapping this
# attributes to corresponding cpld nodes.
#
"""
Usage: %(scriptName)s [options] command object
options:
-h | --help : this help message
-d | --debug : run with debug mode
-f | --force : ignore error during installation or clean
command:
install : install drivers and generate related sysfs nodes
clean : uninstall drivers and remove related sysfs nodes
show : show all systen status
sff : dump SFP eeprom
set : change board setting with fan|led|sfp
"""
import os
import commands
import sys, getopt
import logging
import re
import time
from collections import namedtuple
PROJECT_NAME = 'as6712_32x'
version = '0.2.0'
verbose = False
DEBUG = False
args = []
ALL_DEVICE = {}
DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':4, 'psu':2, 'sfp':32}
led_prefix ='/sys/devices/platform/as6712_32x_led/leds/accton_'+PROJECT_NAME+'_led::'
fan_prefix ='/sys/devices/platform/as6712_32x_'
hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'],
'fan1': ['fan'],
'fan2': ['fan'],
'fan3': ['fan'],
'fan4': ['fan'],
'fan5': ['fan'],
}
hwmon_nodes = {'led': ['brightness'] ,
'fan1': ['fan1_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'],
'fan2': ['fan2_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'],
'fan3': ['fan3_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'],
'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'],
'fan5': ['fan5_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'],
}
hwmon_prefix ={'led': led_prefix,
'fan1': fan_prefix,
'fan2': fan_prefix,
'fan3': fan_prefix,
'fan4': fan_prefix,
'fan5': fan_prefix,
}
i2c_prefix = '/sys/bus/i2c/devices/'
i2c_bus = {'thermal': ['38-0048','39-0049', '40-004a', '41-004b'] ,
'psu': ['35-0038','36-003b'],
'sfp': ['-0050']}
i2c_nodes = {
'thermal': ['hwmon/hwmon*/temp1_input'] ,
'psu': ['psu_present ', 'psu_power_good'] ,
'sfp': ['module_present_', 'sfp_tx_disable']}
sfp_map = [ 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33
]
#For sideband signals of SFP/QSFP modules.
bus_of_cpld = [0, 1]
cpld_of_module = {'-0062': list(range(0,16)),
'-0064': list(range(16,32)) }
mknod =[
'echo as6712_32x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo as6712_32x_cpld2 0x62 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo as6712_32x_cpld3 0x64 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device',
# PSU-1
'echo as6712_32x_psu1 0x38 > /sys/bus/i2c/devices/i2c-35/new_device',
'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-35/new_device',
#'echo as6712_32x_psu1 0x50 > /sys/bus/i2c/devices/i2c-35/new_device',
#'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-35/new_device',
# PSU-2
'echo as6712_32x_psu2 0x3b > /sys/bus/i2c/devices/i2c-36/new_device',
'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-36/new_device',
#'echo as6712_32x_psu2 0x53 > /sys/bus/i2c/devices/i2c-36/new_device',
#'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-36/new_device',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-38/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-39/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-40/new_device',
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-41/new_device',
]
mknod2 =[
'echo as6712_32x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo as6712_32x_cpld2 0x62 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo as6712_32x_cpld3 0x64 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device',
# PSU-1
'echo as6712_32x_psu1 0x38 > /sys/bus/i2c/devices/i2c-35/new_device',
'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-35/new_device',
#'echo as6712_32x_psu1 0x50 > /sys/bus/i2c/devices/i2c-35/new_device',
#'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-35/new_device',
# PSU-2
'echo as6712_32x_psu2 0x3b > /sys/bus/i2c/devices/i2c-36/new_device',
'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-36/new_device',
#'echo as6712_32x_psu2 0x53 > /sys/bus/i2c/devices/i2c-36/new_device',
#'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-36/new_device',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-38/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-39/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-40/new_device',
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-41/new_device',
]
FORCE = 0
if DEBUG == True:
print sys.argv[0]
print 'ARGV :', sys.argv[1:]
def main():
global DEBUG
global args
global FORCE
if len(sys.argv)<2:
show_help()
options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
'debug',
'force',
])
if DEBUG == True:
print options
print args
print len(sys.argv)
for opt, arg in options:
if opt in ('-h', '--help'):
show_help()
elif opt in ('-d', '--debug'):
DEBUG = True
logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG)
logging.basicConfig(level=logging.INFO)
elif opt in ('-f', '--force'):
FORCE = 1
else:
logging.info('no option')
for arg in args:
if arg == 'install':
do_install()
elif arg == 'clean':
do_uninstall()
elif arg == 'show':
device_traversal()
elif arg == 'sff':
if len(args)!=2:
show_eeprom_help()
elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']:
show_eeprom_help()
else:
show_eeprom(args[1])
return
elif arg == 'set':
if len(args)<3:
show_set_help()
else:
set_device(args[1:])
return
else:
show_help()
return 0
def show_help():
print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
sys.exit(0)
def show_set_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print cmd +" [led|sfp|fan]"
print " use \""+ cmd + " led 0-4 \" to set led color"
print " use \""+ cmd + " fan 0-100\" to set fan duty percetage"
print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable"
sys.exit(0)
def show_eeprom_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom"
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print "[ACCTON DBG]: "+txt
return
def log_os_system(cmd, show):
logging.info('Run :'+cmd)
status = 1
output = ""
status, output = commands.getstatusoutput(cmd)
my_log (cmd +"with result:" + str(status))
my_log ("cmd:" + cmd)
my_log (" output:"+output)
if status:
logging.info('Failed :'+cmd)
if show:
print('Failed :'+cmd)
return status, output
def driver_inserted():
ret, lsmod = log_os_system("lsmod| grep accton", 0)
logging.info('mods:'+lsmod)
if len(lsmod) ==0:
return False
kos = [
'depmod -ae',
'modprobe i2c_dev',
'modprobe i2c_mux_pca954x',
'modprobe optoe',
'modprobe accton_as6712_32x_cpld',
'modprobe cpr_4011_4mxx',
#'modprobe ym2651y',
'modprobe accton_as6712_32x_fan',
'modprobe leds-accton_as6712_32x',
'modprobe accton_as6712_32x_psu']
def driver_install():
global FORCE
for i in range(0,len(kos)):
status, output = log_os_system(kos[i], 1)
if status:
if FORCE == 0:
return status
return 0
def driver_uninstall():
global FORCE
for i in range(0,len(kos)):
rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
rm = rm.replace("insmod", "rmmod")
status, output = log_os_system(rm, 1)
if status:
if FORCE == 0:
return status
return 0
def cpld_bus_check():
tmp = "i2cget -y -f 0 0x60"
status, output = log_os_system(tmp, 0)
if status:
return 1
else:
return 0
def i2c_order_check():
# i2c bus 0 and 1 might be installed in different order.
# Here check if 0x70 is exist @ i2c-0
tmp = "echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device"
status, output = log_os_system(tmp, 0)
if not device_exist():
order = 1
else:
order = 0
tmp = "echo 0x70 > /sys/bus/i2c/devices/i2c-1/delete_device"
status, output = log_os_system(tmp, 0)
return order
def device_install():
global FORCE
order = i2c_order_check()
# if 0x76 is not exist @i2c-0, use reversed bus order
if order:
for i in range(0,len(mknod2)):
#for pca932x need times to built new i2c buses
if mknod2[i].find('pca954') != -1:
time.sleep(2)
status, output = log_os_system(mknod2[i], 1)
if status:
print output
if FORCE == 0:
return status
else:
for i in range(0,len(mknod)):
#for pca932x need times to built new i2c buses
if mknod[i].find('pca954') != -1:
time.sleep(2)
status, output = log_os_system(mknod[i], 1)
if status:
print output
if FORCE == 0:
return status
for i in range(0,len(sfp_map)):
status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
if status:
print output
if FORCE == 0:
return status
status, output =log_os_system("echo port"+str(i)+" > /sys/bus/i2c/devices/"+str(sfp_map[i])+"-0050/port_name", 1)
if status:
print output
if FORCE == 0:
return status
return
def device_uninstall():
global FORCE
status, output =log_os_system("ls /sys/bus/i2c/devices/0-0070", 0)
if status==0:
I2C_ORDER=1
else:
I2C_ORDER=0
for i in range(0,len(sfp_map)):
target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device"
status, output =log_os_system("echo 0x50 > "+ target, 1)
if status:
print output
if FORCE == 0:
return status
if I2C_ORDER==0:
nodelist = mknod
else:
nodelist = mknod2
for i in range(len(nodelist)):
target = nodelist[-(i+1)]
temp = target.split()
del temp[1]
temp[-1] = temp[-1].replace('new_device', 'delete_device')
status, output = log_os_system(" ".join(temp), 1)
if status:
print output
if FORCE == 0:
return status
return
def system_ready():
if driver_inserted() == False:
return False
if not device_exist():
return False
return True
def do_install():
print "Checking system...."
if driver_inserted() == False:
print "No driver, installing...."
status = driver_install()
if status:
if FORCE == 0:
return status
else:
print PROJECT_NAME.upper()+" drivers detected...."
if not device_exist():
print "No device, installing...."
status = device_install()
if status:
if FORCE == 0:
return status
else:
print PROJECT_NAME.upper()+" devices detected...."
return
def do_uninstall():
print "Checking system...."
if not device_exist():
print PROJECT_NAME.upper() +" has no device installed...."
else:
print "Removing device...."
status = device_uninstall()
if status:
if FORCE == 0:
return status
if driver_inserted()== False :
print PROJECT_NAME.upper() +" has no driver installed...."
else:
print "Removing installed driver...."
status = driver_uninstall()
if status:
if FORCE == 0:
return status
return
def devices_info():
global DEVICE_NO
global ALL_DEVICE
global i2c_bus, hwmon_types
for key in DEVICE_NO:
ALL_DEVICE[key]= {}
for i in range(0,DEVICE_NO[key]):
ALL_DEVICE[key][key+str(i+1)] = []
order = cpld_bus_check()
for key in i2c_bus:
buses = i2c_bus[key]
nodes = i2c_nodes[key]
for i in range(0,len(buses)):
for j in range(0,len(nodes)):
if 'fan' == key:
for k in range(0,DEVICE_NO[key]):
node = key+str(k+1)
path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
elif 'sfp' == key:
for k in range(0,DEVICE_NO[key]):
for lk in cpld_of_module:
if k in cpld_of_module[lk]:
bus = bus_of_cpld[order]
node = key+str(k+1)
path = i2c_prefix + str(bus) + lk + "/"+ nodes[j] + str(k+1)
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
else:
node = key+str(i+1)
path = i2c_prefix+ buses[i]+"/"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
for key in hwmon_types:
itypes = hwmon_types[key]
nodes = hwmon_nodes[key]
for i in range(0,len(itypes)):
for j in range(0,len(nodes)):
node = key+"_"+itypes[i]
path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][ key+str(i+1)].append(path)
#show dict all in the order
if DEBUG == True:
for i in sorted(ALL_DEVICE.keys()):
print(i+": ")
for j in sorted(ALL_DEVICE[i].keys()):
print(" "+j)
for k in (ALL_DEVICE[i][j]):
print(" "+" "+k)
return
def show_eeprom(index):
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0]
node = node.replace(node.split("/")[-1], 'eeprom')
# check if got hexdump command in current environment
ret, log = log_os_system("which hexdump", 0)
ret, log2 = log_os_system("which busybox hexdump", 0)
if len(log):
hex_cmd = 'hexdump'
elif len(log2):
hex_cmd = ' busybox hexdump'
else:
log = 'Failed : no hexdump cmd!!'
logging.info(log)
print log
return 1
print node + ":"
ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
if ret==0:
print log
else:
print "**********device no found**********"
return
def set_device(args):
global DEVICE_NO
global ALL_DEVICE
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
if args[0]=='led':
if int(args[1])>4:
show_set_help()
return
#print ALL_DEVICE['led']
for i in range(0,len(ALL_DEVICE['led'])):
for k in (ALL_DEVICE['led']['led'+str(i+1)]):
ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
if ret:
return ret
elif args[0]=='fan':
if int(args[1])>100:
show_set_help()
return
#print ALL_DEVICE['fan']
#fan1~6 is all fine, all fan share same setting
node = ALL_DEVICE['fan1'] ['fan11'][0]
node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage')
ret, log = log_os_system("cat "+ node, 1)
if ret==0:
print ("Previous fan duty: " + log.strip() +"%")
ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
if ret==0:
print ("Current fan duty: " + args[1] +"%")
return ret
elif args[0]=='sfp':
if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0:
show_set_help()
return
if len(args)<2:
show_set_help()
return
if int(args[2])>1:
show_set_help()
return
#print ALL_DEVICE[args[0]]
for i in range(0,len(ALL_DEVICE[args[0]])):
for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]:
if j.find('tx_disable')!= -1:
ret, log = log_os_system("echo "+args[2]+" >"+ j, 1)
if ret:
return ret
return
#get digits inside a string.
#Ex: 31 for "sfp31"
def get_value(input):
digit = re.findall('\d+', input)
return int(digit[0])
def device_traversal():
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
for i in sorted(ALL_DEVICE.keys()):
print("============================================")
print(i.upper()+": ")
print("============================================")
for j in sorted(ALL_DEVICE[i].keys(), key=get_value):
print " "+j+":",
for k in (ALL_DEVICE[i][j]):
ret, log = log_os_system("cat "+k, 0)
func = k.split("/")[-1].strip()
func = re.sub(j+'_','',func,1)
func = re.sub(i.lower()+'_','',func,1)
if ret==0:
print func+"="+log+" ",
else:
print func+"="+"X"+" ",
print
print("----------------------------------------------------------------")
print
return
def device_exist():
ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0)
ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0)
return not(ret1 or ret2)
if __name__ == "__main__":
main()

View File

@ -32,3 +32,7 @@ Description: kernel modules for platform devices such as fan, led, sfp
Package: sonic-platform-accton-as7326-56x
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp
Package: sonic-platform-accton-as6712-32x
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x
MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service

View File