[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:
ec-michael-shih 2021-05-12 10:06:36 +08:00 committed by GitHub
parent b64a6402d0
commit a070f1a239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 8537 additions and 1 deletions

View File

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

View File

@ -0,0 +1 @@
Accton-AS9726-32D t1

View File

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

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

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python
#############################################################################
# Accton
#
# Module contains an implementation of SONiC PSU Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
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

View 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, {}

View File

@ -0,0 +1,5 @@
{
"skip_ledd": true,
"skip_thermalctld": true
}

View File

@ -0,0 +1,2 @@
__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan']
from . import platform

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View 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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -35,6 +35,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(ACCTON_AS5812_54T_PLATFORM_MODULE) \
$(ACCTON_AS5835_54X_PLATFORM_MODULE) \
$(ACCTON_AS9716_32D_PLATFORM_MODULE) \
$(ACCTON_AS9726_32D_PLATFORM_MODULE) \
$(ACCTON_AS5835_54T_PLATFORM_MODULE) \
$(ACCTON_AS7312_54XS_PLATFORM_MODULE) \
$(ACCTON_AS7315_27XB_PLATFORM_MODULE) \

View File

@ -16,6 +16,7 @@ ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS5835_54X_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_AS7312_54XS_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_AS5835_54X_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_AS7312_54XS_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
$(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)_PLATFORM = x86_64-accton_as5835_54t-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54T_PLATFORM_MODULE)))

View 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

View File

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

View 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

View File

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

View File

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

View File

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

View 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");

View File

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

View File

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

View File

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

View 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'},
)

View File

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

View 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.

View File

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

View File

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

View File

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

View File

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

View File

@ -69,6 +69,10 @@ Package: sonic-platform-accton-as9716-32d
Architecture: amd64
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
Architecture: amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -22,7 +22,7 @@ KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
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 += 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
UTILS_DIR := utils
SERVICE_DIR := service

View File

@ -0,0 +1,2 @@
as9726-32d/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as9726_32d-r0