[Platform] Accton add to support as9726-32d platform. (#7479)
Add support for Accton as9726-32d platform This pull request is based on as9716-32d, so I reference as9716-32d to create new model: as9726-32d. This module do not need led driver to control led, FPGA can handle it. I also implement API2.0(sonic_platform) for this model, CPLD driver, PSU driver, Fan driver to control these HW behavior.
This commit is contained in:
parent
b64a6402d0
commit
a070f1a239
@ -0,0 +1,35 @@
|
|||||||
|
# name lanes alias index speed
|
||||||
|
Ethernet1 73,74,75,76,77,78,79,80 fourHundredGigE1 1 400000
|
||||||
|
Ethernet2 65,66,67,68,69,70,71,72 fourHundredGigE2 2 400000
|
||||||
|
Ethernet3 81,82,83,84,85,86,87,88 fourHundredGigE3 3 400000
|
||||||
|
Ethernet4 89,90,91,92,93,94,95,96 fourHundredGigE4 4 400000
|
||||||
|
Ethernet5 97,98,99,100,101,102,103,104 fourHundredGigE5 5 400000
|
||||||
|
Ethernet6 105,106,107,108,109,110,111,112 fourHundredGigE6 6 400000
|
||||||
|
Ethernet7 113,114,115,116,117,118,119,120 fourHundredGigE7 7 400000
|
||||||
|
Ethernet8 121,122,123,124,125,126,127,128 fourHundredGigE8 8 400000
|
||||||
|
Ethernet9 41,42,43,44,45,46,47,48 fourHundredGigE9 9 400000
|
||||||
|
Ethernet10 33,34,35,36,37,38,39,40 fourHundredGigE10 10 400000
|
||||||
|
Ethernet11 49,50,51,52,53,54,55,56 fourHundredGigE11 11 400000
|
||||||
|
Ethernet12 57,58,59,60,61,62,63,64 fourHundredGigE12 12 400000
|
||||||
|
Ethernet13 129,130,131,132,133,134,135,136 fourHundredGigE13 13 400000
|
||||||
|
Ethernet14 137,138,139,140,141,142,143,144 fourHundredGigE14 14 400000
|
||||||
|
Ethernet15 145,146,147,148,149,150,151,152 fourHundredGigE15 15 400000
|
||||||
|
Ethernet16 153,154,155,156,157,158,159,160 fourHundredGigE16 16 400000
|
||||||
|
Ethernet17 169,170,171,172,173,174,175,176 fourHundredGigE17 17 400000
|
||||||
|
Ethernet18 161,162,163,164,165,166,167,168 fourHundredGigE18 18 400000
|
||||||
|
Ethernet19 177,178,179,180,181,182,183,184 fourHundredGigE19 19 400000
|
||||||
|
Ethernet20 185,186,187,188,189,190,191,192 fourHundredGigE20 20 400000
|
||||||
|
Ethernet21 1,2,3,4,5,6,7,8 fourHundredGigE21 21 400000
|
||||||
|
Ethernet22 9,10,11,12,13,14,15,16 fourHundredGigE22 22 400000
|
||||||
|
Ethernet23 17,18,19,20,21,22,23,24 fourHundredGigE23 23 400000
|
||||||
|
Ethernet24 25,26,27,28,29,30,31,32 fourHundredGigE24 24 400000
|
||||||
|
Ethernet25 201,202,203,204,205,206,207,208 fourHundredGigE25 25 400000
|
||||||
|
Ethernet26 193,194,195,196,197,198,199,200 fourHundredGigE26 26 400000
|
||||||
|
Ethernet27 217,218,219,220,221,222,223,224 fourHundredGigE27 27 400000
|
||||||
|
Ethernet28 209,210,211,212,213,214,215,216 fourHundredGigE28 28 400000
|
||||||
|
Ethernet29 233,234,235,236,237,238,239,240 fourHundredGigE29 29 400000
|
||||||
|
Ethernet30 225,226,227,228,229,230,231,232 fourHundredGigE30 30 400000
|
||||||
|
Ethernet31 249,250,251,252,253,254,255,256 fourHundredGigE31 31 400000
|
||||||
|
Ethernet32 241,242,243,244,245,246,247,248 fourHundredGigE32 32 400000
|
||||||
|
Ethernet33 249 tenGigE33 33 10000
|
||||||
|
Ethernet34 250 tenGigE34 34 10000
|
1
device/accton/x86_64-accton_as9726_32d-r0/default_sku
Normal file
1
device/accton/x86_64-accton_as9726_32d-r0/default_sku
Normal file
@ -0,0 +1 @@
|
|||||||
|
Accton-AS9726-32D t1
|
3
device/accton/x86_64-accton_as9726_32d-r0/installer.conf
Normal file
3
device/accton/x86_64-accton_as9726_32d-r0/installer.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
CONSOLE_PORT=0x3f8
|
||||||
|
CONSOLE_DEV=0
|
||||||
|
CONSOLE_SPEED=115200
|
13
device/accton/x86_64-accton_as9726_32d-r0/plugins/eeprom.py
Executable file
13
device/accton/x86_64-accton_as9726_32d-r0/plugins/eeprom.py
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
try:
|
||||||
|
from sonic_eeprom import eeprom_tlvinfo
|
||||||
|
|
||||||
|
except ImportError as 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"
|
||||||
|
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
61
device/accton/x86_64-accton_as9726_32d-r0/plugins/psuutil.py
Executable file
61
device/accton/x86_64-accton_as9726_32d-r0/plugins/psuutil.py
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC PSU Base API and
|
||||||
|
# provides the PSUs status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
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: "9-0050",
|
||||||
|
2: "9-0051",
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
293
device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py
Executable file
293
device/accton/x86_64-accton_as9726_32d-r0/plugins/sfputil.py
Executable file
@ -0,0 +1,293 @@
|
|||||||
|
# sfputil.py
|
||||||
|
#
|
||||||
|
# Platform-specific SFP transceiver interface for SONiC
|
||||||
|
#
|
||||||
|
|
||||||
|
try:
|
||||||
|
import time
|
||||||
|
from ctypes import create_string_buffer
|
||||||
|
from sonic_sfp.sfputilbase import SfpUtilBase
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError("%s - required module not found" % str(e))
|
||||||
|
|
||||||
|
|
||||||
|
class SfpUtil(SfpUtilBase):
|
||||||
|
"""Platform-specific SfpUtil class"""
|
||||||
|
|
||||||
|
PORT_START = 1
|
||||||
|
QSFP_PORT_END = 32
|
||||||
|
PORT_END = 34
|
||||||
|
PORTS_IN_BLOCK = 34
|
||||||
|
|
||||||
|
BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
|
||||||
|
BASE_CPLD2_PATH = "/sys/bus/i2c/devices/10-0061/"
|
||||||
|
BASE_CPLD3_PATH = "/sys/bus/i2c/devices/10-0062/"
|
||||||
|
|
||||||
|
_port_to_is_present = {}
|
||||||
|
_port_to_lp_mode = {}
|
||||||
|
|
||||||
|
_port_to_eeprom_mapping = {}
|
||||||
|
_port_to_i2c_mapping = {
|
||||||
|
1: 17,
|
||||||
|
2: 18,
|
||||||
|
3: 19,
|
||||||
|
4: 20,
|
||||||
|
5: 21,
|
||||||
|
6: 22,
|
||||||
|
7: 23,
|
||||||
|
8: 24,
|
||||||
|
9: 25,
|
||||||
|
10: 26,
|
||||||
|
11: 27,
|
||||||
|
12: 28,
|
||||||
|
13: 29,
|
||||||
|
14: 30,
|
||||||
|
15: 31,
|
||||||
|
16: 32,
|
||||||
|
17: 33,
|
||||||
|
18: 34,
|
||||||
|
19: 35,
|
||||||
|
20: 36,
|
||||||
|
21: 37,
|
||||||
|
22: 38,
|
||||||
|
23: 39,
|
||||||
|
24: 40,
|
||||||
|
25: 41,
|
||||||
|
26: 42,
|
||||||
|
27: 43,
|
||||||
|
28: 44,
|
||||||
|
29: 45,
|
||||||
|
30: 46,
|
||||||
|
31: 47,
|
||||||
|
32: 48,
|
||||||
|
33: 49,
|
||||||
|
34: 50,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_start(self):
|
||||||
|
return self.PORT_START
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_end(self):
|
||||||
|
return self.PORT_END
|
||||||
|
|
||||||
|
@property
|
||||||
|
def qsfp_ports(self):
|
||||||
|
return list(range(self.PORT_START, self.PORTS_IN_BLOCK - 1))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_to_eeprom_mapping(self):
|
||||||
|
return self._port_to_eeprom_mapping
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
eeprom_path = self.BASE_OOM_PATH + "eeprom"
|
||||||
|
|
||||||
|
for x in range(self.port_start, self.port_end+1):
|
||||||
|
self.port_to_eeprom_mapping[x] = eeprom_path.format(
|
||||||
|
self._port_to_i2c_mapping[x]
|
||||||
|
)
|
||||||
|
|
||||||
|
SfpUtilBase.__init__(self)
|
||||||
|
|
||||||
|
def __write_txt_file(self, file_path, value):
|
||||||
|
try:
|
||||||
|
reg_file = open(file_path, "w")
|
||||||
|
except IOError as e:
|
||||||
|
print("Error: unable to open file: %s" % str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
reg_file.write(str(value))
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_presence(self, port_num):
|
||||||
|
if port_num <= 16:
|
||||||
|
present_path = self.BASE_CPLD2_PATH + "module_present_" + str(port_num)
|
||||||
|
else:
|
||||||
|
present_path = self.BASE_CPLD3_PATH + "module_present_" + str(port_num)
|
||||||
|
self.__port_to_is_present = present_path
|
||||||
|
|
||||||
|
try:
|
||||||
|
val_file = open(present_path)
|
||||||
|
content = val_file.readline().rstrip()
|
||||||
|
val_file.close()
|
||||||
|
except IOError as e:
|
||||||
|
print("Error: unable to access file: %s" % str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if content == "1":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_low_power_mode(self, port_num):
|
||||||
|
if port_num > self.QSFP_PORT_END: #sfp not support lpmode
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
eeprom = None
|
||||||
|
|
||||||
|
if not self.get_presence(port_num):
|
||||||
|
return False
|
||||||
|
|
||||||
|
eeprom = open(self.port_to_eeprom_mapping[port_num], "rb")
|
||||||
|
eeprom.seek(93)
|
||||||
|
lpmode = ord(eeprom.read(1))
|
||||||
|
|
||||||
|
if ((lpmode & 0x3) == 0x3):
|
||||||
|
return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1
|
||||||
|
else:
|
||||||
|
# High Power Mode if one of the following conditions is matched:
|
||||||
|
# 1. "Power override" bit is 0
|
||||||
|
# 2. "Power override" bit is 1 and "Power set" bit is 0
|
||||||
|
return False
|
||||||
|
except IOError as e:
|
||||||
|
print("Error: unable to open file: %s" % str(e))
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if eeprom is not None:
|
||||||
|
eeprom.close()
|
||||||
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
def set_low_power_mode(self, port_num, lpmode):
|
||||||
|
# Check for invalid port_num
|
||||||
|
if port_num > self.QSFP_PORT_END: #sfp not support lpmode:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
eeprom = None
|
||||||
|
if not self.get_presence(port_num):
|
||||||
|
return False # Port is not present, unable to set the eeprom
|
||||||
|
|
||||||
|
# Fill in write buffer
|
||||||
|
# 0x3:Low Power Mode. "Power override" bit is 1 and "Power set" bit is 1
|
||||||
|
# 0x9:High Power Mode. "Power override" bit is 1 ,"Power set" bit is 0 and "High Power Class Enable" bit is 1
|
||||||
|
regval = 0x3 if lpmode else 0x9
|
||||||
|
|
||||||
|
buffer = create_string_buffer(1)
|
||||||
|
buffer[0] = regval
|
||||||
|
|
||||||
|
# Write to eeprom
|
||||||
|
eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b")
|
||||||
|
eeprom.seek(93)
|
||||||
|
eeprom.write(buffer[0])
|
||||||
|
return True
|
||||||
|
except IOError as e:
|
||||||
|
print("Error: unable to open file: %s" % str(e))
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if eeprom is not None:
|
||||||
|
eeprom.close()
|
||||||
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
def reset(self, port_num):
|
||||||
|
if port_num > self.QSFP_PORT_END: #sfp not support lpmode:
|
||||||
|
return False
|
||||||
|
if not self.get_presence(port_num):
|
||||||
|
return False # Port is not present, unable to set reset
|
||||||
|
|
||||||
|
if port_num < 16:
|
||||||
|
mod_rst_path = self.BASE_CPLD2_PATH + "module_reset_" + str(port_num)
|
||||||
|
else:
|
||||||
|
mod_rst_path = self.BASE_CPLD3_PATH + "module_reset_" + str(port_num)
|
||||||
|
|
||||||
|
self.__port_to_mod_rst = mod_rst_path
|
||||||
|
|
||||||
|
ret = self.__write_txt_file(self.__port_to_mod_rst, 1)
|
||||||
|
if ret is not True:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
time.sleep(0.2)
|
||||||
|
ret = self.__write_txt_file(self.__port_to_mod_rst, 0)
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_cpld_interrupt(self):
|
||||||
|
port_dict = {}
|
||||||
|
for i in range(0, 4):
|
||||||
|
if i == 0 or i == 1:
|
||||||
|
cpld_i2c_path = self.BASE_CPLD2_PATH + "cpld_intr_" + str(i+1)
|
||||||
|
else:
|
||||||
|
cpld_i2c_path = self.BASE_CPLD3_PATH + "cpld_intr_" + str(i+1)
|
||||||
|
|
||||||
|
start_i = (i*8)
|
||||||
|
end_i = (i*8+8)
|
||||||
|
try:
|
||||||
|
val_file = open(cpld_i2c_path)
|
||||||
|
except IOError as e:
|
||||||
|
print("Error: unable to open file: %s" % str(e))
|
||||||
|
|
||||||
|
for k in range(start_i, end_i):
|
||||||
|
port_dict[k] = 0
|
||||||
|
return port_dict
|
||||||
|
|
||||||
|
status = val_file.readline().rstrip()
|
||||||
|
val_file.close()
|
||||||
|
status = status.strip()
|
||||||
|
status = int(status, 16)
|
||||||
|
|
||||||
|
interrupt_status = ~(status & 0xff)
|
||||||
|
if interrupt_status:
|
||||||
|
port_shift = 0
|
||||||
|
for k in range(start_i, end_i):
|
||||||
|
if interrupt_status & (0x1 << port_shift):
|
||||||
|
port_dict[k] = 1
|
||||||
|
else:
|
||||||
|
port_dict[k] = 0
|
||||||
|
port_shift = port_shift+1
|
||||||
|
|
||||||
|
return port_dict
|
||||||
|
|
||||||
|
def get_transceiver_change_event(self, timeout=0):
|
||||||
|
start_time = time.time()
|
||||||
|
port_dict = {}
|
||||||
|
forever = False
|
||||||
|
|
||||||
|
if timeout == 0:
|
||||||
|
forever = True
|
||||||
|
elif timeout > 0:
|
||||||
|
timeout = timeout / float(1000) # Convert to secs
|
||||||
|
else:
|
||||||
|
print("get_transceiver_change_event:Invalid timeout value", timeout)
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
end_time = start_time + timeout
|
||||||
|
if start_time > end_time:
|
||||||
|
print('get_transceiver_change_event:'
|
||||||
|
'time wrap / invalid timeout value', timeout)
|
||||||
|
|
||||||
|
return False, {} # Time wrap or possibly incorrect timeout
|
||||||
|
|
||||||
|
# for i in range(self.port_start, self.port_end+1):
|
||||||
|
# ori_present[i]=self.get_presence(i)
|
||||||
|
|
||||||
|
while timeout >= 0:
|
||||||
|
change_status = 0
|
||||||
|
|
||||||
|
port_dict = self.get_cpld_interrupt()
|
||||||
|
present = 0
|
||||||
|
for key, value in port_dict.items():
|
||||||
|
if value == 1:
|
||||||
|
present = self.get_presence(key)
|
||||||
|
change_status = 1
|
||||||
|
if present:
|
||||||
|
port_dict[key] = '1'
|
||||||
|
else:
|
||||||
|
port_dict[key] = '0'
|
||||||
|
|
||||||
|
if change_status:
|
||||||
|
return True, port_dict
|
||||||
|
if forever:
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
timeout = end_time - time.time()
|
||||||
|
if timeout >= 1:
|
||||||
|
time.sleep(1) # We poll at 1 second granularity
|
||||||
|
else:
|
||||||
|
if timeout > 0:
|
||||||
|
time.sleep(timeout)
|
||||||
|
return True, {}
|
||||||
|
print("get_evt_change_event: Should not reach here.")
|
||||||
|
return False, {}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"skip_ledd": true,
|
||||||
|
"skip_thermalctld": true
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan']
|
||||||
|
from . import platform
|
@ -0,0 +1,201 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the Chassis information which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.chassis_base import ChassisBase
|
||||||
|
from .helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
NUM_FAN_TRAY = 6
|
||||||
|
NUM_FAN = 2
|
||||||
|
NUM_PSU = 2
|
||||||
|
NUM_THERMAL = 3
|
||||||
|
NUM_QSFP = 32
|
||||||
|
PORT_START = 1
|
||||||
|
PORT_END = 34
|
||||||
|
QSFP_PORT_START = 0
|
||||||
|
QSFP_PORT_END = 31
|
||||||
|
NUM_COMPONENT = 2
|
||||||
|
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||||
|
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||||
|
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||||
|
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||||
|
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||||
|
|
||||||
|
|
||||||
|
class Chassis(ChassisBase):
|
||||||
|
"""Platform-specific Chassis class"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
ChassisBase.__init__(self)
|
||||||
|
self._api_helper = APIHelper()
|
||||||
|
self.is_host = self._api_helper.is_host()
|
||||||
|
|
||||||
|
self.config_data = {}
|
||||||
|
|
||||||
|
self.__initialize_fan()
|
||||||
|
self.__initialize_psu()
|
||||||
|
self.__initialize_thermals()
|
||||||
|
self.__initialize_components()
|
||||||
|
self.__initialize_sfp()
|
||||||
|
self.__initialize_eeprom()
|
||||||
|
|
||||||
|
def __initialize_sfp(self):
|
||||||
|
from sonic_platform.sfp import Sfp
|
||||||
|
|
||||||
|
self.QSFP_PORT_START = QSFP_PORT_START
|
||||||
|
self.QSFP_PORT_END = QSFP_PORT_END
|
||||||
|
for index in range(0, PORT_END):
|
||||||
|
if index in range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1):
|
||||||
|
sfp_module = Sfp(index, 'QSFP')
|
||||||
|
else:
|
||||||
|
sfp_module = Sfp(index, 'SFP')
|
||||||
|
self._sfp_list.append(sfp_module)
|
||||||
|
self.sfp_module_initialized = True
|
||||||
|
|
||||||
|
def __initialize_fan(self):
|
||||||
|
from sonic_platform.fan import Fan
|
||||||
|
for fant_index in range(0, NUM_FAN_TRAY):
|
||||||
|
for fan_index in range(0, NUM_FAN):
|
||||||
|
fan = Fan(fant_index, fan_index)
|
||||||
|
self._fan_list.append(fan)
|
||||||
|
|
||||||
|
def __initialize_psu(self):
|
||||||
|
from sonic_platform.psu import Psu
|
||||||
|
for index in range(0, NUM_PSU):
|
||||||
|
psu = Psu(index)
|
||||||
|
self._psu_list.append(psu)
|
||||||
|
|
||||||
|
def __initialize_thermals(self):
|
||||||
|
from sonic_platform.thermal import Thermal
|
||||||
|
for index in range(0, NUM_THERMAL):
|
||||||
|
thermal = Thermal(index)
|
||||||
|
self._thermal_list.append(thermal)
|
||||||
|
|
||||||
|
def __initialize_eeprom(self):
|
||||||
|
from sonic_platform.eeprom import Tlv
|
||||||
|
self._eeprom = Tlv()
|
||||||
|
|
||||||
|
def __initialize_components(self):
|
||||||
|
from sonic_platform.component import Component
|
||||||
|
for index in range(0, NUM_COMPONENT):
|
||||||
|
component = Component(index)
|
||||||
|
self._component_list.append(component)
|
||||||
|
|
||||||
|
def __initialize_watchdog(self):
|
||||||
|
from sonic_platform.watchdog import Watchdog
|
||||||
|
self._watchdog = Watchdog()
|
||||||
|
|
||||||
|
|
||||||
|
def __is_host(self):
|
||||||
|
return os.system(HOST_CHK_CMD) == 0
|
||||||
|
|
||||||
|
def __read_txt_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
return data.strip()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
"""
|
||||||
|
Retrieves the name of the device
|
||||||
|
Returns:
|
||||||
|
string: The name of the device
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._api_helper.hwsku
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
"""
|
||||||
|
Retrieves the presence of the Chassis
|
||||||
|
Returns:
|
||||||
|
bool: True if Chassis is present, False if not
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the operational status of the device
|
||||||
|
Returns:
|
||||||
|
A boolean value, True if device is operating properly, False if not
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_base_mac(self):
|
||||||
|
"""
|
||||||
|
Retrieves the base MAC address for the chassis
|
||||||
|
Returns:
|
||||||
|
A string containing the MAC address in the format
|
||||||
|
'XX:XX:XX:XX:XX:XX'
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_mac()
|
||||||
|
|
||||||
|
def get_serial_number(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware serial number for the chassis
|
||||||
|
Returns:
|
||||||
|
A string containing the hardware serial number for this chassis.
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_serial()
|
||||||
|
|
||||||
|
def get_system_eeprom_info(self):
|
||||||
|
"""
|
||||||
|
Retrieves the full content of system EEPROM information for the chassis
|
||||||
|
Returns:
|
||||||
|
A dictionary where keys are the type code defined in
|
||||||
|
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||||
|
values.
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_eeprom()
|
||||||
|
|
||||||
|
def get_reboot_cause(self):
|
||||||
|
"""
|
||||||
|
Retrieves the cause of the previous reboot
|
||||||
|
Returns:
|
||||||
|
A tuple (string, string) where the first element is a string
|
||||||
|
containing the cause of the previous reboot. This string must be
|
||||||
|
one of the predefined strings in this class. If the first string
|
||||||
|
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||||
|
to pass a description of the reboot cause.
|
||||||
|
"""
|
||||||
|
|
||||||
|
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||||
|
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||||
|
reboot_cause_path) or "Unknown"
|
||||||
|
|
||||||
|
|
||||||
|
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
|
||||||
|
|
||||||
|
def get_sfp(self, index):
|
||||||
|
"""
|
||||||
|
Retrieves sfp represented by (1-based) index <index>
|
||||||
|
Args:
|
||||||
|
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||||
|
The index should be the sequence of a physical port in a chassis,
|
||||||
|
starting from 1.
|
||||||
|
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
|
||||||
|
Returns:
|
||||||
|
An object dervied from SfpBase representing the specified sfp
|
||||||
|
"""
|
||||||
|
sfp = None
|
||||||
|
if not self.sfp_module_initialized:
|
||||||
|
self.__initialize_sfp()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# The index will start from 1
|
||||||
|
sfp = self._sfp_list[index-1]
|
||||||
|
except IndexError:
|
||||||
|
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||||
|
index, len(self._sfp_list)))
|
||||||
|
return sfp
|
@ -0,0 +1,121 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Component contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the components firmware management function
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.component_base import ComponentBase
|
||||||
|
from .helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
CPLD_ADDR_MAPPING = {
|
||||||
|
"CPLD1": "3-0060"
|
||||||
|
}
|
||||||
|
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||||
|
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||||
|
COMPONENT_LIST= [
|
||||||
|
("CPLD1", "CPLD 1"),
|
||||||
|
("BIOS", "Basic Input/Output System")
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
class Component(ComponentBase):
|
||||||
|
"""Platform-specific Component class"""
|
||||||
|
|
||||||
|
DEVICE_TYPE = "component"
|
||||||
|
|
||||||
|
def __init__(self, component_index=0):
|
||||||
|
self._api_helper=APIHelper()
|
||||||
|
ComponentBase.__init__(self)
|
||||||
|
self.index = component_index
|
||||||
|
self.name = self.get_name()
|
||||||
|
|
||||||
|
def __run_command(self, command):
|
||||||
|
# Run bash command and print output to stdout
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
shlex.split(command), stdout=subprocess.PIPE)
|
||||||
|
while True:
|
||||||
|
output = process.stdout.readline()
|
||||||
|
if output == '' and process.poll() is not None:
|
||||||
|
break
|
||||||
|
rc = process.poll()
|
||||||
|
if rc != 0:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __get_bios_version(self):
|
||||||
|
# Retrieves the BIOS firmware version
|
||||||
|
try:
|
||||||
|
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||||
|
bios_version = fd.read()
|
||||||
|
return bios_version.strip()
|
||||||
|
except Exception as e:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __get_cpld_version(self):
|
||||||
|
# Retrieves the CPLD firmware version
|
||||||
|
cpld_version = dict()
|
||||||
|
for cpld_name in CPLD_ADDR_MAPPING:
|
||||||
|
try:
|
||||||
|
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
|
||||||
|
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
|
||||||
|
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
|
||||||
|
except Exception as e:
|
||||||
|
print('Get exception when read cpld')
|
||||||
|
cpld_version[cpld_name] = 'None'
|
||||||
|
|
||||||
|
return cpld_version
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
"""
|
||||||
|
Retrieves the name of the component
|
||||||
|
Returns:
|
||||||
|
A string containing the name of the component
|
||||||
|
"""
|
||||||
|
return COMPONENT_LIST[self.index][0]
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
"""
|
||||||
|
Retrieves the description of the component
|
||||||
|
Returns:
|
||||||
|
A string containing the description of the component
|
||||||
|
"""
|
||||||
|
return COMPONENT_LIST[self.index][1]
|
||||||
|
|
||||||
|
|
||||||
|
def get_firmware_version(self):
|
||||||
|
"""
|
||||||
|
Retrieves the firmware version of module
|
||||||
|
Returns:
|
||||||
|
string: The firmware versions of the module
|
||||||
|
"""
|
||||||
|
fw_version = None
|
||||||
|
|
||||||
|
if self.name == "BIOS":
|
||||||
|
fw_version = self.__get_bios_version()
|
||||||
|
elif "CPLD" in self.name:
|
||||||
|
cpld_version = self.__get_cpld_version()
|
||||||
|
fw_version = cpld_version.get(self.name)
|
||||||
|
|
||||||
|
return fw_version
|
||||||
|
|
||||||
|
def install_firmware(self, image_path):
|
||||||
|
"""
|
||||||
|
Install firmware to module
|
||||||
|
Args:
|
||||||
|
image_path: A string, path to firmware image
|
||||||
|
Returns:
|
||||||
|
A boolean, True if install successfully, False if not
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
@ -0,0 +1,102 @@
|
|||||||
|
try:
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
from io import StringIO
|
||||||
|
else:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
|
||||||
|
CACHE_FILE = 'syseeprom_cache'
|
||||||
|
|
||||||
|
|
||||||
|
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
|
||||||
|
|
||||||
|
EEPROM_DECODE_HEADLINES = 6
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
|
||||||
|
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||||
|
self._eeprom = self._load_eeprom()
|
||||||
|
|
||||||
|
def __parse_output(self, decode_output):
|
||||||
|
decode_output.replace('\0', '')
|
||||||
|
lines = decode_output.split('\n')
|
||||||
|
lines = lines[self.EEPROM_DECODE_HEADLINES:]
|
||||||
|
_eeprom_info_dict = dict()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
try:
|
||||||
|
match = re.search(
|
||||||
|
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
|
||||||
|
if match is not None:
|
||||||
|
idx = match.group(1)
|
||||||
|
value = match.group(3).rstrip('\0')
|
||||||
|
|
||||||
|
_eeprom_info_dict[idx] = value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return _eeprom_info_dict
|
||||||
|
|
||||||
|
def _load_eeprom(self):
|
||||||
|
original_stdout = sys.stdout
|
||||||
|
sys.stdout = StringIO()
|
||||||
|
try:
|
||||||
|
self.read_eeprom_db()
|
||||||
|
except Exception:
|
||||||
|
decode_output = sys.stdout.getvalue()
|
||||||
|
sys.stdout = original_stdout
|
||||||
|
return self.__parse_output(decode_output)
|
||||||
|
|
||||||
|
status = self.check_status()
|
||||||
|
if 'ok' not in status:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.exists(CACHE_ROOT):
|
||||||
|
try:
|
||||||
|
os.makedirs(CACHE_ROOT)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#
|
||||||
|
# only the eeprom classes that inherit from eeprom_base
|
||||||
|
# support caching. Others will work normally
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
e = self.read_eeprom()
|
||||||
|
if e is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.update_cache(e)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.decode_eeprom(e)
|
||||||
|
decode_output = sys.stdout.getvalue()
|
||||||
|
sys.stdout = original_stdout
|
||||||
|
|
||||||
|
(is_valid, valid_crc) = self.is_checksum_valid(e)
|
||||||
|
if not is_valid:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.__parse_output(decode_output)
|
||||||
|
|
||||||
|
def get_eeprom(self):
|
||||||
|
return self._eeprom
|
||||||
|
|
||||||
|
def get_serial(self):
|
||||||
|
return self._eeprom.get('0x23', "Undefined.")
|
||||||
|
|
||||||
|
def get_mac(self):
|
||||||
|
return self._eeprom.get('0x24', "Undefined.")
|
171
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py
Normal file
171
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/fan.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the fan status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.fan_base import FanBase
|
||||||
|
from .helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
PSU_FAN_MAX_RPM = 26688
|
||||||
|
|
||||||
|
CPLD_I2C_PATH = "/sys/bus/i2c/devices/14-0066/fan_"
|
||||||
|
PSU_HWMON_I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
|
||||||
|
PSU_I2C_MAPPING = {
|
||||||
|
0: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "58"
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "59"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Fan(FanBase):
|
||||||
|
"""Platform-specific Fan class"""
|
||||||
|
|
||||||
|
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||||
|
self._api_helper=APIHelper()
|
||||||
|
self.fan_index = fan_index
|
||||||
|
self.fan_tray_index = fan_tray_index
|
||||||
|
self.is_psu_fan = is_psu_fan
|
||||||
|
|
||||||
|
if self.is_psu_fan:
|
||||||
|
self.psu_index = psu_index
|
||||||
|
self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]['num']
|
||||||
|
self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]['addr']
|
||||||
|
self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format(
|
||||||
|
self.psu_i2c_num, self.psu_i2c_addr)
|
||||||
|
|
||||||
|
FanBase.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
|
def get_direction(self):
|
||||||
|
"""
|
||||||
|
Retrieves the direction of fan
|
||||||
|
Returns:
|
||||||
|
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||||
|
depending on fan direction
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
if not self.is_psu_fan:
|
||||||
|
dir_str = "{}{}{}".format(CPLD_I2C_PATH, 'direction_', self.fan_tray_index)
|
||||||
|
val=self._api_helper.read_txt_file(dir_str)
|
||||||
|
if val is not None:
|
||||||
|
if val==0:#F2B
|
||||||
|
direction=self.FAN_DIRECTION_EXHAUST
|
||||||
|
else:
|
||||||
|
direction=self.FAN_DIRECTION_INTAKE
|
||||||
|
else:
|
||||||
|
direction=self.FAN_DIRECTION_EXHAUST
|
||||||
|
|
||||||
|
else: #For PSU
|
||||||
|
dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir')
|
||||||
|
val=self._api_helper.read_txt_file(dir_str)
|
||||||
|
if val is not None:
|
||||||
|
if val=='F2B':
|
||||||
|
direction=self.FAN_DIRECTION_EXHAUST
|
||||||
|
else:
|
||||||
|
direction=self.FAN_DIRECTION_INTAKE
|
||||||
|
else:
|
||||||
|
direction=self.FAN_DIRECTION_EXHAUST
|
||||||
|
|
||||||
|
return direction
|
||||||
|
|
||||||
|
def get_speed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the speed of fan as a percentage of full speed
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||||
|
to 100 (full speed)
|
||||||
|
|
||||||
|
"""
|
||||||
|
speed = 0
|
||||||
|
if self.is_psu_fan:
|
||||||
|
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
|
||||||
|
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
|
||||||
|
if fan_speed_rpm is not None:
|
||||||
|
speed = (int(fan_speed_rpm,10))*100/26688
|
||||||
|
if speed > 100:
|
||||||
|
speed=100
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
elif self.get_presence():
|
||||||
|
speed_path = "{}{}".format(CPLD_I2C_PATH, 'duty_cycle_percentage')
|
||||||
|
speed=self._api_helper.read_txt_file(speed_path)
|
||||||
|
if speed is None:
|
||||||
|
return 0
|
||||||
|
return int(speed)
|
||||||
|
|
||||||
|
def get_target_speed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the target (expected) speed of the fan
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||||
|
to 100 (full speed)
|
||||||
|
Note:
|
||||||
|
speed_pc = pwm_target/255*100
|
||||||
|
0 : when PWM mode is use
|
||||||
|
pwm : when pwm mode is not use
|
||||||
|
"""
|
||||||
|
return False #Not supported
|
||||||
|
|
||||||
|
def get_speed_tolerance(self):
|
||||||
|
"""
|
||||||
|
Retrieves the speed tolerance of the fan
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of variance from target speed which is
|
||||||
|
considered tolerable
|
||||||
|
"""
|
||||||
|
return False #Not supported
|
||||||
|
|
||||||
|
def set_speed(self, speed):
|
||||||
|
"""
|
||||||
|
Sets the fan speed
|
||||||
|
Args:
|
||||||
|
speed: An integer, the percentage of full fan speed to set fan to,
|
||||||
|
in the range 0 (off) to 100 (full speed)
|
||||||
|
Returns:
|
||||||
|
A boolean, True if speed is set successfully, False if not
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.is_psu_fan and self.get_presence():
|
||||||
|
speed_path = "{}{}".format(CPLD_I2C_PATH, 'duty_cycle_percentage')
|
||||||
|
return self._api_helper.write_txt_file(speed_path, int(speed))
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_status_led(self, color):
|
||||||
|
"""
|
||||||
|
Sets the state of the fan module status LED
|
||||||
|
Args:
|
||||||
|
color: A string representing the color with which to set the
|
||||||
|
fan module status LED
|
||||||
|
Returns:
|
||||||
|
bool: True if status LED state is set successfully, False if not
|
||||||
|
"""
|
||||||
|
return False #Not supported
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
"""
|
||||||
|
Retrieves the presence of the FAN
|
||||||
|
Returns:
|
||||||
|
bool: True if FAN is present, False if not
|
||||||
|
"""
|
||||||
|
present_path = "{}{}{}".format(CPLD_I2C_PATH, 'present_', self.fan_index+1)
|
||||||
|
val=self._api_helper.read_txt_file(present_path)
|
||||||
|
if not self.is_psu_fan:
|
||||||
|
if val is not None:
|
||||||
|
return int(val, 10)==1
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
@ -0,0 +1,117 @@
|
|||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
from mmap import *
|
||||||
|
from sonic_py_common import device_info
|
||||||
|
|
||||||
|
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||||
|
EMPTY_STRING = ""
|
||||||
|
|
||||||
|
|
||||||
|
class APIHelper():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
|
||||||
|
|
||||||
|
def is_host(self):
|
||||||
|
return os.system(HOST_CHK_CMD) == 0
|
||||||
|
|
||||||
|
def pci_get_value(self, resource, offset):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
fd = os.open(resource, os.O_RDWR)
|
||||||
|
mm = mmap(fd, 0)
|
||||||
|
mm.seek(int(offset))
|
||||||
|
read_data_stream = mm.read(4)
|
||||||
|
result = struct.unpack('I', read_data_stream)
|
||||||
|
except Exception:
|
||||||
|
status = False
|
||||||
|
return status, result
|
||||||
|
|
||||||
|
def run_command(self, cmd):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
except Exception:
|
||||||
|
status = False
|
||||||
|
return status, result
|
||||||
|
|
||||||
|
def run_interactive_command(self, cmd):
|
||||||
|
try:
|
||||||
|
os.system(cmd)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def read_txt_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
return data.strip()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def write_txt_file(self, file_path, value):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'w') as fd:
|
||||||
|
fd.write(str(value))
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ipmi_raw(self, netfn, cmd):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
else:
|
||||||
|
status = False
|
||||||
|
except Exception:
|
||||||
|
status = False
|
||||||
|
return status, result
|
||||||
|
|
||||||
|
def ipmi_fru_id(self, id, key=None):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
cmd = "ipmitool fru print {}".format(str(
|
||||||
|
id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key))
|
||||||
|
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
else:
|
||||||
|
status = False
|
||||||
|
except Exception:
|
||||||
|
status = False
|
||||||
|
return status, result
|
||||||
|
|
||||||
|
def ipmi_set_ss_thres(self, id, threshold_key, value):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value))
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
else:
|
||||||
|
status = False
|
||||||
|
except Exception:
|
||||||
|
status = False
|
||||||
|
return status, result
|
@ -0,0 +1,21 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the platform information
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.platform_base import PlatformBase
|
||||||
|
from sonic_platform.chassis import Chassis
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class Platform(PlatformBase):
|
||||||
|
"""Platform-specific Platform class"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
PlatformBase.__init__(self)
|
||||||
|
self._chassis = Chassis()
|
226
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py
Normal file
226
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/psu.py
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the PSUs status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.psu_base import PsuBase
|
||||||
|
#from sonic_platform.fan import Fan
|
||||||
|
from .helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/"
|
||||||
|
|
||||||
|
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
||||||
|
PSU_NUM_FAN = [1, 1]
|
||||||
|
PSU_HWMON_I2C_MAPPING = {
|
||||||
|
0: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "58"
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "59"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
PSU_CPLD_I2C_MAPPING = {
|
||||||
|
0: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "50"
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
"num": 9,
|
||||||
|
"addr": "51"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class Psu(PsuBase):
|
||||||
|
"""Platform-specific Psu class"""
|
||||||
|
|
||||||
|
def __init__(self, psu_index=0):
|
||||||
|
PsuBase.__init__(self)
|
||||||
|
self.index = psu_index
|
||||||
|
self._api_helper = APIHelper()
|
||||||
|
|
||||||
|
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
|
||||||
|
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
|
||||||
|
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||||
|
|
||||||
|
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
|
||||||
|
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
|
||||||
|
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||||
|
self.__initialize_fan()
|
||||||
|
'''
|
||||||
|
for fan_index in range(0, PSU_NUM_FAN[self.index]):
|
||||||
|
#def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||||
|
#fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
|
||||||
|
fan = Fan(fan_index, 0, True, self.index)
|
||||||
|
self._fan_list.append(fan)
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __initialize_fan(self):
|
||||||
|
from sonic_platform.fan import Fan
|
||||||
|
for fan_index in range(0, PSU_NUM_FAN[self.index]):
|
||||||
|
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
|
||||||
|
self._fan_list.append(fan)
|
||||||
|
|
||||||
|
def get_voltage(self):
|
||||||
|
"""
|
||||||
|
Retrieves current PSU voltage output
|
||||||
|
Returns:
|
||||||
|
A float number, the output voltage in volts,
|
||||||
|
e.g. 12.1
|
||||||
|
"""
|
||||||
|
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
|
||||||
|
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||||
|
if vout_val is not None:
|
||||||
|
return float(vout_val)/ 1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_current(self):
|
||||||
|
"""
|
||||||
|
Retrieves present electric current supplied by PSU
|
||||||
|
Returns:
|
||||||
|
A float number, the electric current in amperes, e.g 15.4
|
||||||
|
"""
|
||||||
|
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
|
||||||
|
val=self._api_helper.read_txt_file(iout_path)
|
||||||
|
if val is not None:
|
||||||
|
return float(val)/1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_power(self):
|
||||||
|
"""
|
||||||
|
Retrieves current energy supplied by PSU
|
||||||
|
Returns:
|
||||||
|
A float number, the power in watts, e.g. 302.6
|
||||||
|
"""
|
||||||
|
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
|
||||||
|
val=self._api_helper.read_txt_file(pout_path)
|
||||||
|
if val is not None:
|
||||||
|
return float(val)/1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_powergood_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the powergood status of PSU
|
||||||
|
Returns:
|
||||||
|
A boolean, True if PSU has stablized its output voltages and passed all
|
||||||
|
its internal self-tests, False if not.
|
||||||
|
"""
|
||||||
|
return self.get_status()
|
||||||
|
|
||||||
|
def set_status_led(self, color):
|
||||||
|
"""
|
||||||
|
Sets the state of the PSU status LED
|
||||||
|
Args:
|
||||||
|
color: A string representing the color with which to set the PSU status LED
|
||||||
|
Note: Only support green and off
|
||||||
|
Returns:
|
||||||
|
bool: True if status LED state is set successfully, False if not
|
||||||
|
"""
|
||||||
|
|
||||||
|
return False #Controlled by HW
|
||||||
|
|
||||||
|
def get_status_led(self):
|
||||||
|
"""
|
||||||
|
Gets the state of the PSU status LED
|
||||||
|
Returns:
|
||||||
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||||
|
"""
|
||||||
|
|
||||||
|
return False #Controlled by HW
|
||||||
|
|
||||||
|
def get_temperature(self):
|
||||||
|
"""
|
||||||
|
Retrieves current temperature reading from PSU
|
||||||
|
Returns:
|
||||||
|
A float number of current temperature in Celsius up to nearest thousandth
|
||||||
|
of one degree Celsius, e.g. 30.125
|
||||||
|
"""
|
||||||
|
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
|
||||||
|
val=self._api_helper.read_txt_file(temp_path)
|
||||||
|
if val is not None:
|
||||||
|
return float(val)/1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_temperature_high_threshold(self):
|
||||||
|
"""
|
||||||
|
Retrieves the high threshold temperature of PSU
|
||||||
|
Returns:
|
||||||
|
A float number, the high threshold temperature of PSU in Celsius
|
||||||
|
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||||
|
"""
|
||||||
|
return False #Not supported
|
||||||
|
|
||||||
|
def get_voltage_high_threshold(self):
|
||||||
|
"""
|
||||||
|
Retrieves the high threshold PSU voltage output
|
||||||
|
Returns:
|
||||||
|
A float number, the high threshold output voltage in volts,
|
||||||
|
e.g. 12.1
|
||||||
|
"""
|
||||||
|
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
|
||||||
|
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||||
|
if vout_val is not None:
|
||||||
|
return float(vout_val)/ 1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_voltage_low_threshold(self):
|
||||||
|
"""
|
||||||
|
Retrieves the low threshold PSU voltage output
|
||||||
|
Returns:
|
||||||
|
A float number, the low threshold output voltage in volts,
|
||||||
|
e.g. 12.1
|
||||||
|
"""
|
||||||
|
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
|
||||||
|
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||||
|
if vout_val is not None:
|
||||||
|
return float(vout_val)/ 1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
"""
|
||||||
|
Retrieves the name of the device
|
||||||
|
Returns:
|
||||||
|
string: The name of the device
|
||||||
|
"""
|
||||||
|
return PSU_NAME_LIST[self.index]
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
"""
|
||||||
|
Retrieves the presence of the PSU
|
||||||
|
Returns:
|
||||||
|
bool: True if PSU is present, False if not
|
||||||
|
"""
|
||||||
|
presence_path="{}{}".format(self.cpld_path, 'psu_present')
|
||||||
|
val=self._api_helper.read_txt_file(presence_path)
|
||||||
|
if val is not None:
|
||||||
|
return int(val, 10) == 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the operational status of the device
|
||||||
|
Returns:
|
||||||
|
A boolean value, True if device is operating properly, False if not
|
||||||
|
"""
|
||||||
|
power_path="{}{}".format(self.cpld_path, 'psu_power_good')
|
||||||
|
val=self._api_helper.read_txt_file(power_path)
|
||||||
|
if val is not None:
|
||||||
|
return int(val, 10) == 1
|
||||||
|
else:
|
||||||
|
return 0
|
2221
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py
Normal file
2221
device/accton/x86_64-accton_as9726_32d-r0/sonic_platform/sfp.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,151 @@
|
|||||||
|
#############################################################################
|
||||||
|
# Accton
|
||||||
|
#
|
||||||
|
# Thermal contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the thermal device status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import glob
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.thermal_base import ThermalBase
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class Thermal(ThermalBase):
|
||||||
|
"""Platform-specific Thermal class"""
|
||||||
|
|
||||||
|
THERMAL_NAME_LIST = []
|
||||||
|
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||||
|
|
||||||
|
def __init__(self, thermal_index=0):
|
||||||
|
self.THERMAL_NAME_LIST = []
|
||||||
|
self.SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||||
|
self.index = thermal_index
|
||||||
|
# Add thermal name
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 1")
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 2")
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 3")
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 4")
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 5")
|
||||||
|
self.THERMAL_NAME_LIST.append("Temp sensor 6")
|
||||||
|
|
||||||
|
# Set hwmon path
|
||||||
|
i2c_path = {
|
||||||
|
0: "15-0048/hwmon/hwmon*/",
|
||||||
|
1: "15-0049/hwmon/hwmon*/",
|
||||||
|
2: "15-004a/hwmon/hwmon*/",
|
||||||
|
3: "15-004b/hwmon/hwmon*/",
|
||||||
|
4: "15-004c/hwmon/hwmon*/",
|
||||||
|
5: "15-004f/hwmon/hwmon*/"
|
||||||
|
}.get(self.index, None)
|
||||||
|
|
||||||
|
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
|
||||||
|
self.ss_key = self.THERMAL_NAME_LIST[self.index]
|
||||||
|
self.ss_index = 1
|
||||||
|
|
||||||
|
def __read_txt_file(self, file_path):
|
||||||
|
for filename in glob.glob(file_path):
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as fd:
|
||||||
|
data =fd.readline().rstrip()
|
||||||
|
return data
|
||||||
|
except IOError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __get_temp(self, temp_file):
|
||||||
|
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||||
|
raw_temp = self.__read_txt_file(temp_file_path)
|
||||||
|
if raw_temp is not None:
|
||||||
|
return float(raw_temp)/1000
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def __set_threshold(self, file_name, temperature):
|
||||||
|
temp_file_path = os.path.join(self.hwmon_path, file_name)
|
||||||
|
for filename in glob.glob(temp_file_path):
|
||||||
|
try:
|
||||||
|
with open(filename, 'w') as fd:
|
||||||
|
fd.write(str(temperature))
|
||||||
|
return True
|
||||||
|
except IOError as e:
|
||||||
|
print("IOError")
|
||||||
|
|
||||||
|
|
||||||
|
def get_temperature(self):
|
||||||
|
"""
|
||||||
|
Retrieves current temperature reading from thermal
|
||||||
|
Returns:
|
||||||
|
A float number of current temperature in Celsius up to nearest thousandth
|
||||||
|
of one degree Celsius, e.g. 30.125
|
||||||
|
"""
|
||||||
|
temp_file = "temp{}_input".format(self.ss_index)
|
||||||
|
return self.__get_temp(temp_file)
|
||||||
|
|
||||||
|
def get_high_threshold(self):
|
||||||
|
"""
|
||||||
|
Retrieves the high threshold temperature of thermal
|
||||||
|
Returns:
|
||||||
|
A float number, the high threshold temperature of thermal in Celsius
|
||||||
|
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||||
|
"""
|
||||||
|
temp_file = "temp{}_max".format(self.ss_index)
|
||||||
|
return self.__get_temp(temp_file)
|
||||||
|
|
||||||
|
def set_high_threshold(self, temperature):
|
||||||
|
"""
|
||||||
|
Sets the high threshold temperature of thermal
|
||||||
|
Args :
|
||||||
|
temperature: A float number up to nearest thousandth of one degree Celsius,
|
||||||
|
e.g. 30.125
|
||||||
|
Returns:
|
||||||
|
A boolean, True if threshold is set successfully, False if not
|
||||||
|
"""
|
||||||
|
temp_file = "temp{}_max".format(self.ss_index)
|
||||||
|
temperature = temperature *1000
|
||||||
|
self.__set_threshold(temp_file, temperature)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
"""
|
||||||
|
Retrieves the name of the thermal device
|
||||||
|
Returns:
|
||||||
|
string: The name of the thermal device
|
||||||
|
"""
|
||||||
|
return self.THERMAL_NAME_LIST[self.index]
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
"""
|
||||||
|
Retrieves the presence of the Thermal
|
||||||
|
Returns:
|
||||||
|
bool: True if Thermal is present, False if not
|
||||||
|
"""
|
||||||
|
temp_file = "temp{}_input".format(self.ss_index)
|
||||||
|
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||||
|
raw_txt = self.__read_txt_file(temp_file_path)
|
||||||
|
if raw_txt is not None:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the operational status of the device
|
||||||
|
Returns:
|
||||||
|
A boolean value, True if device is operating properly, False if not
|
||||||
|
"""
|
||||||
|
|
||||||
|
file_str = "temp{}_input".format(self.ss_index)
|
||||||
|
file_path = os.path.join(self.hwmon_path, file_str)
|
||||||
|
raw_txt = self.__read_txt_file(file_path)
|
||||||
|
if raw_txt is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return int(raw_txt) != 0
|
@ -35,6 +35,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
|
|||||||
$(ACCTON_AS5812_54T_PLATFORM_MODULE) \
|
$(ACCTON_AS5812_54T_PLATFORM_MODULE) \
|
||||||
$(ACCTON_AS5835_54X_PLATFORM_MODULE) \
|
$(ACCTON_AS5835_54X_PLATFORM_MODULE) \
|
||||||
$(ACCTON_AS9716_32D_PLATFORM_MODULE) \
|
$(ACCTON_AS9716_32D_PLATFORM_MODULE) \
|
||||||
|
$(ACCTON_AS9726_32D_PLATFORM_MODULE) \
|
||||||
$(ACCTON_AS5835_54T_PLATFORM_MODULE) \
|
$(ACCTON_AS5835_54T_PLATFORM_MODULE) \
|
||||||
$(ACCTON_AS7312_54XS_PLATFORM_MODULE) \
|
$(ACCTON_AS7312_54XS_PLATFORM_MODULE) \
|
||||||
$(ACCTON_AS7315_27XB_PLATFORM_MODULE) \
|
$(ACCTON_AS7315_27XB_PLATFORM_MODULE) \
|
||||||
|
@ -16,6 +16,7 @@ ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1
|
|||||||
ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION = 1.1
|
||||||
ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION = 1.1
|
||||||
ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION = 1.1
|
||||||
|
ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION = 1.1
|
||||||
ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1
|
||||||
ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION = 1.1
|
||||||
ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION = 1.1
|
ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION = 1.1
|
||||||
@ -36,6 +37,7 @@ export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION
|
|||||||
export ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION
|
export ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION
|
||||||
export ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION
|
export ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION
|
||||||
export ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION
|
export ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION
|
||||||
|
export ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION
|
||||||
export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION
|
export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION
|
||||||
export ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION
|
export ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION
|
||||||
export ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION
|
export ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION
|
||||||
@ -110,6 +112,10 @@ ACCTON_AS9716_32D_PLATFORM_MODULE = sonic-platform-accton-as9716-32d_$(ACCTON_AS
|
|||||||
$(ACCTON_AS9716_32D_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9716_32d-r0
|
$(ACCTON_AS9716_32D_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9716_32d-r0
|
||||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS9716_32D_PLATFORM_MODULE)))
|
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS9716_32D_PLATFORM_MODULE)))
|
||||||
|
|
||||||
|
ACCTON_AS9726_32D_PLATFORM_MODULE = sonic-platform-accton-as9726-32d_$(ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||||
|
$(ACCTON_AS9726_32D_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9726_32d-r0
|
||||||
|
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS9726_32D_PLATFORM_MODULE)))
|
||||||
|
|
||||||
ACCTON_AS5835_54T_PLATFORM_MODULE = sonic-platform-accton-as5835-54t_$(ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION)_amd64.deb
|
ACCTON_AS5835_54T_PLATFORM_MODULE = sonic-platform-accton-as5835-54t_$(ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||||
$(ACCTON_AS5835_54T_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5835_54t-r0
|
$(ACCTON_AS5835_54T_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5835_54t-r0
|
||||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54T_PLATFORM_MODULE)))
|
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54T_PLATFORM_MODULE)))
|
||||||
|
216
platform/broadcom/sonic-platform-modules-accton/as9726-32d/classes/fanutil.py
Executable file
216
platform/broadcom/sonic-platform-modules-accton/as9726-32d/classes/fanutil.py
Executable file
@ -0,0 +1,216 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||||
|
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||||
|
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||||
|
#
|
||||||
|
# See the Apache Version 2.0 License for specific language governing
|
||||||
|
# permissions and limitations under the License.
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# HISTORY:
|
||||||
|
# mm/dd/yyyy (A.D.)
|
||||||
|
# 04/06/2021:Michael_Shih craete for as9726_32d
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
try:
|
||||||
|
import logging
|
||||||
|
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 = 6
|
||||||
|
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_NUM_6_IDX = 6
|
||||||
|
|
||||||
|
FAN_NODE_NUM_OF_MAP = 2
|
||||||
|
FAN_NODE_FAULT_IDX_OF_MAP = 1
|
||||||
|
FAN_NODE_DIR_IDX_OF_MAP = 2
|
||||||
|
|
||||||
|
BASE_VAL_PATH = '/sys/bus/i2c/devices/14-0066/{0}'
|
||||||
|
FAN_DUTY_PATH = '/sys/bus/i2c/devices/14-0066/fan_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_device_path_mapping = {}
|
||||||
|
|
||||||
|
#fan1_direction
|
||||||
|
#fan1_fault
|
||||||
|
#fan1_present
|
||||||
|
|
||||||
|
#(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
|
||||||
|
_fan_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',
|
||||||
|
|
||||||
|
(FAN_NUM_6_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan6_fault',
|
||||||
|
(FAN_NUM_6_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan6_direction',
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_fan_device_node(self, fan_num, node_num):
|
||||||
|
return self._fan_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_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 IOError:
|
||||||
|
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_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 BaseException:
|
||||||
|
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_device_path_mapping[(fan_num, node_num)] = fan_path.format(
|
||||||
|
self._fan_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_device_node_mapping)
|
||||||
|
|
||||||
|
def get_size_path_map(self):
|
||||||
|
return len(self._fan_device_path_mapping)
|
||||||
|
|
||||||
|
def get_fan_device_path(self, fan_num, node_num):
|
||||||
|
return self._fan_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_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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
fan_file.write(str(val))
|
||||||
|
fan_file.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||||
|
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||||
|
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||||
|
#
|
||||||
|
# See the Apache Version 2.0 License for specific language governing
|
||||||
|
# permissions and limitations under the License.
|
||||||
|
#
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# HISTORY:
|
||||||
|
# mm/dd/yyyy (A.D.)
|
||||||
|
# 04/06/2021: Michael_Shih craete for as9726_32d
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
try:
|
||||||
|
import logging
|
||||||
|
import glob
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError('%s - required module not found' % str(e))
|
||||||
|
|
||||||
|
class ThermalUtil(object):
|
||||||
|
"""Platform-specific ThermalUtil class"""
|
||||||
|
THERMAL_NUM_MAX = 7
|
||||||
|
THERMAL_NUM_1_IDX = 1 # 1~6 are mainboard thermal sensors
|
||||||
|
THERMAL_NUM_2_IDX = 2
|
||||||
|
THERMAL_NUM_3_IDX = 3
|
||||||
|
THERMAL_NUM_4_IDX = 4
|
||||||
|
THERMAL_NUM_5_IDX = 5
|
||||||
|
THERMAL_NUM_6_IDX = 6 # CPU core
|
||||||
|
THERMAL_NUM_7_IDX = 7
|
||||||
|
|
||||||
|
""" Dictionary where
|
||||||
|
key1 = thermal id index (integer) starting from 1
|
||||||
|
value = path to fan device file (string) """
|
||||||
|
#_thermal_to_device_path_mapping = {}
|
||||||
|
|
||||||
|
thermal_sysfspath ={
|
||||||
|
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/15-0048/hwmon/hwmon*/temp1_input"],
|
||||||
|
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/15-0049/hwmon/hwmon*/temp1_input"],
|
||||||
|
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/15-004a/hwmon/hwmon*/temp1_input"],
|
||||||
|
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/15-004c/hwmon/hwmon*/temp1_input"],
|
||||||
|
THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/15-004f/hwmon/hwmon*/temp1_input"],
|
||||||
|
THERMAL_NUM_6_IDX: ["/sys/class/hwmon/hwmon0/temp1_input"],
|
||||||
|
THERMAL_NUM_7_IDX: ["/sys/bus/i2c/devices/15-004b/hwmon/hwmon*/temp1_input"],
|
||||||
|
}
|
||||||
|
|
||||||
|
#def __init__(self):
|
||||||
|
|
||||||
|
def _get_thermal_val(self, thermal_num):
|
||||||
|
if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX:
|
||||||
|
logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
|
||||||
|
return None
|
||||||
|
|
||||||
|
device_path = self.get_thermal_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 BaseException:
|
||||||
|
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return int(content)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_num_thermals(self):
|
||||||
|
return self.THERMAL_NUM_MAX
|
||||||
|
|
||||||
|
def get_size_path_map(self):
|
||||||
|
return len(self.thermal_sysfspath)
|
||||||
|
|
||||||
|
def get_thermal_path(self, thermal_num):
|
||||||
|
return self.thermal_sysfspath[thermal_num][0]
|
19
platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/Makefile
Executable file
19
platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/Makefile
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
ifneq ($(KERNELRELEASE),)
|
||||||
|
obj-m:= x86-64-accton-as9726-32d-cpld.o x86-64-accton-as9726-32d-psu.o \
|
||||||
|
x86-64-accton-as9726-32d-fan.o ym2651y.o
|
||||||
|
|
||||||
|
else
|
||||||
|
ifeq (,$(KERNEL_SRC))
|
||||||
|
#$(error KERNEL_SRC is not defined)
|
||||||
|
KVERSION=3.16.0-8-amd64
|
||||||
|
KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/
|
||||||
|
KERNELDIR:=$(KERNEL_DIR)
|
||||||
|
else
|
||||||
|
KERNELDIR:=$(KERNEL_SRC)
|
||||||
|
endif
|
||||||
|
PWD:=$(shell pwd)
|
||||||
|
default:
|
||||||
|
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.mod.o *.mod.o *.mod.c *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order
|
||||||
|
endif
|
@ -0,0 +1,987 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||||
|
*
|
||||||
|
* This module supports the accton cpld that hold the channel select
|
||||||
|
* mechanism for other i2c slave devices, such as SFP.
|
||||||
|
* This includes the:
|
||||||
|
* Accton as9726_32d CPU-CPLD/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/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 */
|
||||||
|
|
||||||
|
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_type {
|
||||||
|
as9726_32d_fpga,
|
||||||
|
as9726_32d_cpld2,
|
||||||
|
as9726_32d_cpld3,
|
||||||
|
as9726_32d_cpld_cpu
|
||||||
|
};
|
||||||
|
|
||||||
|
struct as9726_32d_cpld_data {
|
||||||
|
enum cpld_type type;
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct mutex update_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct i2c_device_id as9726_32d_cpld_id[] = {
|
||||||
|
{ "as9726_32d_fpga", as9726_32d_fpga },
|
||||||
|
{ "as9726_32d_cpld2", as9726_32d_cpld2 },
|
||||||
|
{ "as9726_32d_cpld3", as9726_32d_cpld3 },
|
||||||
|
{ "as9726_32d_cpld_cpu", as9726_32d_cpld_cpu },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, as9726_32d_cpld_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
|
||||||
|
#define CPLD_INTR_ATTR_ID(index) CPLD_INTR_##index
|
||||||
|
|
||||||
|
enum as9726_32d_cpld_sysfs_attributes {
|
||||||
|
CPLD_VERSION,
|
||||||
|
ACCESS,
|
||||||
|
/* 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),
|
||||||
|
TRANSCEIVER_PRESENT_ATTR_ID(33),
|
||||||
|
TRANSCEIVER_PRESENT_ATTR_ID(34),
|
||||||
|
TRANSCEIVER_TXDISABLE_ATTR_ID(33),
|
||||||
|
TRANSCEIVER_TXDISABLE_ATTR_ID(34),
|
||||||
|
TRANSCEIVER_RXLOS_ATTR_ID(33),
|
||||||
|
TRANSCEIVER_RXLOS_ATTR_ID(34),
|
||||||
|
TRANSCEIVER_TXFAULT_ATTR_ID(33),
|
||||||
|
TRANSCEIVER_TXFAULT_ATTR_ID(34),
|
||||||
|
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),
|
||||||
|
CPLD_INTR_ATTR_ID(1),
|
||||||
|
CPLD_INTR_ATTR_ID(2),
|
||||||
|
CPLD_INTR_ATTR_ID(3),
|
||||||
|
CPLD_INTR_ATTR_ID(4),
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sysfs attributes for hwmon
|
||||||
|
*/
|
||||||
|
static ssize_t show_interrupt(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 set_tx_disable(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 ssize_t get_mode_reset(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count);
|
||||||
|
static int as9726_32d_cpld_read_internal(struct i2c_client *client, u8 reg);
|
||||||
|
static int as9726_32d_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_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \
|
||||||
|
static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \
|
||||||
|
static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index);
|
||||||
|
|
||||||
|
#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \
|
||||||
|
&sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \
|
||||||
|
&sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \
|
||||||
|
&sensor_dev_attr_module_tx_fault_##index.dev_attr.attr
|
||||||
|
|
||||||
|
/*reset*/
|
||||||
|
#define DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR | S_IRUGO, get_mode_reset, set_mode_reset, MODULE_RESET_##index)
|
||||||
|
#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr
|
||||||
|
|
||||||
|
/*cpld interrupt*/
|
||||||
|
#define DECLARE_CPLD_DEVICE_INTR_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(cpld_intr_##index, S_IRUGO, show_interrupt, NULL, CPLD_INTR_##index)
|
||||||
|
#define DECLARE_CPLD_INTR_ATTR(index) &sensor_dev_attr_cpld_intr_##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 */
|
||||||
|
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_PRESENT_SENSOR_DEVICE_ATTR(33);
|
||||||
|
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(34);
|
||||||
|
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(33);
|
||||||
|
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(34);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(1);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(2);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(3);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(4);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(5);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(6);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(7);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(8);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(9);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(10);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(11);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(12);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(13);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(14);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(15);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(16);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(17);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(18);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(19);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(20);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(21);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(22);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(23);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(24);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(25);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(26);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(27);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(28);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(29);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(30);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(31);
|
||||||
|
DECLARE_TRANSCEIVER_SENSOR_DEVICE_RESET_ATTR(32);
|
||||||
|
DECLARE_CPLD_DEVICE_INTR_ATTR(1);
|
||||||
|
DECLARE_CPLD_DEVICE_INTR_ATTR(2);
|
||||||
|
DECLARE_CPLD_DEVICE_INTR_ATTR(3);
|
||||||
|
DECLARE_CPLD_DEVICE_INTR_ATTR(4);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_fpga_attributes[] = {
|
||||||
|
&sensor_dev_attr_version.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_access.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_fpga_group = {
|
||||||
|
.attrs = as9726_32d_fpga_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_cpld2_attributes[] = {
|
||||||
|
&sensor_dev_attr_version.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_access.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),
|
||||||
|
DECLARE_CPLD_INTR_ATTR(1),
|
||||||
|
DECLARE_CPLD_INTR_ATTR(2),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_cpld2_group = {
|
||||||
|
.attrs = as9726_32d_cpld2_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_cpld3_attributes[] = {
|
||||||
|
&sensor_dev_attr_version.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_access.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_PRESENT_ATTR(33),
|
||||||
|
DECLARE_TRANSCEIVER_PRESENT_ATTR(34),
|
||||||
|
DECLARE_SFP_TRANSCEIVER_ATTR(33),
|
||||||
|
DECLARE_SFP_TRANSCEIVER_ATTR(34),
|
||||||
|
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),
|
||||||
|
DECLARE_CPLD_INTR_ATTR(3),
|
||||||
|
DECLARE_CPLD_INTR_ATTR(4),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_cpld3_group = {
|
||||||
|
.attrs = as9726_32d_cpld3_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_cpld_cpu_attributes[] = {
|
||||||
|
&sensor_dev_attr_version.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_cpld_cpu_group = {
|
||||||
|
.attrs = as9726_32d_cpld_cpu_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_interrupt(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 as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
int status = 0;
|
||||||
|
u8 reg = 0;
|
||||||
|
|
||||||
|
switch (attr->index)
|
||||||
|
{
|
||||||
|
case CPLD_INTR_1:
|
||||||
|
reg = 0x10;
|
||||||
|
break;
|
||||||
|
case CPLD_INTR_3:
|
||||||
|
reg = 0x10;
|
||||||
|
break;
|
||||||
|
case CPLD_INTR_2:
|
||||||
|
reg = 0x11;
|
||||||
|
break;
|
||||||
|
case CPLD_INTR_4:
|
||||||
|
reg = 0x11;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
status = as9726_32d_cpld_read_internal(client, reg);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "0x%x\n", status);
|
||||||
|
|
||||||
|
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 as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
int status = 0;
|
||||||
|
u8 reg = 0, mask = 0, revert = 0;
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case MODULE_PRESENT_1 ... MODULE_PRESENT_8:
|
||||||
|
reg = 0x12;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_PRESENT_1);
|
||||||
|
break;
|
||||||
|
case MODULE_PRESENT_9 ... MODULE_PRESENT_16:
|
||||||
|
reg = 0x13;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_PRESENT_9);
|
||||||
|
break;
|
||||||
|
case MODULE_PRESENT_17 ... MODULE_PRESENT_24:
|
||||||
|
reg = 0x12;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_PRESENT_17);
|
||||||
|
break;
|
||||||
|
case MODULE_PRESENT_25 ... MODULE_PRESENT_32:
|
||||||
|
reg = 0x13;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_PRESENT_25);
|
||||||
|
break;
|
||||||
|
case MODULE_PRESENT_33:
|
||||||
|
reg = 0x20;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
case MODULE_PRESENT_34:
|
||||||
|
reg = 0x20;
|
||||||
|
mask = 0x2;
|
||||||
|
break;
|
||||||
|
case MODULE_RXLOS_33:
|
||||||
|
reg = 0x26;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
case MODULE_RXLOS_34:
|
||||||
|
reg = 0x26;
|
||||||
|
mask = 0x2;
|
||||||
|
break;
|
||||||
|
case MODULE_TXDISABLE_33:
|
||||||
|
reg = 0x21;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
case MODULE_TXDISABLE_34:
|
||||||
|
reg = 0x21;
|
||||||
|
mask = 0x2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_34) {
|
||||||
|
revert = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
status = as9726_32d_cpld_read_internal(client, reg);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask));
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_tx_disable(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 as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
long disable;
|
||||||
|
int status;
|
||||||
|
u8 reg = 0, mask = 0;
|
||||||
|
|
||||||
|
status = kstrtol(buf, 10, &disable);
|
||||||
|
if (status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case MODULE_TXDISABLE_33:
|
||||||
|
reg = 0x21;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
case MODULE_TXDISABLE_34:
|
||||||
|
reg = 0x21;
|
||||||
|
mask = 0x2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read current status */
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
status = as9726_32d_cpld_read_internal(client, reg);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update tx_disable status */
|
||||||
|
if (disable) {
|
||||||
|
status |= mask;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status &= ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = as9726_32d_cpld_write_internal(client, reg, status);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
return count;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
u32 addr, val;
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr > 0xFF || val > 0xFF) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
status = as9726_32d_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void as9726_32d_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 as9726_32d_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, "0x%x\n", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t get_mode_reset(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 as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
int status = 0;
|
||||||
|
u8 reg = 0, mask = 0;
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case MODULE_RESET_1 ... MODULE_RESET_8:
|
||||||
|
reg = 0x14;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_1);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_9 ... MODULE_RESET_16:
|
||||||
|
reg = 0x15;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_9);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_17 ... MODULE_RESET_24:
|
||||||
|
reg = 0x14;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_17);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_25 ... MODULE_RESET_32:
|
||||||
|
reg = 0x15;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_25);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
status = as9726_32d_cpld_read_internal(client, reg);
|
||||||
|
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\r\n", !(status & mask));
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
long reset;
|
||||||
|
int status=0, val, error;
|
||||||
|
u8 reg = 0, mask = 0;
|
||||||
|
|
||||||
|
|
||||||
|
error = kstrtol(buf, 10, &reset);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case MODULE_RESET_1 ... MODULE_RESET_8:
|
||||||
|
reg = 0x14;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_1);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_9 ... MODULE_RESET_16:
|
||||||
|
reg = 0x15;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_9);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_17 ... MODULE_RESET_24:
|
||||||
|
reg = 0x14;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_17);
|
||||||
|
break;
|
||||||
|
case MODULE_RESET_25 ... MODULE_RESET_32:
|
||||||
|
reg = 0x15;
|
||||||
|
mask = 0x1 << (attr->index - MODULE_RESET_25);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
|
status = as9726_32d_cpld_read_internal(client, reg);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update lp_mode status */
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
val = status&(~mask);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val =status | (mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = as9726_32d_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C init/probing/exit functions
|
||||||
|
*/
|
||||||
|
static int as9726_32d_cpld_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||||
|
struct as9726_32d_cpld_data *data;
|
||||||
|
int ret = -ENODEV;
|
||||||
|
int status;
|
||||||
|
const struct attribute_group *group = NULL;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct as9726_32d_cpld_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
data->type = id->driver_data;
|
||||||
|
|
||||||
|
|
||||||
|
/* Register sysfs hooks */
|
||||||
|
switch (data->type) {
|
||||||
|
case as9726_32d_fpga:
|
||||||
|
group = &as9726_32d_fpga_group;
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld2:
|
||||||
|
group = &as9726_32d_cpld2_group;
|
||||||
|
/*Set interrupt mask to 0, and then can get intr from 0x8*/
|
||||||
|
status=as9726_32d_cpld_write_internal(client, 0x9, 0x0);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
dev_dbg(&client->dev, "cpld2 reg 0x9 err %d\n", status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld3:
|
||||||
|
group = &as9726_32d_cpld3_group;
|
||||||
|
/*Set interrupt mask to 0, and then can get intr from 0x8*/
|
||||||
|
status=as9726_32d_cpld_write_internal(client, 0x9, 0x0);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
dev_dbg(&client->dev, "cpld3 reg 0x9 err %d\n", status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld_cpu:
|
||||||
|
group = &as9726_32d_cpld_cpu_group;
|
||||||
|
/* Disable CPLD reset to avoid DUT will be reset.
|
||||||
|
*/
|
||||||
|
// status=as9726_32d_cpld_write_internal(client, 0x3, 0x0);
|
||||||
|
// if (status < 0)
|
||||||
|
// {
|
||||||
|
// dev_dbg(&client->dev, "cpu_cpld reg 0x65 err %d\n", status);
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group) {
|
||||||
|
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||||
|
if (ret) {
|
||||||
|
goto exit_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
as9726_32d_cpld_add_client(client);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_free:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_cpld_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct as9726_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
const struct attribute_group *group = NULL;
|
||||||
|
|
||||||
|
as9726_32d_cpld_remove_client(client);
|
||||||
|
|
||||||
|
/* Remove sysfs hooks */
|
||||||
|
switch (data->type) {
|
||||||
|
case as9726_32d_fpga:
|
||||||
|
group = &as9726_32d_fpga_group;
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld2:
|
||||||
|
group = &as9726_32d_cpld2_group;
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld3:
|
||||||
|
group = &as9726_32d_cpld3_group;
|
||||||
|
break;
|
||||||
|
case as9726_32d_cpld_cpu:
|
||||||
|
group = &as9726_32d_cpld_cpu_group;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group) {
|
||||||
|
sysfs_remove_group(&client->dev.kobj, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_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 as9726_32d_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 as9726_32d_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 = as9726_32d_cpld_read_internal(cpld_node->client, reg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&list_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(as9726_32d_cpld_read);
|
||||||
|
|
||||||
|
int as9726_32d_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 = as9726_32d_cpld_write_internal(cpld_node->client, reg, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&list_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(as9726_32d_cpld_write);
|
||||||
|
|
||||||
|
static struct i2c_driver as9726_32d_cpld_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "as9726_32d_cpld",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = as9726_32d_cpld_probe,
|
||||||
|
.remove = as9726_32d_cpld_remove,
|
||||||
|
.id_table = as9726_32d_cpld_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init as9726_32d_cpld_init(void)
|
||||||
|
{
|
||||||
|
mutex_init(&list_lock);
|
||||||
|
return i2c_add_driver(&as9726_32d_cpld_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit as9726_32d_cpld_exit(void)
|
||||||
|
{
|
||||||
|
i2c_del_driver(&as9726_32d_cpld_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Michael Shih <michael_shih@edge-core.com>");
|
||||||
|
MODULE_DESCRIPTION("Accton I2C CPLD driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
module_init(as9726_32d_cpld_init);
|
||||||
|
module_exit(as9726_32d_cpld_exit);
|
||||||
|
|
@ -0,0 +1,717 @@
|
|||||||
|
/*
|
||||||
|
* A hwmon driver for the Accton as9726 32d fan
|
||||||
|
*
|
||||||
|
* 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/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/dmi.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
#define DRVNAME "as9726_32d_fan"
|
||||||
|
|
||||||
|
static struct as9726_32d_fan_data *as9726_32d_fan_update_device(struct device *dev);
|
||||||
|
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf);
|
||||||
|
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count);
|
||||||
|
|
||||||
|
/* fan related data, the index should match sysfs_fan_attributes
|
||||||
|
*/
|
||||||
|
static const u8 fan_reg[] = {
|
||||||
|
0x0F, /* fan 1-6 present status */
|
||||||
|
0x10, /* fan 1-6 direction(0:F2B 1:B2F) */
|
||||||
|
0x11, /* fan PWM(for all fan) */
|
||||||
|
0x12, /* front fan 1 speed(rpm) */
|
||||||
|
0x13, /* front fan 2 speed(rpm) */
|
||||||
|
0x14, /* front fan 3 speed(rpm) */
|
||||||
|
0x15, /* front fan 4 speed(rpm) */
|
||||||
|
0x16, /* front fan 5 speed(rpm) */
|
||||||
|
0x17, /* front fan 6 speed(rpm) */
|
||||||
|
0x22, /* rear fan 1 speed(rpm) */
|
||||||
|
0x23, /* rear fan 2 speed(rpm) */
|
||||||
|
0x24, /* rear fan 3 speed(rpm) */
|
||||||
|
0x25, /* rear fan 4 speed(rpm) */
|
||||||
|
0x26, /* rear fan 5 speed(rpm) */
|
||||||
|
0x27, /* rear fan 6 speed(rpm) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Each client has this additional data */
|
||||||
|
struct as9726_32d_fan_data {
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct mutex update_lock;
|
||||||
|
char valid; /* != 0 if registers are valid */
|
||||||
|
unsigned long last_updated; /* In jiffies */
|
||||||
|
u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */
|
||||||
|
int system_temp; /*In unit of mini-Celsius*/
|
||||||
|
int sensors_found;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fan_id {
|
||||||
|
FAN1_ID,
|
||||||
|
FAN2_ID,
|
||||||
|
FAN3_ID,
|
||||||
|
FAN4_ID,
|
||||||
|
FAN5_ID,
|
||||||
|
FAN6_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sysfs_fan_attributes {
|
||||||
|
FAN_PRESENT_REG,
|
||||||
|
FAN_DIRECTION_REG,
|
||||||
|
FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */
|
||||||
|
FAN1_FRONT_SPEED_RPM,
|
||||||
|
FAN2_FRONT_SPEED_RPM,
|
||||||
|
FAN3_FRONT_SPEED_RPM,
|
||||||
|
FAN4_FRONT_SPEED_RPM,
|
||||||
|
FAN5_FRONT_SPEED_RPM,
|
||||||
|
FAN6_FRONT_SPEED_RPM,
|
||||||
|
FAN1_REAR_SPEED_RPM,
|
||||||
|
FAN2_REAR_SPEED_RPM,
|
||||||
|
FAN3_REAR_SPEED_RPM,
|
||||||
|
FAN4_REAR_SPEED_RPM,
|
||||||
|
FAN5_REAR_SPEED_RPM,
|
||||||
|
FAN6_REAR_SPEED_RPM,
|
||||||
|
FAN1_DIRECTION,
|
||||||
|
FAN2_DIRECTION,
|
||||||
|
FAN3_DIRECTION,
|
||||||
|
FAN4_DIRECTION,
|
||||||
|
FAN5_DIRECTION,
|
||||||
|
FAN6_DIRECTION,
|
||||||
|
FAN1_PRESENT,
|
||||||
|
FAN2_PRESENT,
|
||||||
|
FAN3_PRESENT,
|
||||||
|
FAN4_PRESENT,
|
||||||
|
FAN5_PRESENT,
|
||||||
|
FAN6_PRESENT,
|
||||||
|
FAN1_FAULT,
|
||||||
|
FAN2_FAULT,
|
||||||
|
FAN3_FAULT,
|
||||||
|
FAN4_FAULT,
|
||||||
|
FAN5_FAULT,
|
||||||
|
FAN6_FAULT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define attributes
|
||||||
|
*/
|
||||||
|
#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT)
|
||||||
|
|
||||||
|
#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_fault.dev_attr.attr
|
||||||
|
|
||||||
|
#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION)
|
||||||
|
|
||||||
|
#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr
|
||||||
|
|
||||||
|
#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE)
|
||||||
|
|
||||||
|
#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr
|
||||||
|
|
||||||
|
#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT)
|
||||||
|
|
||||||
|
#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr
|
||||||
|
|
||||||
|
#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index, index2) \
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM);\
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\
|
||||||
|
static SENSOR_DEVICE_ATTR(fan##index2##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM)
|
||||||
|
|
||||||
|
#define DECLARE_FAN_SPEED_RPM_ATTR(index, index2) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \
|
||||||
|
&sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr, \
|
||||||
|
&sensor_dev_attr_fan##index##_input.dev_attr.attr, \
|
||||||
|
&sensor_dev_attr_fan##index2##_input.dev_attr.attr
|
||||||
|
|
||||||
|
/* 6 fan fault attributes in this platform */
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1);
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2);
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3);
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4);
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5);
|
||||||
|
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(6);
|
||||||
|
/* 6 fan speed(rpm) attributes in this platform */
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1,11);
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2,12);
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3,13);
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4,14);
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5,15);
|
||||||
|
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(6,16);
|
||||||
|
/* 6 fan present attributes in this platform */
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1);
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2);
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3);
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4);
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(5);
|
||||||
|
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(6);
|
||||||
|
/* 6 fan direction attribute in this platform */
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1);
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2);
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3);
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4);
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5);
|
||||||
|
DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(6);
|
||||||
|
/* 1 fan duty cycle attribute in this platform */
|
||||||
|
DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR();
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_fan_attributes[] = {
|
||||||
|
/* fan related attributes */
|
||||||
|
DECLARE_FAN_FAULT_ATTR(1),
|
||||||
|
DECLARE_FAN_FAULT_ATTR(2),
|
||||||
|
DECLARE_FAN_FAULT_ATTR(3),
|
||||||
|
DECLARE_FAN_FAULT_ATTR(4),
|
||||||
|
DECLARE_FAN_FAULT_ATTR(5),
|
||||||
|
DECLARE_FAN_FAULT_ATTR(6),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(1,11),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(2,12),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(3,13),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(4,14),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(5,15),
|
||||||
|
DECLARE_FAN_SPEED_RPM_ATTR(6,16),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(1),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(2),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(3),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(4),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(5),
|
||||||
|
DECLARE_FAN_PRESENT_ATTR(6),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(1),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(2),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(3),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(4),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(5),
|
||||||
|
DECLARE_FAN_DIRECTION_ATTR(6),
|
||||||
|
DECLARE_FAN_DUTY_CYCLE_ATTR(),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FAN_DUTY_CYCLE_REG_MASK 0xF
|
||||||
|
#define FAN_MAX_DUTY_CYCLE 100
|
||||||
|
#define FAN_REG_VAL_TO_SPEED_RPM_STEP 200
|
||||||
|
|
||||||
|
static int as9726_32d_fan_read_value(struct i2c_client *client, u8 reg)
|
||||||
|
{
|
||||||
|
return i2c_smbus_read_byte_data(client, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_fan_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||||
|
{
|
||||||
|
return i2c_smbus_write_byte_data(client, reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fan utility functions
|
||||||
|
*/
|
||||||
|
static u32 reg_val_to_duty_cycle(u8 reg_val)
|
||||||
|
{
|
||||||
|
reg_val &= FAN_DUTY_CYCLE_REG_MASK;
|
||||||
|
u32 duty_cycle = 0;
|
||||||
|
|
||||||
|
switch(reg_val)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
duty_cycle = 0;
|
||||||
|
break;
|
||||||
|
case 5 ... 6:
|
||||||
|
duty_cycle = ( ((u32)(reg_val)+1) *6) + 1;
|
||||||
|
break;
|
||||||
|
case 7 ... 10:
|
||||||
|
duty_cycle = ( ((u32)(reg_val)+1) *6) + 2;
|
||||||
|
break;
|
||||||
|
case 11 ... 14:
|
||||||
|
duty_cycle = ( ((u32)(reg_val)+1) *6) + 3;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
duty_cycle = 100;
|
||||||
|
break;
|
||||||
|
default: // 1~4
|
||||||
|
duty_cycle = 31;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return duty_cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 duty_cycle_to_reg_val(u8 duty_cycle)
|
||||||
|
{
|
||||||
|
u32 reg_val = 0;
|
||||||
|
|
||||||
|
if((u32)duty_cycle == 0) {
|
||||||
|
reg_val = 0;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 31) {
|
||||||
|
reg_val = 4;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 37) {
|
||||||
|
reg_val = 5;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 43) {
|
||||||
|
reg_val = 6;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 50) {
|
||||||
|
reg_val = 7;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 56) {
|
||||||
|
reg_val = 8;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 62) {
|
||||||
|
reg_val = 9;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 68) {
|
||||||
|
reg_val = 10;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 75) {
|
||||||
|
reg_val = 11;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 81) {
|
||||||
|
reg_val = 12;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 87) {
|
||||||
|
reg_val = 13;
|
||||||
|
}
|
||||||
|
else if((u32)duty_cycle <= 93) {
|
||||||
|
reg_val = 14;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reg_val = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 reg_val_to_speed_rpm(u8 reg_val)
|
||||||
|
{
|
||||||
|
return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 reg_val_to_direction(u8 reg_val, enum fan_id id)
|
||||||
|
{
|
||||||
|
u8 mask = (1 << id);
|
||||||
|
|
||||||
|
reg_val &= mask;
|
||||||
|
|
||||||
|
return reg_val ? 1 : 0;
|
||||||
|
}
|
||||||
|
static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id)
|
||||||
|
{
|
||||||
|
u8 mask = (1 << id);
|
||||||
|
|
||||||
|
reg_val &= mask;
|
||||||
|
|
||||||
|
return reg_val ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 is_fan_fault(struct as9726_32d_fan_data *data, enum fan_id id)
|
||||||
|
{
|
||||||
|
u8 ret = 1;
|
||||||
|
int front_fan_index = FAN1_FRONT_SPEED_RPM + id;
|
||||||
|
int rear_fan_index = FAN1_REAR_SPEED_RPM + id;
|
||||||
|
|
||||||
|
/* Check if the speed of front or rear fan is ZERO,
|
||||||
|
*/
|
||||||
|
if (reg_val_to_speed_rpm(data->reg_val[front_fan_index]) &&
|
||||||
|
reg_val_to_speed_rpm(data->reg_val[rear_fan_index])) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int error, value;
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
|
||||||
|
error = kstrtoint(buf, 10, &value);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (value < 0 || value > FAN_MAX_DUTY_CYCLE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
as9726_32d_fan_write_value(client, 0x33, 0); /* Disable fan speed watch dog */
|
||||||
|
as9726_32d_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value));
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Due to this struct is declared at lm75.c, it cannot be include
|
||||||
|
* under Sonic environment. I duplicate it from lm75.c.
|
||||||
|
*/
|
||||||
|
struct lm75_data {
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct thermal_zone_device *tz;
|
||||||
|
struct mutex update_lock;
|
||||||
|
u8 orig_conf;
|
||||||
|
u8 resolution; /* In bits, between 9 and 12 */
|
||||||
|
u8 resolution_limits;
|
||||||
|
char valid; /* !=0 if registers are valid */
|
||||||
|
unsigned long last_updated; /* In jiffies */
|
||||||
|
unsigned long sample_time; /* In jiffies */
|
||||||
|
s16 temp[3]; /* Register values,
|
||||||
|
0 = input
|
||||||
|
1 = max
|
||||||
|
2 = hyst */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Copied from lm75.c*/
|
||||||
|
static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
|
||||||
|
{
|
||||||
|
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Get hwmon_dev from i2c_client, set hwmon_dev = NULL is failed.*/
|
||||||
|
static struct device * get_hwmon_dev(
|
||||||
|
struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct lm75_data *data = NULL;
|
||||||
|
|
||||||
|
data = i2c_get_clientdata(client);
|
||||||
|
if(data)
|
||||||
|
{
|
||||||
|
if( data->valid == 1 && data->hwmon_dev)
|
||||||
|
{
|
||||||
|
return data->hwmon_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To find hwmon index by opening hwmon under that i2c address.
|
||||||
|
*/
|
||||||
|
static int find_hwmon_index_by_FileOpen(
|
||||||
|
int bus_nr,
|
||||||
|
unsigned short addr,
|
||||||
|
int *index)
|
||||||
|
{
|
||||||
|
#define MAX_HWMON_DEVICE (10) /* Find hwmon device in 0~10*/
|
||||||
|
struct file *sfd;
|
||||||
|
char client_name[96];
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
snprintf(client_name, sizeof(client_name),
|
||||||
|
"/sys/bus/i2c/devices/%d-%04x/hwmon/hwmon%d/temp1_input",
|
||||||
|
bus_nr, addr, i);
|
||||||
|
|
||||||
|
sfd = filp_open(client_name, O_RDONLY, 0);
|
||||||
|
i++;
|
||||||
|
} while( IS_ERR(sfd) && i < MAX_HWMON_DEVICE);
|
||||||
|
|
||||||
|
if (IS_ERR(sfd)) {
|
||||||
|
pr_err("Failed to open file(%s)#%d\r\n", client_name, __LINE__);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
filp_close(sfd, 0);
|
||||||
|
*index = i - 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#undef MAX_HWMON_DEVICE
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_temp_file_path(
|
||||||
|
int bus_nr, unsigned short addr,
|
||||||
|
struct device *hwmon_dev
|
||||||
|
,char *path, int max_len)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(hwmon_dev && strlen(dev_name(hwmon_dev)))
|
||||||
|
{
|
||||||
|
snprintf(path, max_len,
|
||||||
|
"/sys/bus/i2c/devices/%d-%04x/hwmon/%s/temp1_input",
|
||||||
|
bus_nr, addr, dev_name(hwmon_dev));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
if(find_hwmon_index_by_FileOpen( bus_nr, addr, &i))
|
||||||
|
{
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
snprintf(path, max_len,
|
||||||
|
"/sys/bus/i2c/devices/%d-%04x/hwmon/hwmon%d/temp1_input",
|
||||||
|
bus_nr, addr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*File read the dev file at user space.*/
|
||||||
|
static int read_devfile_temp1_input(
|
||||||
|
struct device *dev,
|
||||||
|
int bus_nr,
|
||||||
|
unsigned short addr,
|
||||||
|
struct device *hwmon_dev,
|
||||||
|
int *miniCelsius)
|
||||||
|
{
|
||||||
|
struct file *sfd;
|
||||||
|
char buffer[96];
|
||||||
|
char devfile[96];
|
||||||
|
int rc, status;
|
||||||
|
int rdlen, value;
|
||||||
|
mm_segment_t old_fs;
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile));
|
||||||
|
sfd = filp_open(devfile, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(sfd)) {
|
||||||
|
pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
dev_dbg(dev, "Found device:%s\n",devfile);
|
||||||
|
|
||||||
|
if(!(sfd->f_op) || !(sfd->f_op->read) ) {
|
||||||
|
pr_err("file %s cann't readable ?\n",devfile);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_fs = get_fs();
|
||||||
|
set_fs(KERNEL_DS);
|
||||||
|
rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos);
|
||||||
|
if (rdlen == 0) {
|
||||||
|
pr_err( "File(%s) empty!\n", devfile);
|
||||||
|
rc = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
status = sscanf(buffer, "%d", &value);
|
||||||
|
if (status != 1) {
|
||||||
|
rc = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
*miniCelsius = value;
|
||||||
|
dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
set_fs(old_fs);
|
||||||
|
filp_close(sfd, 0);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 is_lm75_data_due(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct lm75_data *data = NULL;
|
||||||
|
|
||||||
|
data = i2c_get_clientdata(client);
|
||||||
|
if (time_after(jiffies, data->last_updated + data->sample_time))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
struct as9726_32d_fan_data *data = as9726_32d_fan_update_device(dev);
|
||||||
|
ssize_t ret = 0;
|
||||||
|
|
||||||
|
if (data->valid) {
|
||||||
|
switch (attr->index) {
|
||||||
|
case FAN_DUTY_CYCLE_PERCENTAGE:
|
||||||
|
{
|
||||||
|
u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]);
|
||||||
|
ret = sprintf(buf, "%u\n", duty_cycle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FAN1_FRONT_SPEED_RPM:
|
||||||
|
case FAN2_FRONT_SPEED_RPM:
|
||||||
|
case FAN3_FRONT_SPEED_RPM:
|
||||||
|
case FAN4_FRONT_SPEED_RPM:
|
||||||
|
case FAN5_FRONT_SPEED_RPM:
|
||||||
|
case FAN6_FRONT_SPEED_RPM:
|
||||||
|
case FAN1_REAR_SPEED_RPM:
|
||||||
|
case FAN2_REAR_SPEED_RPM:
|
||||||
|
case FAN3_REAR_SPEED_RPM:
|
||||||
|
case FAN4_REAR_SPEED_RPM:
|
||||||
|
case FAN5_REAR_SPEED_RPM:
|
||||||
|
case FAN6_REAR_SPEED_RPM:
|
||||||
|
ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index]));
|
||||||
|
break;
|
||||||
|
case FAN1_PRESENT:
|
||||||
|
case FAN2_PRESENT:
|
||||||
|
case FAN3_PRESENT:
|
||||||
|
case FAN4_PRESENT:
|
||||||
|
case FAN5_PRESENT:
|
||||||
|
case FAN6_PRESENT:
|
||||||
|
ret = sprintf(buf, "%d\n",
|
||||||
|
reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG],
|
||||||
|
attr->index - FAN1_PRESENT));
|
||||||
|
break;
|
||||||
|
case FAN1_FAULT:
|
||||||
|
case FAN2_FAULT:
|
||||||
|
case FAN3_FAULT:
|
||||||
|
case FAN4_FAULT:
|
||||||
|
case FAN5_FAULT:
|
||||||
|
case FAN6_FAULT:
|
||||||
|
ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT));
|
||||||
|
break;
|
||||||
|
case FAN1_DIRECTION:
|
||||||
|
case FAN2_DIRECTION:
|
||||||
|
case FAN3_DIRECTION:
|
||||||
|
case FAN4_DIRECTION:
|
||||||
|
case FAN5_DIRECTION:
|
||||||
|
case FAN6_DIRECTION:
|
||||||
|
ret = sprintf(buf, "%d\n",
|
||||||
|
reg_val_to_direction(data->reg_val[FAN_DIRECTION_REG],
|
||||||
|
attr->index - FAN1_DIRECTION));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_fan_group = {
|
||||||
|
.attrs = as9726_32d_fan_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct as9726_32d_fan_data *as9726_32d_fan_update_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct as9726_32d_fan_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;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "Starting as9726_32d_fan update\n");
|
||||||
|
data->valid = 0;
|
||||||
|
|
||||||
|
/* Update fan data
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) {
|
||||||
|
int status = as9726_32d_fan_read_value(client, fan_reg[i]);
|
||||||
|
if (status < 0) {
|
||||||
|
data->valid = 0;
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n", fan_reg[i], status);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->reg_val[i] = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->last_updated = jiffies;
|
||||||
|
data->valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_fan_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *dev_id)
|
||||||
|
{
|
||||||
|
struct as9726_32d_fan_data *data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
|
status = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct as9726_32d_fan_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, &as9726_32d_fan_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: fan '%s'\n",
|
||||||
|
dev_name(data->hwmon_dev), client->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_remove:
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &as9726_32d_fan_group);
|
||||||
|
exit_free:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_fan_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct as9726_32d_fan_data *data = i2c_get_clientdata(client);
|
||||||
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &as9726_32d_fan_group);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Addresses to scan */
|
||||||
|
static const unsigned short normal_i2c[] = { 0x66, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
static const struct i2c_device_id as9726_32d_fan_id[] = {
|
||||||
|
{ "as9726_32d_fan", 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, as9726_32d_fan_id);
|
||||||
|
|
||||||
|
static struct i2c_driver as9726_32d_fan_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
|
.driver = {
|
||||||
|
.name = DRVNAME,
|
||||||
|
},
|
||||||
|
.probe = as9726_32d_fan_probe,
|
||||||
|
.remove = as9726_32d_fan_remove,
|
||||||
|
.id_table = as9726_32d_fan_id,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(as9726_32d_fan_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Michael Shih <michael_shih@edge-core.com>");
|
||||||
|
MODULE_DESCRIPTION("as9726_32d_fan driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* An hwmon driver for accton as9726_32d Power Module
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Accton Technology Corporation.
|
||||||
|
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||||
|
*
|
||||||
|
* Based on ad7414.c
|
||||||
|
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
|
||||||
|
#define MAX_MODEL_NAME 20
|
||||||
|
#define MAX_SERIAL_NUMBER 19
|
||||||
|
|
||||||
|
static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
|
||||||
|
static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf);
|
||||||
|
static int as9726_32d_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
|
||||||
|
extern int as9726_32d_cpld_read(unsigned short cpld_addr, u8 reg);
|
||||||
|
|
||||||
|
/* Addresses scanned
|
||||||
|
*/
|
||||||
|
static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
/* Each client has this additional data
|
||||||
|
*/
|
||||||
|
struct as9726_32d_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[MAX_MODEL_NAME]; /* Model name, read from eeprom */
|
||||||
|
char serial_number[MAX_SERIAL_NUMBER];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct as9726_32d_psu_data *as9726_32d_psu_update_device(struct device *dev);
|
||||||
|
|
||||||
|
enum as9726_32d_psu_sysfs_attributes {
|
||||||
|
PSU_PRESENT,
|
||||||
|
PSU_MODEL_NAME,
|
||||||
|
PSU_POWER_GOOD,
|
||||||
|
PSU_SERIAL_NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sysfs attributes for hwmon
|
||||||
|
*/
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER);
|
||||||
|
|
||||||
|
|
||||||
|
static struct attribute *as9726_32d_psu_attributes[] = {
|
||||||
|
&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,
|
||||||
|
&sensor_dev_attr_psu_serial_number.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
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 as9726_32d_psu_data *data = as9726_32d_psu_update_device(dev);
|
||||||
|
u8 status = 0;
|
||||||
|
|
||||||
|
//printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index);
|
||||||
|
if (attr->index == PSU_PRESENT) {
|
||||||
|
if(data->index==0)
|
||||||
|
status = !( (data->status) & 0x1);
|
||||||
|
else
|
||||||
|
status = !( (data->status >> 1) & 0x1);
|
||||||
|
}
|
||||||
|
else { /* PSU_POWER_GOOD */
|
||||||
|
if(data->index==0)
|
||||||
|
status = ( (data->status >> 2) & 0x1);
|
||||||
|
else
|
||||||
|
status = ( (data->status >> 3) & 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_string(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct as9726_32d_psu_data *data = as9726_32d_psu_update_device(dev);
|
||||||
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
if (!data->valid) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case PSU_MODEL_NAME:
|
||||||
|
ptr = data->model_name;
|
||||||
|
break;
|
||||||
|
case PSU_SERIAL_NUMBER:
|
||||||
|
ptr = data->serial_number;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct attribute_group as9726_32d_psu_group = {
|
||||||
|
.attrs = as9726_32d_psu_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int as9726_32d_psu_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *dev_id)
|
||||||
|
{
|
||||||
|
struct as9726_32d_psu_data *data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||||
|
status = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct as9726_32d_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, &as9726_32d_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, &as9726_32d_psu_group);
|
||||||
|
exit_free:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int as9726_32d_psu_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct as9726_32d_psu_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &as9726_32d_psu_group);
|
||||||
|
kfree(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum psu_index
|
||||||
|
{
|
||||||
|
as9726_32d_psu1,
|
||||||
|
as9726_32d_psu2
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct i2c_device_id as9726_32d_psu_id[] = {
|
||||||
|
{ "as9726_32d_psu1", as9726_32d_psu1 },
|
||||||
|
{ "as9726_32d_psu2", as9726_32d_psu2 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, as9726_32d_psu_id);
|
||||||
|
|
||||||
|
static struct i2c_driver as9726_32d_psu_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
|
.driver = {
|
||||||
|
.name = "as9726_32d_psu",
|
||||||
|
},
|
||||||
|
.probe = as9726_32d_psu_probe,
|
||||||
|
.remove = as9726_32d_psu_remove,
|
||||||
|
.id_table = as9726_32d_psu_id,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int as9726_32d_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct as9726_32d_psu_data *as9726_32d_psu_update_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct as9726_32d_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;
|
||||||
|
int psu_present = 0;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "Starting as9726_32d update\n");
|
||||||
|
|
||||||
|
/* Read psu status */
|
||||||
|
status = as9726_32d_cpld_read(0x60, 0x03);
|
||||||
|
//printk("status=0x%x in %s\n", status, __FUNCTION__);
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read model name */
|
||||||
|
memset(data->model_name, 0, sizeof(data->model_name));
|
||||||
|
memset(data->serial_number, 0, sizeof(data->serial_number));
|
||||||
|
psu_present = (data->status >> (data->index) & 0x1); //0:present, 1:not present
|
||||||
|
|
||||||
|
if (!psu_present) {
|
||||||
|
status = as9726_32d_psu_read_block(client, 0x20, data->model_name,
|
||||||
|
ARRAY_SIZE(data->model_name)-1);
|
||||||
|
if (status < 0) {
|
||||||
|
data->model_name[0] = '\0';
|
||||||
|
dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr);
|
||||||
|
printk("unable to read model name from (0x%x)\n", client->addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0';
|
||||||
|
|
||||||
|
}
|
||||||
|
/* Read from offset 0x35 ~ 0x46 (18 bytes) */
|
||||||
|
status = as9726_32d_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
data->serial_number[0] = '\0';
|
||||||
|
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x2e)\n", client->addr);
|
||||||
|
printk("unable to read model name from (0x%x) offset(0x2e)\n", client->addr);
|
||||||
|
}
|
||||||
|
data->serial_number[MAX_SERIAL_NUMBER-1]='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
data->last_updated = jiffies;
|
||||||
|
data->valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_i2c_driver(as9726_32d_psu_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Michael Shih <michael_shih@edge-core.com>");
|
||||||
|
MODULE_DESCRIPTION("as9726_32d_psu driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
678
platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c
Executable file
678
platform/broadcom/sonic-platform-modules-accton/as9726-32d/modules/ym2651y.c
Executable file
@ -0,0 +1,678 @@
|
|||||||
|
/*
|
||||||
|
* An hwmon driver for the 3Y Power YM-2651Y Power Module
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Accton Technology Corporation.
|
||||||
|
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||||
|
*
|
||||||
|
* Based on ad7414.c
|
||||||
|
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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[] = { 0x58, 0x59, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
enum chips {
|
||||||
|
YM2651,
|
||||||
|
YM2401,
|
||||||
|
YM2851,
|
||||||
|
YPEB1200AM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Each client has this additional data
|
||||||
|
*/
|
||||||
|
struct ym2651y_data {
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct mutex update_lock;
|
||||||
|
char valid; /* !=0 if registers are valid */
|
||||||
|
unsigned long last_updated; /* In jiffies */
|
||||||
|
u8 chip; /* chip id */
|
||||||
|
u8 capability; /* Register value */
|
||||||
|
u16 status_word; /* Register value */
|
||||||
|
u8 fan_fault; /* Register value */
|
||||||
|
u8 over_temp; /* Register value */
|
||||||
|
u16 v_out; /* Register value */
|
||||||
|
u16 i_out; /* Register value */
|
||||||
|
u16 p_out; /* Register value */
|
||||||
|
u8 vout_mode; /* Register value */
|
||||||
|
u16 temp; /* Register value */
|
||||||
|
u16 fan_speed; /* Register value */
|
||||||
|
u16 fan_duty_cycle[2]; /* Register value */
|
||||||
|
u8 fan_dir[4]; /* Register value */
|
||||||
|
u8 pmbus_revision; /* Register value */
|
||||||
|
u8 mfr_id[10]; /* Register value */
|
||||||
|
u8 mfr_model[10]; /* Register value */
|
||||||
|
u8 mfr_revsion[3]; /* Register value */
|
||||||
|
u16 mfr_vin_min; /* Register value */
|
||||||
|
u16 mfr_vin_max; /* Register value */
|
||||||
|
u16 mfr_iin_max; /* Register value */
|
||||||
|
u16 mfr_iout_max; /* Register value */
|
||||||
|
u16 mfr_pin_max; /* Register value */
|
||||||
|
u16 mfr_pout_max; /* Register value */
|
||||||
|
u16 mfr_vout_min; /* Register value */
|
||||||
|
u16 mfr_vout_max; /* Register value */
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_word(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf);
|
||||||
|
static struct ym2651y_data *ym2651y_update_device(struct device *dev);
|
||||||
|
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count);
|
||||||
|
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value);
|
||||||
|
|
||||||
|
enum ym2651y_sysfs_attributes {
|
||||||
|
PSU_POWER_ON = 0,
|
||||||
|
PSU_TEMP_FAULT,
|
||||||
|
PSU_POWER_GOOD,
|
||||||
|
PSU_FAN1_FAULT,
|
||||||
|
PSU_FAN_DIRECTION,
|
||||||
|
PSU_OVER_TEMP,
|
||||||
|
PSU_V_OUT,
|
||||||
|
PSU_I_OUT,
|
||||||
|
PSU_P_OUT,
|
||||||
|
PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/
|
||||||
|
PSU_TEMP1_INPUT,
|
||||||
|
PSU_FAN1_SPEED,
|
||||||
|
PSU_FAN1_DUTY_CYCLE,
|
||||||
|
PSU_PMBUS_REVISION,
|
||||||
|
PSU_MFR_ID,
|
||||||
|
PSU_MFR_MODEL,
|
||||||
|
PSU_MFR_REVISION,
|
||||||
|
PSU_MFR_VIN_MIN,
|
||||||
|
PSU_MFR_VIN_MAX,
|
||||||
|
PSU_MFR_VOUT_MIN,
|
||||||
|
PSU_MFR_VOUT_MAX,
|
||||||
|
PSU_MFR_IIN_MAX,
|
||||||
|
PSU_MFR_IOUT_MAX,
|
||||||
|
PSU_MFR_PIN_MAX,
|
||||||
|
PSU_MFR_POUT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sysfs attributes for hwmon
|
||||||
|
*/
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX);
|
||||||
|
static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX);
|
||||||
|
|
||||||
|
/*Duplicate nodes for lm-sensors.*/
|
||||||
|
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_vout, NULL, PSU_V_OUT);
|
||||||
|
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT);
|
||||||
|
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(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
|
||||||
|
|
||||||
|
static struct attribute *ym2651y_attributes[] = {
|
||||||
|
&sensor_dev_attr_psu_power_on.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_temp_fault.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_power_good.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_over_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_v_out.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_i_out.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_p_out.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_temp1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr,
|
||||||
|
/*Duplicate nodes for lm-sensors.*/
|
||||||
|
&sensor_dev_attr_curr2_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_in3_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_temp1_fault.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
|
||||||
|
return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) :
|
||||||
|
sprintf(buf, "0\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_word(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
u16 status = 0;
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */
|
||||||
|
status = (data->status_word & 0x40) ? 0 : 1;
|
||||||
|
break;
|
||||||
|
case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */
|
||||||
|
status = (data->status_word & 0x4) >> 2;
|
||||||
|
break;
|
||||||
|
case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */
|
||||||
|
status = (data->status_word & 0x800) ? 0 : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
|
||||||
|
{
|
||||||
|
u16 valid_data = data & mask;
|
||||||
|
bool is_negative = valid_data >> (valid_bit - 1);
|
||||||
|
|
||||||
|
return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||||
|
int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1;
|
||||||
|
long speed;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = kstrtol(buf, 10, &speed);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->fan_duty_cycle[nr] = speed;
|
||||||
|
ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
|
||||||
|
u16 value = 0;
|
||||||
|
int exponent, mantissa;
|
||||||
|
int multiplier = 1000;
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case PSU_V_OUT:
|
||||||
|
value = data->v_out;
|
||||||
|
break;
|
||||||
|
case PSU_I_OUT:
|
||||||
|
value = data->i_out;
|
||||||
|
break;
|
||||||
|
case PSU_P_OUT_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;
|
||||||
|
break;
|
||||||
|
case PSU_FAN1_SPEED:
|
||||||
|
value = data->fan_speed;
|
||||||
|
multiplier = 1;
|
||||||
|
break;
|
||||||
|
case PSU_FAN1_DUTY_CYCLE:
|
||||||
|
value = data->fan_duty_cycle[0];
|
||||||
|
multiplier = 1;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_VIN_MIN:
|
||||||
|
value = data->mfr_vin_min;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_VIN_MAX:
|
||||||
|
value = data->mfr_vin_max;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_VOUT_MIN:
|
||||||
|
value = data->mfr_vout_min;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_VOUT_MAX:
|
||||||
|
value = data->mfr_vout_max;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_PIN_MAX:
|
||||||
|
value = data->mfr_pin_max;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_POUT_MAX:
|
||||||
|
value = data->mfr_pout_max;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_IOUT_MAX:
|
||||||
|
value = data->mfr_iout_max;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_IIN_MAX:
|
||||||
|
value = data->mfr_iin_max;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
|
||||||
|
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
|
||||||
|
return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
|
||||||
|
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
|
||||||
|
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", data->fan_fault >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", data->over_temp >> 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
u8 *ptr = NULL;
|
||||||
|
|
||||||
|
switch (attr->index) {
|
||||||
|
case PSU_FAN_DIRECTION: /* psu_fan_dir */
|
||||||
|
if (data->chip==YPEB1200AM)
|
||||||
|
{
|
||||||
|
memcpy(data->fan_dir, "F2B", 3);
|
||||||
|
data->fan_dir[3]='\0';
|
||||||
|
}
|
||||||
|
ptr = data->fan_dir;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_ID: /* psu_mfr_id */
|
||||||
|
ptr = data->mfr_id;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_MODEL: /* psu_mfr_model */
|
||||||
|
ptr = data->mfr_model;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_REVISION: /* psu_mfr_revision */
|
||||||
|
ptr = data->mfr_revsion;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
|
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||||
|
int exponent, mantissa;
|
||||||
|
int multiplier = 1000;
|
||||||
|
|
||||||
|
if (!data->valid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
|
||||||
|
switch (attr->index) {
|
||||||
|
case PSU_MFR_VOUT_MIN:
|
||||||
|
mantissa = data->mfr_vout_min;
|
||||||
|
break;
|
||||||
|
case PSU_MFR_VOUT_MAX:
|
||||||
|
mantissa = data->mfr_vout_max;
|
||||||
|
break;
|
||||||
|
case PSU_V_OUT:
|
||||||
|
mantissa = data->v_out;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
|
||||||
|
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 *ptr = NULL;
|
||||||
|
|
||||||
|
ptr = data->mfr_model + 1; /* The first byte is the count byte of string. */
|
||||||
|
if (data->chip == YM2401) {
|
||||||
|
return show_vout_by_mode(dev, da, buf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return show_linear(dev, da, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct attribute_group ym2651y_group = {
|
||||||
|
.attrs = ym2651y_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ym2651y_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *dev_id)
|
||||||
|
{
|
||||||
|
struct ym2651y_data *data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(client->adapter,
|
||||||
|
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
|
I2C_FUNC_SMBUS_WORD_DATA |
|
||||||
|
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||||
|
status = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
status = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
data->chip = dev_id->driver_data;
|
||||||
|
dev_info(&client->dev, "chip found\n");
|
||||||
|
|
||||||
|
/* Register sysfs hooks */
|
||||||
|
status = sysfs_create_group(&client->dev.kobj, &ym2651y_group);
|
||||||
|
if (status) {
|
||||||
|
goto exit_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
|
status = PTR_ERR(data->hwmon_dev);
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&client->dev, "%s: psu '%s'\n",
|
||||||
|
dev_name(data->hwmon_dev), client->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_remove:
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
|
||||||
|
exit_free:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ym2651y_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
|
||||||
|
kfree(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id ym2651y_id[] = {
|
||||||
|
{ "ym2651", YM2651 },
|
||||||
|
{ "ym2401", YM2401 },
|
||||||
|
{ "ym2851", YM2851 },
|
||||||
|
{ "ype1200am", YPEB1200AM },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, ym2651y_id);
|
||||||
|
|
||||||
|
static struct i2c_driver ym2651y_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
|
.driver = {
|
||||||
|
.name = "ym2651",
|
||||||
|
},
|
||||||
|
.probe = ym2651y_probe,
|
||||||
|
.remove = ym2651y_remove,
|
||||||
|
.id_table = ym2651y_id,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ym2651y_read_byte(struct i2c_client *client, u8 reg)
|
||||||
|
{
|
||||||
|
return i2c_smbus_read_byte_data(client, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ym2651y_read_word(struct i2c_client *client, u8 reg)
|
||||||
|
{
|
||||||
|
return i2c_smbus_read_word_data(client, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value)
|
||||||
|
{
|
||||||
|
return i2c_smbus_write_word_data(client, reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data,
|
||||||
|
int data_len)
|
||||||
|
{
|
||||||
|
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
|
||||||
|
|
||||||
|
if (unlikely(result < 0))
|
||||||
|
goto abort;
|
||||||
|
if (unlikely(result != data_len)) {
|
||||||
|
result = -EIO;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reg_data_byte {
|
||||||
|
u8 reg;
|
||||||
|
u8 *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reg_data_word {
|
||||||
|
u8 reg;
|
||||||
|
u16 *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
|
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||||
|
|| !data->valid) {
|
||||||
|
int i, status;
|
||||||
|
u8 command;
|
||||||
|
u8 fan_dir[5] = {0};
|
||||||
|
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
|
||||||
|
{0x20, &data->vout_mode},
|
||||||
|
{0x7d, &data->over_temp},
|
||||||
|
{0x81, &data->fan_fault},
|
||||||
|
{0x98, &data->pmbus_revision}
|
||||||
|
};
|
||||||
|
struct reg_data_word regs_word[] = { {0x79, &data->status_word},
|
||||||
|
{0x8b, &data->v_out},
|
||||||
|
{0x8c, &data->i_out},
|
||||||
|
{0x96, &data->p_out},
|
||||||
|
{0x8d, &data->temp},
|
||||||
|
{0x3b, &(data->fan_duty_cycle[0])},
|
||||||
|
{0x3c, &(data->fan_duty_cycle[1])},
|
||||||
|
{0x90, &data->fan_speed},
|
||||||
|
{0xa0, &data->mfr_vin_min},
|
||||||
|
{0xa1, &data->mfr_vin_max},
|
||||||
|
{0xa2, &data->mfr_iin_max},
|
||||||
|
{0xa3, &data->mfr_pin_max},
|
||||||
|
{0xa4, &data->mfr_vout_min},
|
||||||
|
{0xa5, &data->mfr_vout_max},
|
||||||
|
{0xa6, &data->mfr_iout_max},
|
||||||
|
{0xa7, &data->mfr_pout_max}
|
||||||
|
};
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "Starting ym2651 update\n");
|
||||||
|
|
||||||
|
/* Read byte data */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
|
||||||
|
status = ym2651y_read_byte(client, regs_byte[i].reg);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||||
|
regs_byte[i].reg, status);
|
||||||
|
*(regs_byte[i].value) = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*(regs_byte[i].value) = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read word data */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
|
||||||
|
status = ym2651y_read_word(client, regs_word[i].reg);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||||
|
regs_word[i].reg, status);
|
||||||
|
*(regs_word[i].value) = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*(regs_word[i].value) = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read fan_direction */
|
||||||
|
command = 0xC3;
|
||||||
|
status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1);
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1);
|
||||||
|
data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0';
|
||||||
|
|
||||||
|
/* Read mfr_id */
|
||||||
|
command = 0x99;
|
||||||
|
status = ym2651y_read_block(client, command, data->mfr_id,
|
||||||
|
ARRAY_SIZE(data->mfr_id)-1);
|
||||||
|
data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0';
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||||
|
|
||||||
|
/* Read mfr_model */
|
||||||
|
command = 0x9a;
|
||||||
|
status = ym2651y_read_block(client, command, data->mfr_model,
|
||||||
|
ARRAY_SIZE(data->mfr_model)-1);
|
||||||
|
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||||
|
|
||||||
|
/* Read mfr_revsion */
|
||||||
|
command = 0x9b;
|
||||||
|
status = ym2651y_read_block(client, command, data->mfr_revsion,
|
||||||
|
ARRAY_SIZE(data->mfr_revsion)-1);
|
||||||
|
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||||
|
|
||||||
|
data->last_updated = jiffies;
|
||||||
|
data->valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_i2c_driver(ym2651y_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Michael Shih <michael_shih@edge-core.com>");
|
||||||
|
MODULE_DESCRIPTION("3Y Power YM-2651Y driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Accton AS9726_32D Platform Monitoring FAN service
|
||||||
|
Before=pmon.service
|
||||||
|
After=as9726-32d-platform-monitor.service
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/accton_as9726_32d_monitor_fan.py
|
||||||
|
KillSignal=SIGKILL
|
||||||
|
SuccessExitStatus=SIGKILL
|
||||||
|
|
||||||
|
# Resource Limitations
|
||||||
|
LimitCORE=infinity
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Accton AS9726_32D Platform Monitoring PSU service
|
||||||
|
Before=pmon.service
|
||||||
|
After=as9726-32d-platform-monitor.service
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/accton_as9726_32d_monitor_psu.py
|
||||||
|
KillSignal=SIGKILL
|
||||||
|
SuccessExitStatus=SIGKILL
|
||||||
|
|
||||||
|
# Resource Limitations
|
||||||
|
LimitCORE=infinity
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Accton AS9726_32D Platform Monitoring service
|
||||||
|
Before=pmon.service
|
||||||
|
After=sysinit.target
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/usr/local/bin/accton_as9726_32d_util.py install
|
||||||
|
ExecStart=/usr/local/bin/accton_as9726_32d_monitor.py
|
||||||
|
KillSignal=SIGKILL
|
||||||
|
SuccessExitStatus=SIGKILL
|
||||||
|
|
||||||
|
# Resource Limitations
|
||||||
|
LimitCORE=infinity
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
14
platform/broadcom/sonic-platform-modules-accton/as9726-32d/setup.py
Executable file
14
platform/broadcom/sonic-platform-modules-accton/as9726-32d/setup.py
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
from setuptools import setup
|
||||||
|
os.listdir
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='as9726_32d',
|
||||||
|
version='1.0',
|
||||||
|
description='Module to initialize Accton AS9726_32D platforms',
|
||||||
|
|
||||||
|
packages=['as9726_32d'],
|
||||||
|
package_dir={'as9726_32d': 'as9726-32d/classes'},
|
||||||
|
)
|
@ -0,0 +1,34 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
DEVICE_NAME = 'accton'
|
||||||
|
HW_SKU = 'x86_64-accton_as9726_32d-r0'
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sonic-platform',
|
||||||
|
version='1.0',
|
||||||
|
description='SONiC platform API implementation on Accton Platforms',
|
||||||
|
license='Apache 2.0',
|
||||||
|
author='SONiC Team',
|
||||||
|
author_email='linuxnetdev@microsoft.com',
|
||||||
|
url='https://github.com/Azure/sonic-buildimage',
|
||||||
|
maintainer='Michael Shih',
|
||||||
|
maintainer_email='michael_shih@edge-core.com',
|
||||||
|
packages=[
|
||||||
|
'sonic_platform',
|
||||||
|
],
|
||||||
|
package_dir={
|
||||||
|
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 3 - Alpha',
|
||||||
|
'Environment :: Plugins',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Information Technology',
|
||||||
|
'Intended Audience :: System Administrators',
|
||||||
|
'License :: OSI Approved :: Apache Software License',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Topic :: Utilities',
|
||||||
|
],
|
||||||
|
keywords='sonic SONiC platform PLATFORM',
|
||||||
|
)
|
65
platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/README
Executable file
65
platform/broadcom/sonic-platform-modules-accton/as9726-32d/utils/README
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
Copyright (C) 2019 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/>.
|
||||||
|
|
||||||
|
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 AS9726-32D has 2 parts,
|
||||||
|
kernel drivers and operational script.
|
||||||
|
The kernel drivers of peripherals are under module/ directory.
|
||||||
|
1. These drivers are at module dir.
|
||||||
|
2. A operational script, accton_as9726_32d_util.py, for device initializatian and
|
||||||
|
peripheral accessing should be installed at /usr/bin.
|
||||||
|
Run "accton_as9726_32d_util.py install" to install drivers.
|
||||||
|
|
||||||
|
To initialize the system, run "accton_as9726_32d_util.py install".
|
||||||
|
To clean up the drivers & devices, run "accton_as9726_32d_util.py clean".
|
||||||
|
To dump information of sensors, run "accton_as9726_32d_util.py show".
|
||||||
|
To dump SFP EEPROM, run "accton_as9726_32d_util.py sff".
|
||||||
|
To set fan speed, run "accton_as9726_32d_util.py set fan".
|
||||||
|
To enable/disable SFP emission, run "accton_as9726_32d_util.py set sfp".
|
||||||
|
To set system LEDs' color, run "accton_as9726_32d_util.py set led"
|
||||||
|
For more information, run "accton_as9726_32d_util.py --help".
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
Besides applying accton_as9726_32d_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, psu1, psu2 and fan.
|
||||||
|
The sysfs interface color mappings are as follows:
|
||||||
|
Brightness:
|
||||||
|
0 => off
|
||||||
|
1 => green
|
||||||
|
2 => amber
|
||||||
|
But not all colors are available for each LED.
|
||||||
|
|
||||||
|
Fan Control:
|
||||||
|
There are 12 fans inside 6 fan modules.
|
||||||
|
All fans share 1 duty setting, ranged from 0~100.
|
||||||
|
|
||||||
|
Thermal sensers:
|
||||||
|
6 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 QSFP56-DD and 2 SFP+ modules are equipped.
|
||||||
|
Before operating on PSU and QSFP+, please make sure it is well plugged.
|
||||||
|
Otherwise, operation is going to fail.
|
||||||
|
|
@ -0,0 +1,565 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*
|
||||||
|
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||||
|
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||||
|
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||||
|
#
|
||||||
|
# See the Apache Version 2.0 License for specific language governing
|
||||||
|
# permissions and limitations under the License.
|
||||||
|
#
|
||||||
|
# HISTORY:
|
||||||
|
# mm/dd/yyyy (A.D.)#
|
||||||
|
# 04/23/2021: Michael_Shih create for as9726_32d thermal plan
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
try:
|
||||||
|
import commands
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import logging.handlers
|
||||||
|
import time # this is only being used as part of the example
|
||||||
|
from as9726_32d.fanutil import FanUtil
|
||||||
|
from as9726_32d.thermalutil import ThermalUtil
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError('%s - required module not found' % str(e))
|
||||||
|
|
||||||
|
# Deafults
|
||||||
|
VERSION = '1.0'
|
||||||
|
FUNCTION_NAME = '/usr/local/bin/accton_as9726_32d_monitor'
|
||||||
|
|
||||||
|
class switch(object):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.fall = False
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Return the match method once, then stop"""
|
||||||
|
yield self.match
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def match(self, *args):
|
||||||
|
"""Indicate whether or not to enter a case suite"""
|
||||||
|
if self.fall or not args:
|
||||||
|
return True
|
||||||
|
elif self.value in args: # changed for v1.5, see below
|
||||||
|
self.fall = True
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Read fanN_direction=1: The air flow of Fan6 is “AFI-Back to Front”
|
||||||
|
# 0: The air flow of Fan6 is “AFO-Front to back”
|
||||||
|
#
|
||||||
|
# Thermal policy:
|
||||||
|
# a.Defaut fan duty_cycle=100%
|
||||||
|
# b.One fan fail, set to fan duty_cycle=100%
|
||||||
|
# 1.For AFI:
|
||||||
|
# Default fan duty_cycle will be 100%(fan_policy_state=LEVEL_FAN_MAX).
|
||||||
|
# If all below case meet with, set to 75%(LEVEL_FAN_MID).
|
||||||
|
# MB board
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)>=49.5
|
||||||
|
# LM75-2(0X49)>=42.9
|
||||||
|
# LM75-3(0X4A)>=46.3
|
||||||
|
# LM75-4(0X4C)>=40.1
|
||||||
|
# LM75-6(0X4F)>=39.4
|
||||||
|
# (CPU board)
|
||||||
|
# Core>=46
|
||||||
|
# LM75-1(0X4B)>=34.8
|
||||||
|
|
||||||
|
# When fan_policy_state=LEVEL_FAN_MID, meet with below case, Fan duty_cycle will be 100%(LEVEL_FAN_DAX)
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)>=55.9
|
||||||
|
# LM75-2(0X49)>=48.8
|
||||||
|
# LM75-3(0X4A)>=51.5
|
||||||
|
# LM75-4(0X4C)>=45.3
|
||||||
|
# LM75-6(0X4F)>=43.4
|
||||||
|
# (CPU board)
|
||||||
|
# Core>=50
|
||||||
|
# LM75-1(0X4B)>=43.4
|
||||||
|
|
||||||
|
#Yellow Alarm
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=57.9
|
||||||
|
#LM75-2(0X49)>=51.9
|
||||||
|
#LM75-3(0X4A)>=48.9
|
||||||
|
#LM75-4(0X4C)>=55.9
|
||||||
|
#LM75-6(0X4F)>=48.5
|
||||||
|
#CPU Board
|
||||||
|
#Core>=52
|
||||||
|
#LM75-1(0X4B)>=41.8
|
||||||
|
|
||||||
|
#Red Alarm
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=62.9
|
||||||
|
#LM75-2(0X49)>=56.9
|
||||||
|
#LM75-3(0X4A)>=53.9
|
||||||
|
#LM75-4(0X4C)>=58.9
|
||||||
|
#LM75-6(0X4F)>=53.5
|
||||||
|
#CPU Board
|
||||||
|
#Core>=57
|
||||||
|
#LM75-1(0X4B)>=46.8
|
||||||
|
|
||||||
|
#Shut down
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=67.9
|
||||||
|
#LM75-2(0X49)>=61.9
|
||||||
|
#LM75-3(0X4A)>=58.9
|
||||||
|
#LM75-4(0X4C)>=63.9
|
||||||
|
#LM75-6(0X4F)>=58.5
|
||||||
|
#CPU Board
|
||||||
|
#Core>=62
|
||||||
|
#LM75-1(0X4B)>=51.8
|
||||||
|
|
||||||
|
# 2. For AFO:
|
||||||
|
# At default, FAN duty_cycle was 100%(LEVEL_FAN_MAX). If all below case meet with, set to 75%(LEVEL_FAN_MID).
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)<=56
|
||||||
|
# LM75-2(0X49)<=53.5
|
||||||
|
# LM75-3(0X4A)<=52.5
|
||||||
|
# LM75-4(0X4C)<=52
|
||||||
|
# LM75-6(0X4F)<=52.8
|
||||||
|
# (CPU board)
|
||||||
|
# Core<=62
|
||||||
|
# LM75-1(0X4B)<=45.8
|
||||||
|
|
||||||
|
# When FAN duty_cycle was 75%(LEVEL_FAN_MID). If all below case meet with, set to 50%(LEVEL_FAN_DEF).
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)<=50
|
||||||
|
# LM75-2(0X49)<=47.3
|
||||||
|
# LM75-3(0X4A)<=46.4
|
||||||
|
# LM75-4(0X4C)<=44.6
|
||||||
|
# LM75-6(0X4F)<=47
|
||||||
|
# (CPU board)
|
||||||
|
# Core<=56
|
||||||
|
# LM75-1(0X4B)<=38.8
|
||||||
|
|
||||||
|
# When fan_speed 50%(LEVEL_FAN_DEF).
|
||||||
|
# Meet with below case, Fan duty_cycle will be 75%(LEVEL_FAN_MID)
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)>=63
|
||||||
|
# LM75-2(0X49)>=60.5
|
||||||
|
# LM75-3(0X4A)>=60
|
||||||
|
# LM75-4(0X4C)>=60
|
||||||
|
# LM75-6(0X4F)>=61
|
||||||
|
# (CPU board)
|
||||||
|
# Core>=72
|
||||||
|
# LM75-1(0X4B)>=50
|
||||||
|
|
||||||
|
# When FAN duty_cycle was 75%(LEVEL_FAN_MID). If all below case meet with, set to 100%(LEVEL_FAN_MAX).
|
||||||
|
# (MB board)
|
||||||
|
# LM75-1(0X48)>=63
|
||||||
|
# LM75-2(0X49)>=60
|
||||||
|
# LM75-3(0X4A)>=60
|
||||||
|
# LM75-4(0X4C)>=59
|
||||||
|
# LM75-6(0X4F)>=60
|
||||||
|
|
||||||
|
# (CPU board)
|
||||||
|
# Core >=69
|
||||||
|
# LM75-1(0X4B)>=51.5
|
||||||
|
|
||||||
|
|
||||||
|
#Yellow Alarm
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=67
|
||||||
|
#LM75-2(0X49)>=65
|
||||||
|
#LM75-3(0X4A)>=64
|
||||||
|
#LM75-4(0X4C)>=62
|
||||||
|
#LM75-6(0X4F)>=64
|
||||||
|
#CPU Board
|
||||||
|
#Core>=73
|
||||||
|
#LM75-1(0X4B)>=67
|
||||||
|
|
||||||
|
#Red Alarm
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=72
|
||||||
|
#LM75-2(0X49)>=70
|
||||||
|
#LM75-3(0X4A)>=69
|
||||||
|
#LM75-4(0X4C)>=67
|
||||||
|
#LM75-6(0X4F)>=69
|
||||||
|
#CPU Board
|
||||||
|
#Core>=78
|
||||||
|
#LM75-1(0X4B)>=72
|
||||||
|
|
||||||
|
#Shut down
|
||||||
|
#MB board
|
||||||
|
#LM75-1(0X48)>=77
|
||||||
|
#LM75-2(0X49)>=75
|
||||||
|
#LM75-3(0X4A)>=74
|
||||||
|
#LM75-4(0X4C)>=72
|
||||||
|
#LM75-6(0X4F)>=74
|
||||||
|
#CPU Board
|
||||||
|
#Core>=83
|
||||||
|
#LM75-1(0X4B)>=77
|
||||||
|
|
||||||
|
def power_off_dut():
|
||||||
|
cmd_str="i2cset -y -f 1 0x60 0x60 0x10"
|
||||||
|
status, output = commands.getstatusoutput(cmd_str)
|
||||||
|
return status
|
||||||
|
|
||||||
|
#If only one PSU insert(or one of PSU pwoer fail), and watt >800w. Must let DUT fan pwm >= 75% in AFO.
|
||||||
|
# Because the psu temp is high.
|
||||||
|
# Return 1: full load
|
||||||
|
# Return 0: Not full load
|
||||||
|
def check_psu_loading():
|
||||||
|
psu_power_status=[1, 1]
|
||||||
|
|
||||||
|
psu_power_good = {
|
||||||
|
2: "/sys/bus/i2c/devices/9-0051/psu_power_good",
|
||||||
|
1: "/sys/bus/i2c/devices/9-0050/psu_power_good",
|
||||||
|
}
|
||||||
|
psu_power_out = {
|
||||||
|
2: "/sys/bus/i2c/devices/9-0059/psu_p_out",
|
||||||
|
1: "/sys/bus/i2c/devices/9-0058/psu_p_out",
|
||||||
|
}
|
||||||
|
|
||||||
|
check_psu_watt=0
|
||||||
|
for i in range(1,3):
|
||||||
|
node = psu_power_good[i]
|
||||||
|
try:
|
||||||
|
with open(node, 'r') as power_status:
|
||||||
|
status = int(power_status.read())
|
||||||
|
except IOError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
psu_power_status[i-1]=int(status)
|
||||||
|
if status==0:
|
||||||
|
check_psu_watt=1
|
||||||
|
|
||||||
|
if check_psu_watt:
|
||||||
|
for i in range(1,3):
|
||||||
|
if psu_power_status[i-1]==1:
|
||||||
|
#check watt
|
||||||
|
node = psu_power_out[i]
|
||||||
|
try:
|
||||||
|
with open(node, 'r') as power_status:
|
||||||
|
status = int(power_status.read())
|
||||||
|
except IOError:
|
||||||
|
return None
|
||||||
|
psu_p_out= int(status)
|
||||||
|
if psu_p_out/1000 > 800:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
fan_policy_state=0
|
||||||
|
fan_policy_alarm=0
|
||||||
|
send_yellow_alarm=0
|
||||||
|
send_red_alarm=0
|
||||||
|
fan_fail=0
|
||||||
|
count_check=0
|
||||||
|
|
||||||
|
test_temp = 0
|
||||||
|
test_temp_list = [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
temp_test_data=0
|
||||||
|
test_temp_revert=0
|
||||||
|
|
||||||
|
# Make a class we can use to capture stdout and sterr in the log
|
||||||
|
class device_monitor(object):
|
||||||
|
# static temp var
|
||||||
|
temp = 0
|
||||||
|
new_duty_cycle = 0
|
||||||
|
duty_cycle=0
|
||||||
|
ori_duty_cycle = 0
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, log_file, log_level):
|
||||||
|
"""Needs a logger and a logger level."""
|
||||||
|
|
||||||
|
self.thermal = ThermalUtil()
|
||||||
|
self.fan = FanUtil()
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||||
|
sys_handler.setLevel(logging.WARNING)
|
||||||
|
logging.getLogger('').addHandler(sys_handler)
|
||||||
|
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||||
|
|
||||||
|
|
||||||
|
def manage_fans(self):
|
||||||
|
|
||||||
|
global fan_policy_state
|
||||||
|
global fan_policy_alarm
|
||||||
|
global send_yellow_alarm
|
||||||
|
global send_red_alarm
|
||||||
|
global fan_fail
|
||||||
|
global count_check
|
||||||
|
global test_temp
|
||||||
|
global test_temp_list
|
||||||
|
global temp_test_data
|
||||||
|
global test_temp_revert
|
||||||
|
|
||||||
|
CHECK_TIMES=3
|
||||||
|
|
||||||
|
LEVEL_FAN_INIT=0
|
||||||
|
LEVEL_FAN_MIN=1
|
||||||
|
LEVEL_FAN_MID=2
|
||||||
|
LEVEL_FAN_MAX=3
|
||||||
|
LEVEL_FAN_YELLOW_ALARM=4
|
||||||
|
LEVEL_FAN_RED_ALARM=5
|
||||||
|
LEVEL_FAN_SHUTDOWN=6
|
||||||
|
|
||||||
|
fan_policy_f2b = { #AFO
|
||||||
|
LEVEL_FAN_MIN: [50, 0x7],
|
||||||
|
LEVEL_FAN_MID: [75, 0xb],
|
||||||
|
LEVEL_FAN_MAX: [100, 0xf]
|
||||||
|
}
|
||||||
|
fan_policy_b2f = { #AFI
|
||||||
|
LEVEL_FAN_MID: [75, 0xb],
|
||||||
|
LEVEL_FAN_MAX: [100, 0xf]
|
||||||
|
}
|
||||||
|
|
||||||
|
afi_thermal_spec={
|
||||||
|
"mid_to_max_temp":[61500, 51500, 49400, 49400, 45100, 46750, 48000, 38500],
|
||||||
|
"max_to_mid_temp":[57000, 47300, 45000, 45100, 40750, 42100, 44000, 35000],
|
||||||
|
"max_to_yellow_alarm": [57900, 51900, 48900, 55900, 48500, 52000, 41800],
|
||||||
|
"yellow_to_red_alarm": [62900, 56900, 53900, 58900, 53500, 57000, 46800],
|
||||||
|
"red_alarm_to_shutdown": [67900, 61900, 58900, 63900, 58500, 62000, 51800]
|
||||||
|
}
|
||||||
|
afo_thermal_spec={
|
||||||
|
"min_to_mid_temp": [63000, 60500, 60000, 60000, 61000, 72000, 50000],
|
||||||
|
"mid_to_max_temp": [63000, 60000, 60000, 59000, 60000, 69000, 51500],
|
||||||
|
"max_to_mid_temp": [56000, 53500, 52500, 52000, 52800, 62000, 45800],
|
||||||
|
"mid_to_min_temp": [50000, 47300, 46400, 44600, 47000, 56000, 38800],
|
||||||
|
"max_to_yellow_alarm": [67000, 65000, 64000, 62000, 64000, 73000, 67000],
|
||||||
|
"yellow_to_red_alarm": [72000, 70000, 69000, 67000, 69000, 78000, 72000],
|
||||||
|
"red_alarm_to_shutdown": [77000, 75000, 74000, 72000, 74000, 83000, 77000]
|
||||||
|
}
|
||||||
|
|
||||||
|
thermal_val=[0,0,0,0,0,0,0]
|
||||||
|
max_to_mid=0
|
||||||
|
mid_to_min=0
|
||||||
|
|
||||||
|
fan = self.fan
|
||||||
|
if fan_policy_state==LEVEL_FAN_INIT:
|
||||||
|
fan_policy_state=LEVEL_FAN_MAX #This is default state
|
||||||
|
logging.debug("fan_policy_state=LEVEL_FAN_MAX")
|
||||||
|
return
|
||||||
|
|
||||||
|
count_check=count_check+1
|
||||||
|
if count_check < CHECK_TIMES:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
count_check=0
|
||||||
|
|
||||||
|
thermal = self.thermal
|
||||||
|
fan_dir=fan.get_fan_dir(1)
|
||||||
|
|
||||||
|
if fan_dir==1: # AFI
|
||||||
|
fan_thermal_spec = afi_thermal_spec
|
||||||
|
fan_policy=fan_policy_b2f
|
||||||
|
elif fan_dir==0: # AFO
|
||||||
|
fan_thermal_spec = afo_thermal_spec
|
||||||
|
fan_policy=fan_policy_f2b
|
||||||
|
else:
|
||||||
|
logging.debug( "NULL case")
|
||||||
|
|
||||||
|
ori_duty_cycle=fan.get_fan_duty_cycle()
|
||||||
|
new_duty_cycle=0
|
||||||
|
|
||||||
|
if test_temp_revert==0:
|
||||||
|
temp_test_data=temp_test_data+2000
|
||||||
|
else:
|
||||||
|
temp_test_data=temp_test_data-2000
|
||||||
|
|
||||||
|
if test_temp==0:
|
||||||
|
for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1):
|
||||||
|
thermal_val[i-1]=thermal._get_thermal_val(i)
|
||||||
|
else:
|
||||||
|
for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1):
|
||||||
|
thermal_val[i-1]=test_temp_list[i-1]
|
||||||
|
thermal_val[i-1]= thermal_val[i-1] + temp_test_data
|
||||||
|
logging.debug(thermal_val)
|
||||||
|
fan_fail=0
|
||||||
|
|
||||||
|
ori_state=fan_policy_state;
|
||||||
|
current_state=fan_policy_state;
|
||||||
|
|
||||||
|
if fan_dir==1: #AFI
|
||||||
|
for i in range (0, thermal.THERMAL_NUM_MAX):
|
||||||
|
if ori_state==LEVEL_FAN_MID:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["mid_to_max_temp"][i]:
|
||||||
|
current_state=LEVEL_FAN_MAX
|
||||||
|
logging.debug("current_state=LEVEL_FAN_MAX")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if (thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i]):
|
||||||
|
max_to_mid=max_to_mid+1
|
||||||
|
if fan_policy_alarm==0:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["max_to_yellow_alarm"][i]:
|
||||||
|
if send_yellow_alarm==0:
|
||||||
|
logging.warning('Alarm-Yellow for temperature high is detected')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_YELLOW_ALARM
|
||||||
|
send_yellow_alarm=1
|
||||||
|
elif fan_policy_alarm==LEVEL_FAN_YELLOW_ALARM:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["yellow_to_red_alarm"][i]:
|
||||||
|
if send_red_alarm==0:
|
||||||
|
logging.warning('Alarm-Red for temperature high is detected')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_RED_ALARM
|
||||||
|
send_red_alarm=1
|
||||||
|
elif fan_policy_alarm==LEVEL_FAN_RED_ALARM:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["red_alarm_to_shutdown"][i]:
|
||||||
|
logging.critical('Alarm-Critical for temperature high is detected, shutdown DUT')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_SHUTDOWN
|
||||||
|
time.sleep(2)
|
||||||
|
power_off_dut()
|
||||||
|
|
||||||
|
if max_to_mid==thermal.THERMAL_NUM_MAX and fan_policy_state==LEVEL_FAN_MAX:
|
||||||
|
current_state=LEVEL_FAN_MID
|
||||||
|
if fan_policy_alarm!=0:
|
||||||
|
logging.warning('Alarm for temperature high is cleared')
|
||||||
|
fan_policy_alarm=0
|
||||||
|
send_yellow_alarm=0
|
||||||
|
send_red_alarm=0
|
||||||
|
test_temp_revert=0
|
||||||
|
logging.debug("current_state=LEVEL_FAN_MID")
|
||||||
|
|
||||||
|
else: #AFO
|
||||||
|
psu_full_load=check_psu_loading()
|
||||||
|
for i in range (0, thermal.THERMAL_NUM_MAX):
|
||||||
|
if ori_state==LEVEL_FAN_MID:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["mid_to_max_temp"][i]:
|
||||||
|
current_state=LEVEL_FAN_MAX
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if psu_full_load!=True and thermal_val[i] <= fan_thermal_spec["mid_to_min_temp"][i]:
|
||||||
|
mid_to_min=mid_to_min+1
|
||||||
|
|
||||||
|
elif ori_state==LEVEL_FAN_MIN:
|
||||||
|
if psu_full_load==True:
|
||||||
|
current_state=LEVEL_FAN_MID
|
||||||
|
logging.debug("psu_full_load, set current_state=LEVEL_FAN_MID")
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["min_to_mid_temp"][i]:
|
||||||
|
current_state=LEVEL_FAN_MID
|
||||||
|
|
||||||
|
else:
|
||||||
|
if thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i] :
|
||||||
|
max_to_mid=max_to_mid+1
|
||||||
|
if fan_policy_alarm==0:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["max_to_yellow_alarm"][i]:
|
||||||
|
if send_yellow_alarm==0:
|
||||||
|
logging.warning('Alarm-Yellow for temperature high is detected')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_YELLOW_ALARM
|
||||||
|
send_yellow_alarm=1
|
||||||
|
elif fan_policy_alarm==LEVEL_FAN_YELLOW_ALARM:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["yellow_to_red_alarm"][i]:
|
||||||
|
if send_red_alarm==0:
|
||||||
|
logging.warning('Alarm-Red for temperature high is detected')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_RED_ALARM
|
||||||
|
send_red_alarm=1
|
||||||
|
elif fan_policy_alarm==LEVEL_FAN_RED_ALARM:
|
||||||
|
if thermal_val[i] >= fan_thermal_spec["red_alarm_to_shutdown"][i]:
|
||||||
|
logging.critical('Alarm-Critical for temperature high is detected, shutdown DUT')
|
||||||
|
fan_policy_alarm=LEVEL_FAN_SHUTDOWN
|
||||||
|
time.sleep(2)
|
||||||
|
power_off_dut()
|
||||||
|
|
||||||
|
if max_to_mid==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MAX:
|
||||||
|
current_state=LEVEL_FAN_MID
|
||||||
|
if fan_policy_alarm!=0:
|
||||||
|
logging.warning('Alarm for temperature high is cleared')
|
||||||
|
fan_policy_alarm=0
|
||||||
|
send_yellow_alarm=0
|
||||||
|
send_red_alarm=0
|
||||||
|
test_temp_revert=0
|
||||||
|
logging.debug("current_state=LEVEL_FAN_MID")
|
||||||
|
|
||||||
|
if mid_to_min==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MID:
|
||||||
|
if psu_full_load==0:
|
||||||
|
current_state=LEVEL_FAN_MIN
|
||||||
|
logging.debug("current_state=LEVEL_FAN_MIN")
|
||||||
|
|
||||||
|
#Check Fan fault status. True: fan not fault/present, 1: fan fault/un-present
|
||||||
|
for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1):
|
||||||
|
if fan.get_fan_status(i)==False:
|
||||||
|
new_duty_cycle=100
|
||||||
|
current_state=LEVEL_FAN_MAX
|
||||||
|
logging.debug('fan_%d fail, set duty_cycle to 100',i)
|
||||||
|
if test_temp==0:
|
||||||
|
fan_fail=1
|
||||||
|
fan.set_fan_duty_cycle(new_duty_cycle)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
fan_fail=0
|
||||||
|
|
||||||
|
if current_state!=ori_state:
|
||||||
|
fan_policy_state=current_state
|
||||||
|
new_duty_cycle=fan_policy[current_state][0]
|
||||||
|
logging.debug("fan_policy_state=%d, new_duty_cycle=%d", fan_policy_state, new_duty_cycle)
|
||||||
|
if new_duty_cycle!=ori_duty_cycle and fan_fail==0:
|
||||||
|
fan.set_fan_duty_cycle(new_duty_cycle)
|
||||||
|
return True
|
||||||
|
if new_duty_cycle==0 and fan_fail==0:
|
||||||
|
fan.set_fan_duty_cycle(FAN_DUTY_CYCLE_MAX)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
log_file = '%s.log' % FUNCTION_NAME
|
||||||
|
log_level = logging.INFO
|
||||||
|
global test_temp
|
||||||
|
if len(sys.argv) != 1:
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(argv,'hdlt:',['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
|
||||||
|
|
||||||
|
if sys.argv[1]== '-t':
|
||||||
|
if len(sys.argv)!=9:
|
||||||
|
print "temp test, need input 7 temp"
|
||||||
|
return 0
|
||||||
|
i=0
|
||||||
|
for x in range(2, 9):
|
||||||
|
test_temp_list[i]= int(sys.argv[x])*1000
|
||||||
|
i=i+1
|
||||||
|
test_temp = 1
|
||||||
|
log_level = logging.DEBUG
|
||||||
|
print test_temp_list
|
||||||
|
|
||||||
|
fan = FanUtil()
|
||||||
|
fan.set_fan_duty_cycle(100)
|
||||||
|
monitor = device_monitor(log_file, log_level)
|
||||||
|
# Loop forever, doing something useful hopefully:
|
||||||
|
while True:
|
||||||
|
monitor.manage_fans()
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv[1:])
|
@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 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.)
|
||||||
|
# 04/23/2021: Michael_Shih create for as9726-32d
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
try:
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import logging.handlers
|
||||||
|
import time # this is only being used as part of the example
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError('%s - required module not found' % str(e))
|
||||||
|
|
||||||
|
# Deafults
|
||||||
|
VERSION = '1.0'
|
||||||
|
FUNCTION_NAME = '/usr/local/bin/accton_as9726_32d_monitor_fan'
|
||||||
|
|
||||||
|
class switch(object):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.fall = False
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Return the match method once, then stop"""
|
||||||
|
yield self.match
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def match(self, *args):
|
||||||
|
"""Indicate whether or not to enter a case suite"""
|
||||||
|
if self.fall or not args:
|
||||||
|
return True
|
||||||
|
elif self.value in args: # changed for v1.5, see below
|
||||||
|
self.fall = True
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
fan_state=[2, 2, 2, 2, 2, 2] #init state=2, insert=1, remove=0
|
||||||
|
fan_status_state=[2, 2, 2, 2, 2, 2] #init state=2, fault=1, normal=0
|
||||||
|
# Make a class we can use to capture stdout and sterr in the log
|
||||||
|
class device_monitor(object):
|
||||||
|
|
||||||
|
def __init__(self, log_file, log_level):
|
||||||
|
|
||||||
|
self.fan_num = 6
|
||||||
|
self.fan_path = "/sys/bus/i2c/devices/14-0066/"
|
||||||
|
self.present = {
|
||||||
|
0: "fan1_present",
|
||||||
|
1: "fan2_present",
|
||||||
|
2: "fan3_present",
|
||||||
|
3: "fan4_present",
|
||||||
|
4: "fan5_present",
|
||||||
|
5: "fan6_present",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fault = {
|
||||||
|
0: "fan1_fault",
|
||||||
|
1: "fan2_fault",
|
||||||
|
2: "fan3_fault",
|
||||||
|
3: "fan4_fault",
|
||||||
|
4: "fan5_fault",
|
||||||
|
5: "fan6_fault",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
"""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(logging.DEBUG)
|
||||||
|
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||||
|
console.setFormatter(formatter)
|
||||||
|
logging.getLogger('').addHandler(console)
|
||||||
|
|
||||||
|
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||||
|
#sys_handler.setLevel(logging.WARNING)
|
||||||
|
sys_handler.setLevel(logging.INFO)
|
||||||
|
logging.getLogger('').addHandler(sys_handler)
|
||||||
|
|
||||||
|
|
||||||
|
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||||
|
|
||||||
|
def manage_fan(self):
|
||||||
|
|
||||||
|
FAN_STATE_REMOVE = 0
|
||||||
|
FAN_STATE_INSERT = 1
|
||||||
|
|
||||||
|
FAN_STATUS_FAULT = 1
|
||||||
|
FAN_STATUS_NORMAL = 0
|
||||||
|
|
||||||
|
global fan_state
|
||||||
|
global fan_status_state
|
||||||
|
|
||||||
|
for idx in range (0, self.fan_num):
|
||||||
|
node = self.fan_path + self.present[idx]
|
||||||
|
try:
|
||||||
|
val_file = open(node)
|
||||||
|
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":
|
||||||
|
if fan_state[idx]!=1:
|
||||||
|
fan_state[idx]=FAN_STATE_INSERT
|
||||||
|
logging.info("FAN-%d present is detected", idx+1);
|
||||||
|
else:
|
||||||
|
if fan_state[idx]!=0:
|
||||||
|
fan_state[idx]=FAN_STATE_REMOVE
|
||||||
|
logging.warning("Alarm for FAN-%d absent is detected", idx+1)
|
||||||
|
|
||||||
|
for idx in range (0, self.fan_num):
|
||||||
|
node = self.fan_path + self.fault[idx]
|
||||||
|
try:
|
||||||
|
val_file = open(node)
|
||||||
|
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":
|
||||||
|
if fan_status_state[idx]!=FAN_STATUS_FAULT:
|
||||||
|
if fan_state[idx] == FAN_STATE_INSERT:
|
||||||
|
logging.warning("Alarm for FAN-%d failed is detected", idx+1);
|
||||||
|
fan_status_state[idx]=FAN_STATUS_FAULT
|
||||||
|
else:
|
||||||
|
fan_status_state[idx]=FAN_STATUS_NORMAL
|
||||||
|
|
||||||
|
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 = device_monitor(log_file, log_level)
|
||||||
|
while True:
|
||||||
|
monitor.manage_fan()
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv[1:])
|
@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 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.)
|
||||||
|
# 04/23/2021: Michael_shih create for as9726-32d
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
try:
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import logging.handlers
|
||||||
|
import time # this is only being used as part of the example
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError('%s - required module not found' % str(e))
|
||||||
|
|
||||||
|
# Deafults
|
||||||
|
VERSION = '1.0'
|
||||||
|
FUNCTION_NAME = '/usr/local/bin/accton_as9726_32d_monitor_psu'
|
||||||
|
|
||||||
|
psu_state=[2, 2]
|
||||||
|
psu_status_state=[2, 2]
|
||||||
|
# Make a class we can use to capture stdout and sterr in the log
|
||||||
|
class device_monitor(object):
|
||||||
|
|
||||||
|
def __init__(self, log_file, log_level):
|
||||||
|
|
||||||
|
self.psu_num = 2
|
||||||
|
self.psu_path = "/sys/bus/i2c/devices/"
|
||||||
|
self.presence = "/psu_present"
|
||||||
|
self.oper_status = "/psu_power_good"
|
||||||
|
self.mapping = {
|
||||||
|
0: "9-0050",
|
||||||
|
1: "9-0051",
|
||||||
|
}
|
||||||
|
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||||
|
#sys_handler.setLevel(logging.WARNING)
|
||||||
|
sys_handler.setLevel(logging.INFO)
|
||||||
|
logging.getLogger('').addHandler(sys_handler)
|
||||||
|
|
||||||
|
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||||
|
|
||||||
|
def manage_psu(self):
|
||||||
|
|
||||||
|
PSU_STATE_REMOVE = 0
|
||||||
|
PSU_STATE_INSERT = 1
|
||||||
|
|
||||||
|
PSU_STATUS_NO_POWER = 0
|
||||||
|
PSU_STATUS_POWER_GOOD = 1
|
||||||
|
PSU_STATUS_IDLE =2
|
||||||
|
|
||||||
|
global psu_state
|
||||||
|
|
||||||
|
for idx in range (0, self.psu_num):
|
||||||
|
node = self.psu_path + self.mapping[idx] + self.presence
|
||||||
|
try:
|
||||||
|
val_file = open(node)
|
||||||
|
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":
|
||||||
|
if psu_state[idx]!=1:
|
||||||
|
psu_state[idx]=PSU_STATE_INSERT
|
||||||
|
logging.info("PSU-%d present is detected", idx+1);
|
||||||
|
#psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert, assume power is good. If no_power, next code will find it.
|
||||||
|
else:
|
||||||
|
if psu_state[idx]!=0:
|
||||||
|
psu_state[idx]=PSU_STATE_REMOVE
|
||||||
|
logging.warning("Alarm for PSU-%d absent is detected", idx+1);
|
||||||
|
psu_status_state[idx]=PSU_STATUS_IDLE
|
||||||
|
|
||||||
|
for idx in range (0, self.psu_num):
|
||||||
|
node = self.psu_path + self.mapping[idx] + self.oper_status
|
||||||
|
try:
|
||||||
|
val_file = open(node)
|
||||||
|
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 == "0":
|
||||||
|
if psu_status_state[idx]!=PSU_STATUS_NO_POWER:
|
||||||
|
if psu_state[idx]==PSU_STATE_INSERT:
|
||||||
|
logging.warning("Alarm for PSU-%d failed is detected", idx+1);
|
||||||
|
psu_status_state[idx]=PSU_STATUS_NO_POWER
|
||||||
|
else:
|
||||||
|
if psu_state[idx]==PSU_STATE_INSERT:
|
||||||
|
if psu_status_state[idx]!=PSU_STATUS_POWER_GOOD:
|
||||||
|
logging.info("PSU-%d power_good is detected", idx+1);
|
||||||
|
psu_status_state[idx]=PSU_STATUS_POWER_GOOD
|
||||||
|
|
||||||
|
|
||||||
|
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 = device_monitor(log_file, log_level)
|
||||||
|
# Loop forever, doing something useful hopefully:
|
||||||
|
while True:
|
||||||
|
monitor.manage_psu()
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv[1:])
|
@ -0,0 +1,680 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016 Accton Networks, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Usage: %(scriptName)s [options] command object
|
||||||
|
options:
|
||||||
|
-h | --help : this help message
|
||||||
|
-d | --debug : run with debug mode
|
||||||
|
-f | --force : ignore error during installation or clean
|
||||||
|
command:
|
||||||
|
install : install drivers and generate related sysfs nodes
|
||||||
|
clean : uninstall drivers and remove related sysfs nodes
|
||||||
|
show : show all systen status
|
||||||
|
sfp : dump SFP eeprom
|
||||||
|
set : change board setting with fan|sfp
|
||||||
|
"""
|
||||||
|
|
||||||
|
import commands
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
PROJECT_NAME = 'as9726_32d'
|
||||||
|
version = '0.0.1'
|
||||||
|
verbose = False
|
||||||
|
DEBUG = False
|
||||||
|
args = []
|
||||||
|
ALL_DEVICE = {}
|
||||||
|
DEVICE_NO = {
|
||||||
|
'fan1': 3,
|
||||||
|
'fan2': 3,
|
||||||
|
'fan3': 3,
|
||||||
|
'fan4': 3,
|
||||||
|
'fan5': 3,
|
||||||
|
'fan6': 3,
|
||||||
|
'thermal': 6,
|
||||||
|
'psu': 2,
|
||||||
|
'sfp': 34}
|
||||||
|
|
||||||
|
fan_prefix = '/sys/devices/platform/as9726_32d_'
|
||||||
|
hwmon_types = {'fan1': ['fan'],
|
||||||
|
'fan2': ['fan'],
|
||||||
|
'fan3': ['fan'],
|
||||||
|
'fan4': ['fan'],
|
||||||
|
'fan5': ['fan'],
|
||||||
|
'fan6': ['fan'],
|
||||||
|
}
|
||||||
|
hwmon_nodes = {
|
||||||
|
'fan1': [
|
||||||
|
'fan_duty_cycle_percentage',
|
||||||
|
'fan1_fault',
|
||||||
|
'fan1_front_speed_rpm',
|
||||||
|
'fan1_direction',
|
||||||
|
'fan1_rear_speed_rpm'],
|
||||||
|
'fan2': [
|
||||||
|
'fan_duty_cycle_percentage',
|
||||||
|
'fan2_fault',
|
||||||
|
'fan2_front_speed_rpm',
|
||||||
|
'fan2_direction',
|
||||||
|
'fan2_rear_speed_rpm'],
|
||||||
|
'fan3': [
|
||||||
|
'fan_duty_cycle_percentage',
|
||||||
|
'fan3_fault',
|
||||||
|
'fan3_front_speed_rpm',
|
||||||
|
'fan3_direction',
|
||||||
|
'fan3_rear_speed_rpm'],
|
||||||
|
'fan4': [
|
||||||
|
'fan4_duty_cycle_percentage',
|
||||||
|
'fan4_fault',
|
||||||
|
'fan4_front_speed_rpm',
|
||||||
|
'fan4_direction',
|
||||||
|
'fan4_rear_speed_rpm'],
|
||||||
|
'fan5': [
|
||||||
|
'fan_duty_cycle_percentage',
|
||||||
|
'fan5_fault',
|
||||||
|
'fan5_front_speed_rpm',
|
||||||
|
'fan5_direction',
|
||||||
|
'fan5_rear_speed_rpm'],
|
||||||
|
'fan6': [
|
||||||
|
'fan_duty_cycle_percentage',
|
||||||
|
'fan6_fault',
|
||||||
|
'fan6_front_speed_rpm',
|
||||||
|
'fan6_direction',
|
||||||
|
'fan6_rear_speed_rpm'],
|
||||||
|
}
|
||||||
|
hwmon_prefix = {'fan1': fan_prefix,
|
||||||
|
'fan2': fan_prefix,
|
||||||
|
'fan3': fan_prefix,
|
||||||
|
'fan4': fan_prefix,
|
||||||
|
'fan5': fan_prefix,
|
||||||
|
'fan6': fan_prefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_prefix = '/sys/bus/i2c/devices/'
|
||||||
|
i2c_bus = {'fan': ['14-0066'],
|
||||||
|
'thermal': ['15-0048', '15-0049', '15-004a', '15-004b', '15-004c', '15-004f'],
|
||||||
|
'psu': ['9-0050', '9-0051'],
|
||||||
|
'sfp': ['10-0061', '10-0062']}
|
||||||
|
i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'],
|
||||||
|
'thermal': ['hwmon/hwmon*/temp1_input'],
|
||||||
|
'psu': ['psu_present ', 'psu_power_good'],
|
||||||
|
'sfp': ['module_present_', 'module_tx_disable_']}
|
||||||
|
|
||||||
|
sfp_map = [17, 18, 19, 20, 21, 22, 23, 24,
|
||||||
|
25, 26, 27, 28, 29, 30, 31, 32,
|
||||||
|
33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48,
|
||||||
|
49, 50]
|
||||||
|
|
||||||
|
mknod = [
|
||||||
|
# i2c-mux
|
||||||
|
'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||||
|
'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
|
||||||
|
# CPLD
|
||||||
|
'echo as9726_32d_cpld_cpu 0x65 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo as9726_32d_fpga 0x60 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
'echo as9726_32d_cpld2 0x61 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||||
|
'echo as9726_32d_cpld3 0x62 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||||
|
|
||||||
|
# FAN
|
||||||
|
'echo as9726_32d_fan 0x66 > /sys/bus/i2c/devices/i2c-14/new_device',
|
||||||
|
|
||||||
|
# LM75
|
||||||
|
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
'echo lm75 0x4f > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||||
|
|
||||||
|
# PSU-1
|
||||||
|
'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||||
|
'echo as9726_32d_psu1 0x50 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||||
|
|
||||||
|
# PSU-2
|
||||||
|
'echo ym2401 0x59 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||||
|
'echo as9726_32d_psu2 0x51 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||||
|
|
||||||
|
# CPU EERPOM
|
||||||
|
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||||
|
# MAINBOARD EEPROM
|
||||||
|
'echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-13/new_device',
|
||||||
|
]
|
||||||
|
|
||||||
|
FORCE = 0
|
||||||
|
|
||||||
|
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:
|
||||||
|
print options
|
||||||
|
print args
|
||||||
|
print len(sys.argv)
|
||||||
|
|
||||||
|
for opt, arg in options:
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
show_help()
|
||||||
|
elif opt in ('-d', '--debug'):
|
||||||
|
DEBUG = True
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
elif opt in ('-f', '--force'):
|
||||||
|
FORCE = 1
|
||||||
|
else:
|
||||||
|
print "TEST"
|
||||||
|
logging.info('no option')
|
||||||
|
for arg in args:
|
||||||
|
if arg == 'install':
|
||||||
|
do_install()
|
||||||
|
elif arg == 'clean':
|
||||||
|
do_uninstall()
|
||||||
|
elif arg == 'api':
|
||||||
|
do_sonic_platform_install()
|
||||||
|
elif arg == 'api_clean':
|
||||||
|
do_sonic_platform_clean()
|
||||||
|
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 + " [sfp|fan]"
|
||||||
|
print " use \"" + cmd + " fan 0-100\" to set fan duty percetage"
|
||||||
|
print " use \"" + cmd + " sfp 33-34 {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-32 \" to dump sfp# eeprom"
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def my_log(txt):
|
||||||
|
if DEBUG:
|
||||||
|
print "[ACCTON DBG]: " + txt
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def log_os_system(cmd, show):
|
||||||
|
logging.info('Run :' + cmd)
|
||||||
|
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("ls /sys/module/*accton*", 0)
|
||||||
|
logging.info('mods:' + lsmod)
|
||||||
|
if ret:
|
||||||
|
return False
|
||||||
|
|
||||||
|
#'modprobe cpr_4011_4mxx',
|
||||||
|
|
||||||
|
|
||||||
|
kos = [
|
||||||
|
'depmod -ae',
|
||||||
|
'modprobe i2c_dev',
|
||||||
|
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
|
||||||
|
'modprobe ym2651y',
|
||||||
|
'modprobe x86-64-accton-as9726-32d_cpld',
|
||||||
|
'modprobe x86-64-accton-as9726-32d_fan',
|
||||||
|
'modprobe x86-64-accton-as9726-32d_psu',
|
||||||
|
'modprobe optoe',
|
||||||
|
'modprobe lm75']
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
lst = rm.split(" ")
|
||||||
|
print "lst=%s" % lst
|
||||||
|
if len(lst) > 3:
|
||||||
|
del(lst[3])
|
||||||
|
rm = " ".join(lst)
|
||||||
|
status, output = log_os_system(rm, 1)
|
||||||
|
if status:
|
||||||
|
if FORCE == 0:
|
||||||
|
return status
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def device_install():
|
||||||
|
global FORCE
|
||||||
|
|
||||||
|
for i in range(0, len(mknod)):
|
||||||
|
# for pca954x need times to built new i2c buses
|
||||||
|
if mknod[i].find('pca954') != -1:
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
status, output = log_os_system(mknod[i], 1)
|
||||||
|
if status:
|
||||||
|
print output
|
||||||
|
if FORCE == 0:
|
||||||
|
return status
|
||||||
|
print("Check SFP")
|
||||||
|
for i in range(0, len(sfp_map)):
|
||||||
|
if(i >= (len(sfp_map)-2)):
|
||||||
|
opt = 'optoe2' #last 2 port is sfp
|
||||||
|
else:
|
||||||
|
opt = 'optoe1' #first 32 port is qsfp
|
||||||
|
status, output = log_os_system("echo " +
|
||||||
|
str(opt) +
|
||||||
|
" 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
nodelist = mknod
|
||||||
|
|
||||||
|
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():
|
||||||
|
print "not device_exist()"
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
||||||
|
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
|
||||||
|
def do_sonic_platform_install():
|
||||||
|
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
|
||||||
|
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
|
||||||
|
|
||||||
|
#Check API2.0 on py whl file
|
||||||
|
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||||
|
if status:
|
||||||
|
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||||
|
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||||
|
if status:
|
||||||
|
print "Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)
|
||||||
|
return status
|
||||||
|
else:
|
||||||
|
print "Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)
|
||||||
|
else:
|
||||||
|
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||||
|
else:
|
||||||
|
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def do_sonic_platform_clean():
|
||||||
|
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||||
|
if status:
|
||||||
|
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||||
|
|
||||||
|
else:
|
||||||
|
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||||
|
if status:
|
||||||
|
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||||
|
return status
|
||||||
|
else:
|
||||||
|
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def do_install():
|
||||||
|
if driver_inserted() == False:
|
||||||
|
status = driver_install()
|
||||||
|
if status:
|
||||||
|
if FORCE == 0:
|
||||||
|
return status
|
||||||
|
else:
|
||||||
|
print PROJECT_NAME.upper() + " drivers detected...."
|
||||||
|
if not device_exist():
|
||||||
|
status = device_install()
|
||||||
|
if status:
|
||||||
|
if FORCE == 0:
|
||||||
|
return status
|
||||||
|
else:
|
||||||
|
print PROJECT_NAME.upper() + " devices detected...."
|
||||||
|
|
||||||
|
# for i in range(len(cpld_set)):
|
||||||
|
# status, output = log_os_system(cpld_set[i], 1)
|
||||||
|
# if status:
|
||||||
|
# if FORCE == 0:
|
||||||
|
# return status
|
||||||
|
|
||||||
|
do_sonic_platform_install()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def do_uninstall():
|
||||||
|
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
|
||||||
|
|
||||||
|
do_sonic_platform_clean()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def devices_info():
|
||||||
|
global DEVICE_NO
|
||||||
|
global ALL_DEVICE
|
||||||
|
global i2c_bus, hwmon_types
|
||||||
|
for key in DEVICE_NO:
|
||||||
|
ALL_DEVICE[key] = {}
|
||||||
|
for i in range(0, DEVICE_NO[key]):
|
||||||
|
ALL_DEVICE[key][key + str(i + 1)] = []
|
||||||
|
|
||||||
|
for key in i2c_bus:
|
||||||
|
buses = i2c_bus[key]
|
||||||
|
nodes = i2c_nodes[key]
|
||||||
|
for i in range(0, len(buses)):
|
||||||
|
for j in range(0, len(nodes)):
|
||||||
|
if 'fan' == key:
|
||||||
|
for k in range(0, 6):
|
||||||
|
node = key + str(k + 1)
|
||||||
|
path = i2c_prefix + \
|
||||||
|
buses[i] + "/fan" + str(k + 1) + "_" + nodes[j]
|
||||||
|
my_log(node + ": " + path)
|
||||||
|
ALL_DEVICE[key + str(k + 1)][node + str(j + 1)].append(path)
|
||||||
|
elif 'sfp' == key:
|
||||||
|
for k in range(0, DEVICE_NO[key]):
|
||||||
|
node = key + str(k + 1)
|
||||||
|
if k < 16 and i==0 and j==0:
|
||||||
|
path = i2c_prefix + \
|
||||||
|
str(buses[0] + "/" + nodes[j] + str(k+1))
|
||||||
|
my_log(node + ": " + path)
|
||||||
|
ALL_DEVICE[key][node].append(path)
|
||||||
|
if k >= 16 and i==1 and j==0:
|
||||||
|
path = i2c_prefix + \
|
||||||
|
str(buses[1] + "/" + nodes[j] + str(k+1))
|
||||||
|
my_log(node + ": " + path)
|
||||||
|
ALL_DEVICE[key][node].append(path)
|
||||||
|
if k >= 32 and i==1 and j==1:
|
||||||
|
path = i2c_prefix + \
|
||||||
|
str(buses[1] + "/" + 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:
|
||||||
|
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')
|
||||||
|
sfp_node = str(sfp_map[int(index)-1]) + '-0050'
|
||||||
|
node = node.replace(node.split("/")[-2], sfp_node)
|
||||||
|
# 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=%s" % node
|
||||||
|
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] == '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], 'fan_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]) < DEVICE_NO[args[0]]-1: #33-34
|
||||||
|
show_set_help()
|
||||||
|
return
|
||||||
|
if len(args)<3 or len(args)>4: #len(args)=3
|
||||||
|
show_set_help()
|
||||||
|
return
|
||||||
|
if int(args[2])>1 or int(args[2])<0: #0|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
|
||||||
|
else:
|
||||||
|
show_set_help()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# get digits inside a string.
|
||||||
|
# Ex: 31 for "sfp31"
|
||||||
|
|
||||||
|
|
||||||
|
def get_value(input):
|
||||||
|
digit = re.findall(r'\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 + "*0077", 0)
|
||||||
|
ret2, log = log_os_system("ls " + i2c_prefix + "i2c-2", 0)
|
||||||
|
return not(ret1 or ret2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -69,6 +69,10 @@ Package: sonic-platform-accton-as9716-32d
|
|||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
|
Package: sonic-platform-accton-as9726-32d
|
||||||
|
Architecture: amd64
|
||||||
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
Package: sonic-platform-accton-as5835-54t
|
Package: sonic-platform-accton-as5835-54t
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
@ -22,7 +22,7 @@ KERNEL_SRC := /lib/modules/$(KVERSION)
|
|||||||
MOD_SRC_DIR:= $(shell pwd)
|
MOD_SRC_DIR:= $(shell pwd)
|
||||||
MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x
|
MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x
|
||||||
MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te minipack as5812-54x
|
MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te minipack as5812-54x
|
||||||
MODULE_DIRS += as5835-54x as9716-32d as5835-54t as7312-54xs as7315-27xb as5812-54t
|
MODULE_DIRS += as5835-54x as9716-32d as9726-32d as5835-54t as7312-54xs as7315-27xb as5812-54t
|
||||||
MODULE_DIR := modules
|
MODULE_DIR := modules
|
||||||
UTILS_DIR := utils
|
UTILS_DIR := utils
|
||||||
SERVICE_DIR := service
|
SERVICE_DIR := service
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
as9726-32d/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as9726_32d-r0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user