[devices]: Add support as9716 platform (#2993)
This commit is contained in:
parent
8b225d3ca1
commit
9b0d1b74f9
@ -27,6 +27,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
|
||||
$(ACCTON_MINIPACK_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS5812_54X_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS5835_54X_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS9716_32D_PLATFORM_MODULE) \
|
||||
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
|
||||
$(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
|
||||
$(INVENTEC_D7264Q28B_PLATFORM_MODULE) \
|
||||
|
@ -13,6 +13,7 @@ ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION = 1.1
|
||||
|
||||
export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION
|
||||
@ -27,6 +28,7 @@ export ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION
|
||||
|
||||
ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton
|
||||
@ -83,4 +85,9 @@ ACCTON_AS5835_54X_PLATFORM_MODULE = sonic-platform-accton-as5835-54x_$(ACCTON_AS
|
||||
$(ACCTON_AS5835_54X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5835_54x-r0
|
||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54X_PLATFORM_MODULE)))
|
||||
|
||||
ACCTON_AS9716_32D_PLATFORM_MODULE = sonic-platform-accton-as9716-32d_$(ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(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)))
|
||||
|
||||
|
||||
SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE)
|
||||
|
251
platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py
Executable file
251
platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py
Executable file
@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2017 Accton Technology Corporation
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 11/13/2017: Polly Hsu, Create
|
||||
# 1/10/2018: Jostar modify for as7716_32
|
||||
# 12/03/2018: Jostar modify for as7726_32
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import time
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
|
||||
class FanUtil(object):
|
||||
"""Platform-specific FanUtil class"""
|
||||
|
||||
FAN_NUM_ON_MAIN_BROAD = 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/54-0066/{0}'
|
||||
FAN_DUTY_PATH = '/sys/bus/i2c/devices/54-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_to_device_path_mapping = {}
|
||||
|
||||
#fan1_direction
|
||||
#fan1_fault
|
||||
#fan1_present
|
||||
|
||||
#(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
|
||||
_fan_to_device_node_mapping = {
|
||||
(FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault',
|
||||
(FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction',
|
||||
|
||||
(FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault',
|
||||
(FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction',
|
||||
|
||||
(FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault',
|
||||
(FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction',
|
||||
|
||||
(FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault',
|
||||
(FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction',
|
||||
|
||||
(FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault',
|
||||
(FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction',
|
||||
|
||||
(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_to_device_node(self, fan_num, node_num):
|
||||
return self._fan_to_device_node_mapping[(fan_num, node_num)]
|
||||
|
||||
def _get_fan_node_val(self, fan_num, node_num):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
|
||||
return None
|
||||
|
||||
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
|
||||
logging.debug('GET. Parameter error. node_num:%d', node_num)
|
||||
return None
|
||||
|
||||
device_path = self.get_fan_to_device_path(fan_num, node_num)
|
||||
|
||||
try:
|
||||
val_file = open(device_path, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
|
||||
content = val_file.readline().rstrip()
|
||||
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
return int(content)
|
||||
|
||||
def _set_fan_node_val(self, fan_num, node_num, val):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
|
||||
return None
|
||||
|
||||
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
|
||||
logging.debug('GET. Parameter error. node_num:%d', node_num)
|
||||
return None
|
||||
|
||||
content = str(val)
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
device_path = self.get_fan_to_device_path(fan_num, node_num)
|
||||
try:
|
||||
val_file = open(device_path, 'w')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
|
||||
val_file.write(content)
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self):
|
||||
fan_path = self.BASE_VAL_PATH
|
||||
|
||||
for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1):
|
||||
for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1):
|
||||
self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format(
|
||||
self._fan_to_device_node_mapping[(fan_num, node_num)])
|
||||
|
||||
def get_num_fans(self):
|
||||
return self.FAN_NUM_ON_MAIN_BROAD
|
||||
|
||||
def get_idx_fan_start(self):
|
||||
return self.FAN_NUM_1_IDX
|
||||
|
||||
def get_num_nodes(self):
|
||||
return self.FAN_NODE_NUM_OF_MAP
|
||||
|
||||
def get_idx_node_start(self):
|
||||
return self.FAN_NODE_FAULT_IDX_OF_MAP
|
||||
|
||||
def get_size_node_map(self):
|
||||
return len(self._fan_to_device_node_mapping)
|
||||
|
||||
def get_size_path_map(self):
|
||||
return len(self._fan_to_device_path_mapping)
|
||||
|
||||
def get_fan_to_device_path(self, fan_num, node_num):
|
||||
return self._fan_to_device_path_mapping[(fan_num, node_num)]
|
||||
|
||||
def get_fan_fault(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP)
|
||||
|
||||
#def get_fan_speed(self, fan_num):
|
||||
# return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP)
|
||||
|
||||
def get_fan_dir(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP)
|
||||
|
||||
def get_fan_duty_cycle(self):
|
||||
#duty_path = self.FAN_DUTY_PATH
|
||||
try:
|
||||
val_file = open(self.FAN_DUTY_PATH)
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
|
||||
return int(content)
|
||||
#self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP)
|
||||
#static u32 reg_val_to_duty_cycle(u8 reg_val)
|
||||
#{
|
||||
# reg_val &= FAN_DUTY_CYCLE_REG_MASK;
|
||||
# return ((u32)(reg_val+1) * 625 + 75)/ 100;
|
||||
#}
|
||||
#
|
||||
def set_fan_duty_cycle(self, val):
|
||||
|
||||
try:
|
||||
fan_file = open(self.FAN_DUTY_PATH, 'r+')
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
#val = ((val + 1 ) * 625 +75 ) / 100
|
||||
fan_file.write(str(val))
|
||||
fan_file.close()
|
||||
return True
|
||||
|
||||
#def get_fanr_fault(self, fan_num):
|
||||
# return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP)
|
||||
|
||||
def get_fanr_speed(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP)
|
||||
|
||||
def get_fan_status(self, fan_num):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num, %d', fan_num)
|
||||
return None
|
||||
|
||||
if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0:
|
||||
logging.debug('GET. FAN fault. fan_num, %d', fan_num)
|
||||
return False
|
||||
|
||||
#if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0:
|
||||
# logging.debug('GET. FANR fault. fan_num, %d', fan_num)
|
||||
# return False
|
||||
|
||||
return True
|
||||
|
||||
#def main():
|
||||
# fan = FanUtil()
|
||||
#
|
||||
# print 'get_size_node_map : %d' % fan.get_size_node_map()
|
||||
# print 'get_size_path_map : %d' % fan.get_size_path_map()
|
||||
# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
|
||||
# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
|
||||
# print fan.get_fan_to_device_path(x, y)
|
||||
#
|
||||
#if __name__ == '__main__':
|
||||
# main()
|
@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2017 Accton Technology Corporation
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 12/18/2018:Jostar craete for as9716_32d
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import glob
|
||||
import commands
|
||||
from collections import namedtuple
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
class ThermalUtil(object):
|
||||
"""Platform-specific ThermalUtil class"""
|
||||
THERMAL_NUM_MAX = 8
|
||||
THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_5_IDX = 5 # 5_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_6_IDX = 6 # 6_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_7_IDX = 7 # 7_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_8_IDX = 8 # 8_ON_MAIN_BROAD. LM75
|
||||
|
||||
""" Dictionary where
|
||||
key1 = thermal id index (integer) starting from 1
|
||||
value = path to fan device file (string) """
|
||||
#_thermal_to_device_path_mapping = {}
|
||||
|
||||
_thermal_to_device_node_mapping = {
|
||||
THERMAL_NUM_1_IDX: ['18', '48'],
|
||||
THERMAL_NUM_2_IDX: ['18', '49'],
|
||||
THERMAL_NUM_3_IDX: ['18', '4a'],
|
||||
THERMAL_NUM_4_IDX: ['18', '4b'],
|
||||
THERMAL_NUM_5_IDX: ['18', '4c'],
|
||||
THERMAL_NUM_6_IDX: ['18', '4e'],
|
||||
THERMAL_NUM_7_IDX: ['18', '4f'],
|
||||
}
|
||||
thermal_sysfspath ={
|
||||
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-0048/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/18-0049/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/18-004a/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/18-004c/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_6_IDX: ["/sys/bus/i2c/devices/18-004e/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_7_IDX: ["/sys/bus/i2c/devices/18-004f/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_8_IDX: ["/sys/class/hwmon/hwmon0/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_to_device_path(thermal_num)
|
||||
for filename in glob.glob(device_path):
|
||||
try:
|
||||
val_file = open(filename, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
content = val_file.readline().rstrip()
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
try:
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
return int(content)
|
||||
|
||||
return 0
|
||||
|
||||
def get_num_thermals(self):
|
||||
return self.THERMAL_NUM_MAX
|
||||
|
||||
def get_idx_thermal_start(self):
|
||||
return self.THERMAL_NUM_1_IDX
|
||||
|
||||
def get_size_node_map(self):
|
||||
return len(self._thermal_to_device_node_mapping)
|
||||
|
||||
def get_size_path_map(self):
|
||||
return len(self.thermal_sysfspath)
|
||||
|
||||
def get_thermal_to_device_path(self, thermal_num):
|
||||
return self.thermal_sysfspath[thermal_num][0]
|
||||
|
||||
def get_thermal_temp(self):
|
||||
return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX))
|
||||
|
||||
def main():
|
||||
thermal = ThermalUtil()
|
||||
print "termal1=%d" %thermal._get_thermal_val(1)
|
||||
print "termal2=%d" %thermal._get_thermal_val(2)
|
||||
print "termal3=%d" %thermal._get_thermal_val(3)
|
||||
print "termal4=%d" %thermal._get_thermal_val(4)
|
||||
print "termal5=%d" %thermal._get_thermal_val(5)
|
||||
print "termal7=%d" %thermal._get_thermal_val(6)
|
||||
print "termal8=%d" %thermal._get_thermal_val(7)
|
||||
print "termal9=%d" %thermal._get_thermal_val(8)
|
||||
|
||||
#
|
||||
# print 'get_size_node_map : %d' % thermal.get_size_node_map()
|
||||
# print 'get_size_path_map : %d' % thermal.get_size_path_map()
|
||||
# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
|
||||
# print thermal.get_thermal_to_device_path(x)
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
main()
|
19
platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile
Executable file
19
platform/broadcom/sonic-platform-modules-accton/as9716-32d/modules/Makefile
Executable file
@ -0,0 +1,19 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m:= accton_as9716_32d_cpld.o accton_as9716_32d_fan.o \
|
||||
accton_as9716_32d_leds.o accton_as9716_32d_psu.o accton_i2c_psu.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 *.ko .*cmd *.mod.c .tmp_versions Module.markers Module.symvers modules.order
|
||||
endif
|
@ -0,0 +1,900 @@
|
||||
/*
|
||||
* 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 as9716_32d CPLD1/CPLD2/CPLD3
|
||||
*
|
||||
* Based on:
|
||||
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
|
||||
* Copyright (C) 2006
|
||||
*
|
||||
* Based on:
|
||||
* pca954x.c from Ken Harrenstien
|
||||
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
|
||||
*
|
||||
* Based on:
|
||||
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
|
||||
* and
|
||||
* pca9540.c from Jean Delvare <khali@linux-fr.org>.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/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 {
|
||||
as9716_32d_fpga,
|
||||
as9716_32d_cpld1,
|
||||
as9716_32d_cpld2,
|
||||
as9716_32d_cpld_cpu
|
||||
};
|
||||
|
||||
struct as9716_32d_cpld_data {
|
||||
enum cpld_type type;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
};
|
||||
|
||||
static const struct i2c_device_id as9716_32d_cpld_id[] = {
|
||||
{ "as9716_32d_fpga", as9716_32d_fpga },
|
||||
{ "as9716_32d_cpld1", as9716_32d_cpld1 },
|
||||
{ "as9716_32d_cpld2", as9716_32d_cpld2 },
|
||||
{ "as9716_32d_cpld_cpu", as9716_32d_cpld_cpu },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as9716_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
|
||||
|
||||
enum as9716_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),
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
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 as9716_32d_cpld_read_internal(struct i2c_client *client, u8 reg);
|
||||
static int as9716_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
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
static struct attribute *as9716_32d_fpga_attributes[] = {
|
||||
&sensor_dev_attr_version.dev_attr.attr,
|
||||
&sensor_dev_attr_access.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group as9716_32d_fpga_group = {
|
||||
.attrs = as9716_32d_fpga_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *as9716_32d_cpld1_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),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group as9716_32d_cpld1_group = {
|
||||
.attrs = as9716_32d_cpld1_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *as9716_32d_cpld2_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),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group as9716_32d_cpld2_group = {
|
||||
.attrs = as9716_32d_cpld2_attributes,
|
||||
};
|
||||
|
||||
|
||||
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 as9716_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 = 0x8;
|
||||
break;
|
||||
case MODULE_RXLOS_33:
|
||||
reg = 0x20;
|
||||
mask = 0x2;
|
||||
break;
|
||||
case MODULE_RXLOS_34:
|
||||
reg = 0x20;
|
||||
mask = 0x10;
|
||||
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 = as9716_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 as9716_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 = as9716_32d_cpld_read_internal(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Update tx_disable status */
|
||||
if (disable) {
|
||||
status |= mask;
|
||||
}
|
||||
else {
|
||||
status &= ~mask;
|
||||
}
|
||||
|
||||
status = as9716_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 as9716_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 = as9716_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 as9716_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 as9716_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, "%d\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 as9716_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 = as9716_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 as9716_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 = as9716_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 = as9716_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 as9716_32d_cpld_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct as9716_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 as9716_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 as9716_32d_fpga:
|
||||
group = &as9716_32d_fpga_group;
|
||||
break;
|
||||
case as9716_32d_cpld1:
|
||||
group = &as9716_32d_cpld1_group;
|
||||
break;
|
||||
case as9716_32d_cpld2:
|
||||
group = &as9716_32d_cpld2_group;
|
||||
break;
|
||||
case as9716_32d_cpld_cpu:
|
||||
/* Disable CPLD reset to avoid DUT will be reset.
|
||||
*/
|
||||
status=as9716_32d_cpld_write_internal(client, 0x3, 0x0);
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "cpu_cpld reg 0x65 err %d\n", status);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (group) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
|
||||
as9716_32d_cpld_add_client(client);
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as9716_32d_cpld_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as9716_32d_cpld_data *data = i2c_get_clientdata(client);
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
as9716_32d_cpld_remove_client(client);
|
||||
|
||||
/* Remove sysfs hooks */
|
||||
switch (data->type) {
|
||||
case as9716_32d_fpga:
|
||||
group = &as9716_32d_fpga_group;
|
||||
break;
|
||||
case as9716_32d_cpld1:
|
||||
group = &as9716_32d_cpld1_group;
|
||||
break;
|
||||
case as9716_32d_cpld2:
|
||||
group = &as9716_32d_cpld2_group;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (group) {
|
||||
sysfs_remove_group(&client->dev.kobj, group);
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as9716_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 as9716_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 as9716_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 = as9716_32d_cpld_read_internal(cpld_node->client, reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(as9716_32d_cpld_read);
|
||||
|
||||
int as9716_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 = as9716_32d_cpld_write_internal(cpld_node->client, reg, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(as9716_32d_cpld_write);
|
||||
|
||||
static struct i2c_driver as9716_32d_cpld_driver = {
|
||||
.driver = {
|
||||
.name = "as9716_32d_cpld",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = as9716_32d_cpld_probe,
|
||||
.remove = as9716_32d_cpld_remove,
|
||||
.id_table = as9716_32d_cpld_id,
|
||||
};
|
||||
|
||||
static int __init as9716_32d_cpld_init(void)
|
||||
{
|
||||
mutex_init(&list_lock);
|
||||
return i2c_add_driver(&as9716_32d_cpld_driver);
|
||||
}
|
||||
|
||||
static void __exit as9716_32d_cpld_exit(void)
|
||||
{
|
||||
i2c_del_driver(&as9716_32d_cpld_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com>");
|
||||
MODULE_DESCRIPTION("Accton I2C CPLD driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(as9716_32d_cpld_init);
|
||||
module_exit(as9716_32d_cpld_exit);
|
||||
|
@ -0,0 +1,760 @@
|
||||
/*
|
||||
* A hwmon driver for the Accton as9716 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 "as9716_32d_fan"
|
||||
|
||||
#define NUM_THERMAL_SENSORS (7) /* Get sum of this number of sensors.*/
|
||||
#define THERMAL_SENSORS_DRIVER "lm75"
|
||||
#define THERMAL_SENSORS_ADDRS {0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4c , 0x4e}
|
||||
|
||||
static struct as9716_32d_fan_data *as9716_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);
|
||||
static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, char *buf);
|
||||
|
||||
/* 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 as9716_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, index2) \
|
||||
static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT);\
|
||||
static SENSOR_DEVICE_ATTR(fan##index2##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT)
|
||||
|
||||
#define DECLARE_FAN_FAULT_ATTR(index, index2) &sensor_dev_attr_fan##index##_fault.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##index2##_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_SYSTEM_TEMP_SENSOR_DEV_ATTR() \
|
||||
static SENSOR_DEVICE_ATTR(sys_temp, S_IRUGO, get_sys_temp, NULL, FAN_DUTY_CYCLE_PERCENTAGE)
|
||||
|
||||
#define DECLARE_FAN_SYSTEM_TEMP_ATTR() &sensor_dev_attr_sys_temp.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,11);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2,12);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3,13);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4,14);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5,15);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(6,16);
|
||||
|
||||
/* 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();
|
||||
/* System temperature for fancontrol */
|
||||
DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR();
|
||||
|
||||
static struct attribute *as9716_32d_fan_attributes[] = {
|
||||
/* fan related attributes */
|
||||
DECLARE_FAN_FAULT_ATTR(1,11),
|
||||
DECLARE_FAN_FAULT_ATTR(2,12),
|
||||
DECLARE_FAN_FAULT_ATTR(3,13),
|
||||
DECLARE_FAN_FAULT_ATTR(4,14),
|
||||
DECLARE_FAN_FAULT_ATTR(5,15),
|
||||
DECLARE_FAN_FAULT_ATTR(6,16),
|
||||
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(),
|
||||
DECLARE_FAN_SYSTEM_TEMP_ATTR(),
|
||||
NULL
|
||||
};
|
||||
|
||||
#define FAN_DUTY_CYCLE_REG_MASK 0xF
|
||||
#define FAN_MAX_DUTY_CYCLE 100
|
||||
#define FAN_REG_VAL_TO_SPEED_RPM_STEP 100
|
||||
|
||||
static int as9716_32d_fan_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int as9716_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;
|
||||
return ((u32)(reg_val+1) * 625 + 75)/ 100;
|
||||
}
|
||||
|
||||
static u8 duty_cycle_to_reg_val(u8 duty_cycle)
|
||||
{
|
||||
return ((u32)duty_cycle * 100 / 625) - 1;
|
||||
}
|
||||
|
||||
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 as9716_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;
|
||||
|
||||
as9716_32d_fan_write_value(client, 0x33, 0); /* Disable fan speed watch dog */
|
||||
as9716_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 int get_lm75_temp(struct i2c_client *client, int *miniCelsius)
|
||||
{
|
||||
struct lm75_data *data = NULL;
|
||||
|
||||
data = i2c_get_clientdata(client);
|
||||
*miniCelsius = lm75_reg_to_mc(data->temp[0], data->resolution);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool lm75_addr_mached(unsigned short addr)
|
||||
{
|
||||
int i;
|
||||
unsigned short addrs[] = THERMAL_SENSORS_ADDRS;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addrs); i++)
|
||||
{
|
||||
if( addr == addrs[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _find_lm75_device(struct device *dev, void *data)
|
||||
{
|
||||
struct device_driver *driver;
|
||||
struct as9716_32d_fan_data *prv = data;
|
||||
char *driver_name = THERMAL_SENSORS_DRIVER;
|
||||
|
||||
driver = dev->driver;
|
||||
if (driver && driver->name &&
|
||||
strcmp(driver->name, driver_name) == 0)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
client = to_i2c_client(dev);
|
||||
if (client)
|
||||
{
|
||||
/*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
int miniCelsius = 0;
|
||||
|
||||
if (! lm75_addr_mached(client->addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!adap) {
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* If the data is not updated, read them from devfile
|
||||
to drive them updateing data from chip.*/
|
||||
if (is_lm75_data_due(client))
|
||||
{
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon_dev = get_hwmon_dev(client);
|
||||
if(0 == read_devfile_temp1_input(dev, adap->nr,
|
||||
client->addr, hwmon_dev, &miniCelsius))
|
||||
{
|
||||
prv->system_temp += miniCelsius;
|
||||
prv->sensors_found++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
get_lm75_temp(client, &miniCelsius);
|
||||
prv->system_temp += miniCelsius;
|
||||
prv->sensors_found++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Find all lm75 devices and return sum of temperatures.*/
|
||||
static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
struct as9716_32d_fan_data *data = as9716_32d_fan_update_device(dev);
|
||||
|
||||
data->system_temp=0;
|
||||
data->sensors_found=0;
|
||||
i2c_for_each_dev(data, _find_lm75_device);
|
||||
if (NUM_THERMAL_SENSORS != data->sensors_found)
|
||||
{
|
||||
dev_dbg(dev,"only %d of %d temps are found\n",
|
||||
data->sensors_found, NUM_THERMAL_SENSORS);
|
||||
data->system_temp = INT_MAX;
|
||||
}
|
||||
ret = sprintf(buf, "%d\n",data->system_temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 as9716_32d_fan_data *data = as9716_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 as9716_32d_fan_group = {
|
||||
.attrs = as9716_32d_fan_attributes,
|
||||
};
|
||||
|
||||
static struct as9716_32d_fan_data *as9716_32d_fan_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as9716_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 as9716_32d_fan update\n");
|
||||
data->valid = 0;
|
||||
|
||||
/* Update fan data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) {
|
||||
int status = as9716_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 as9716_32d_fan_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct as9716_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 as9716_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, &as9716_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, &as9716_32d_fan_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as9716_32d_fan_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as9716_32d_fan_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &as9716_32d_fan_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x66, I2C_CLIENT_END };
|
||||
|
||||
static const struct i2c_device_id as9716_32d_fan_id[] = {
|
||||
{ "as9716_32d_fan", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as9716_32d_fan_id);
|
||||
|
||||
static struct i2c_driver as9716_32d_fan_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = as9716_32d_fan_probe,
|
||||
.remove = as9716_32d_fan_remove,
|
||||
.id_table = as9716_32d_fan_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(as9716_32d_fan_driver);
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as9716_32d_fan driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* A LED driver for the accton_as9716_32d_led
|
||||
*
|
||||
* Copyright (C) 2014 Accton Technology Corporation.
|
||||
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
extern int as9716_32d_cpld_read (unsigned short cpld_addr, u8 reg);
|
||||
extern int as9716_32d_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
#define DRVNAME "accton_as9716_32d_led"
|
||||
|
||||
struct accton_as9716_32d_led_data {
|
||||
struct platform_device *pdev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* != 0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 reg_val[2]; /* only 1 register*/
|
||||
};
|
||||
|
||||
static struct accton_as9716_32d_led_data *ledctl = NULL;
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
|
||||
#define LED_CNTRLER_I2C_ADDRESS (0x61)
|
||||
|
||||
#define LED_TYPE_DIAG_REG_MASK (0x1|0x2|0x4)
|
||||
#define LED_MODE_DIAG_GREEN_VALUE (0x01)
|
||||
#define LED_MODE_DIAG_AMBER_VALUE (0x02) /*It's yellow actually. Green+Red=Yellow*/
|
||||
#define LED_MODE_DIAG_GREEN_BLINK_VALUE (0x04)
|
||||
#define LED_MODE_DIAG_OFF_VALUE (0x0)
|
||||
|
||||
|
||||
#define LED_TYPE_LOC_REG_MASK (0x80|0x40)
|
||||
#define LED_MODE_LOC_GREEN_BLIKN_VALUE 0x80
|
||||
#define LED_MODE_LOC_AMBER_VALUE 0x40
|
||||
#define LED_MODE_LOC_OFF_VALUE (0x0)
|
||||
|
||||
#define LED_TYPE_FAN_REG_MASK (0x20|0x10)
|
||||
#define LED_MODE_FAN_AMBER_VALUE 0x20
|
||||
#define LED_MODE_FAN_GREEN_VALUE 0x10
|
||||
#define LED_MODE_FAN_OFF_VALUE (0x0)
|
||||
|
||||
#define LED_TYPE_PSU2_REG_MASK (0x8|0x4)
|
||||
#define LED_MODE_PSU2_AMBER_VALUE 0x8
|
||||
#define LED_MODE_PSU2_GREEN_VALUE 0x4
|
||||
#define LED_MODE_PSU2_OFF_VALUE (0x0)
|
||||
|
||||
#define LED_TYPE_PSU1_REG_MASK (0x2|0x1)
|
||||
#define LED_MODE_PSU1_AMBER_VALUE 0x2
|
||||
#define LED_MODE_PSU1_GREEN_VALUE 0x1
|
||||
#define LED_MODE_PSU1_OFF_VALUE (0x0)
|
||||
|
||||
enum led_type {
|
||||
LED_TYPE_DIAG,
|
||||
LED_TYPE_LOC,
|
||||
LED_TYPE_FAN,
|
||||
LED_TYPE_PSU1,
|
||||
LED_TYPE_PSU2
|
||||
};
|
||||
|
||||
struct led_reg {
|
||||
u32 types;
|
||||
u8 reg_addr;
|
||||
};
|
||||
|
||||
static const struct led_reg led_reg_map[] = {
|
||||
{(1<<LED_TYPE_DIAG), 0x31},
|
||||
{(1<<LED_TYPE_PSU2) | (1<<LED_TYPE_PSU1) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_LOC), 0x30},
|
||||
};
|
||||
|
||||
|
||||
enum led_light_mode {
|
||||
LED_MODE_OFF = 0,
|
||||
LED_MODE_GREEN,
|
||||
LED_MODE_AMBER,
|
||||
LED_MODE_RED,
|
||||
LED_MODE_BLUE,
|
||||
LED_MODE_GREEN_BLINK,
|
||||
LED_MODE_AMBER_BLINK,
|
||||
LED_MODE_RED_BLINK,
|
||||
LED_MODE_BLUE_BLINK,
|
||||
LED_MODE_AUTO,
|
||||
LED_MODE_UNKNOWN
|
||||
};
|
||||
|
||||
struct led_type_mode {
|
||||
enum led_type type;
|
||||
enum led_light_mode mode;
|
||||
int reg_bit_mask;
|
||||
int mode_value;
|
||||
};
|
||||
|
||||
static struct led_type_mode led_type_mode_data[] = {
|
||||
{LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE},
|
||||
{LED_TYPE_LOC, LED_MODE_GREEN_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_GREEN_BLIKN_VALUE},
|
||||
{LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_GREEN_BLINK, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_BLINK_VALUE},
|
||||
{LED_TYPE_FAN,LED_MODE_OFF, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_OFF_VALUE},
|
||||
{LED_TYPE_FAN,LED_MODE_GREEN, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_GREEN_VALUE},
|
||||
{LED_TYPE_FAN,LED_MODE_AMBER, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_PSU1,LED_MODE_OFF, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_OFF_VALUE},
|
||||
{LED_TYPE_PSU1,LED_MODE_GREEN, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_GREEN_VALUE},
|
||||
{LED_TYPE_PSU1,LED_MODE_AMBER, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_PSU2,LED_MODE_OFF, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_OFF_VALUE},
|
||||
{LED_TYPE_PSU2,LED_MODE_GREEN, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_GREEN_VALUE},
|
||||
{LED_TYPE_PSU2,LED_MODE_AMBER, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AMBER_VALUE},
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void accton_as9716_32d_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode, enum led_type type);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int accton_getLedReg(enum led_type type, u8 *reg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) {
|
||||
if(led_reg_map[i].types & (1<<type)) {
|
||||
*reg = led_reg_map[i].reg_addr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
|
||||
|
||||
if (type != led_type_mode_data[i].type)
|
||||
continue;
|
||||
|
||||
if ((led_type_mode_data[i].reg_bit_mask & reg_val) ==
|
||||
led_type_mode_data[i].mode_value)
|
||||
{
|
||||
return led_type_mode_data[i].mode;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 led_light_mode_to_reg_val(enum led_type type,
|
||||
enum led_light_mode mode, u8 reg_val) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
|
||||
if (type != led_type_mode_data[i].type)
|
||||
continue;
|
||||
|
||||
if (mode != led_type_mode_data[i].mode)
|
||||
continue;
|
||||
|
||||
reg_val = led_type_mode_data[i].mode_value |
|
||||
(reg_val & (~led_type_mode_data[i].reg_bit_mask));
|
||||
break;
|
||||
}
|
||||
|
||||
return reg_val;
|
||||
}
|
||||
|
||||
static int accton_as9716_32d_led_read_value(u8 reg)
|
||||
{
|
||||
return as9716_32d_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg);
|
||||
}
|
||||
|
||||
static int accton_as9716_32d_led_write_value(u8 reg, u8 value)
|
||||
{
|
||||
return as9716_32d_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_update(void)
|
||||
{
|
||||
mutex_lock(&ledctl->update_lock);
|
||||
|
||||
if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
|
||||
|| !ledctl->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&ledctl->pdev->dev, "Starting accton_as9716_32d_led update\n");
|
||||
|
||||
/* Update LED data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
|
||||
int status = accton_as9716_32d_led_read_value(led_reg_map[i].reg_addr);
|
||||
|
||||
if (status < 0) {
|
||||
ledctl->valid = 0;
|
||||
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg_map[i].reg_addr, status);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
ledctl->reg_val[i] = status;
|
||||
}
|
||||
}
|
||||
|
||||
ledctl->last_updated = jiffies;
|
||||
ledctl->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ledctl->update_lock);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode,
|
||||
enum led_type type)
|
||||
{
|
||||
int reg_val;
|
||||
u8 reg ;
|
||||
mutex_lock(&ledctl->update_lock);
|
||||
|
||||
if( !accton_getLedReg(type, ®))
|
||||
{
|
||||
dev_dbg(&ledctl->pdev->dev, "Not match item for %d.\n", type);
|
||||
}
|
||||
|
||||
reg_val = accton_as9716_32d_led_read_value(reg);
|
||||
|
||||
if (reg_val < 0) {
|
||||
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val);
|
||||
goto exit;
|
||||
}
|
||||
reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val);
|
||||
|
||||
accton_as9716_32d_led_write_value(reg, reg_val);
|
||||
|
||||
/* to prevent the slow-update issue */
|
||||
ledctl->valid = 0;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ledctl->update_lock);
|
||||
}
|
||||
|
||||
|
||||
static void accton_as9716_32d_led_diag_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as9716_32d_led_set(led_cdev, led_light_mode, LED_TYPE_DIAG);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as9716_32d_led_diag_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as9716_32d_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_loc_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as9716_32d_led_set(led_cdev, led_light_mode, LED_TYPE_LOC);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as9716_32d_led_loc_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as9716_32d_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_fan_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as9716_32d_led_set(led_cdev, led_light_mode, LED_TYPE_FAN);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as9716_32d_led_fan_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as9716_32d_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_psu1_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as9716_32d_led_set(led_cdev, led_light_mode, LED_TYPE_PSU1);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as9716_32d_led_psu1_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as9716_32d_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as9716_32d_led_psu2_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as9716_32d_led_set(led_cdev, led_light_mode, LED_TYPE_PSU2);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as9716_32d_led_psu2_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as9716_32d_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static struct led_classdev accton_as9716_32d_leds[] = {
|
||||
[LED_TYPE_DIAG] = {
|
||||
.name = "accton_as9716_32d_led::diag",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as9716_32d_led_diag_set,
|
||||
.brightness_get = accton_as9716_32d_led_diag_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN_BLINK,
|
||||
},
|
||||
[LED_TYPE_LOC] = {
|
||||
.name = "accton_as9716_32d_led::loc",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as9716_32d_led_loc_set,
|
||||
.brightness_get = accton_as9716_32d_led_loc_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN_BLINK,
|
||||
},
|
||||
[LED_TYPE_FAN] = {
|
||||
.name = "accton_as9716_32d_led::fan",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as9716_32d_led_fan_set,
|
||||
.brightness_get = accton_as9716_32d_led_fan_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AMBER,
|
||||
},
|
||||
[LED_TYPE_PSU1] = {
|
||||
.name = "accton_as9716_32d_led::psu1",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as9716_32d_led_psu1_set,
|
||||
.brightness_get = accton_as9716_32d_led_psu1_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AMBER,
|
||||
},
|
||||
[LED_TYPE_PSU2] = {
|
||||
.name = "accton_as9716_32d_led::psu2",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as9716_32d_led_psu2_set,
|
||||
.brightness_get = accton_as9716_32d_led_psu2_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AMBER,
|
||||
},
|
||||
};
|
||||
|
||||
static int accton_as9716_32d_led_suspend(struct platform_device *dev,
|
||||
pm_message_t state)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as9716_32d_leds); i++) {
|
||||
led_classdev_suspend(&accton_as9716_32d_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int accton_as9716_32d_led_resume(struct platform_device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as9716_32d_leds); i++) {
|
||||
led_classdev_resume(&accton_as9716_32d_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int accton_as9716_32d_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as9716_32d_leds); i++) {
|
||||
ret = led_classdev_register(&pdev->dev, &accton_as9716_32d_leds[i]);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if all LEDs were successfully registered */
|
||||
if (i != ARRAY_SIZE(accton_as9716_32d_leds)) {
|
||||
int j;
|
||||
|
||||
/* only unregister the LEDs that were successfully registered */
|
||||
for (j = 0; j < i; j++) {
|
||||
led_classdev_unregister(&accton_as9716_32d_leds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int accton_as9716_32d_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as9716_32d_leds); i++) {
|
||||
led_classdev_unregister(&accton_as9716_32d_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver accton_as9716_32d_led_driver = {
|
||||
.probe = accton_as9716_32d_led_probe,
|
||||
.remove = accton_as9716_32d_led_remove,
|
||||
.suspend = accton_as9716_32d_led_suspend,
|
||||
.resume = accton_as9716_32d_led_resume,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init accton_as9716_32d_led_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&accton_as9716_32d_led_driver);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ledctl = kzalloc(sizeof(struct accton_as9716_32d_led_data), GFP_KERNEL);
|
||||
if (!ledctl) {
|
||||
ret = -ENOMEM;
|
||||
platform_driver_unregister(&accton_as9716_32d_led_driver);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_init(&ledctl->update_lock);
|
||||
|
||||
ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
|
||||
if (IS_ERR(ledctl->pdev)) {
|
||||
ret = PTR_ERR(ledctl->pdev);
|
||||
platform_driver_unregister(&accton_as9716_32d_led_driver);
|
||||
kfree(ledctl);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit accton_as9716_32d_led_exit(void)
|
||||
{
|
||||
platform_device_unregister(ledctl->pdev);
|
||||
platform_driver_unregister(&accton_as9716_32d_led_driver);
|
||||
kfree(ledctl);
|
||||
}
|
||||
|
||||
module_init(accton_as9716_32d_led_init);
|
||||
module_exit(accton_as9716_32d_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("accton_as9716_32d_led driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* An hwmon driver for accton as9716_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 16
|
||||
#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 as9716_32d_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
|
||||
extern int as9716_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 as9716_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 as9716_32d_psu_data *as9716_32d_psu_update_device(struct device *dev);
|
||||
|
||||
enum as9716_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 *as9716_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 as9716_32d_psu_data *data = as9716_32d_psu_update_device(dev);
|
||||
u8 status = 0;
|
||||
|
||||
if (attr->index == PSU_PRESENT) {
|
||||
status = !(data->status >> (1-data->index) & 0x1);
|
||||
}
|
||||
else { /* PSU_POWER_GOOD */
|
||||
status = (data->status >> (3-data->index) & 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 as9716_32d_psu_data *data = as9716_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 as9716_32d_psu_group = {
|
||||
.attrs = as9716_32d_psu_attributes,
|
||||
};
|
||||
|
||||
static int as9716_32d_psu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct as9716_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 as9716_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, &as9716_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, &as9716_32d_psu_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as9716_32d_psu_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as9716_32d_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &as9716_32d_psu_group);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum psu_index
|
||||
{
|
||||
as9716_32d_psu1,
|
||||
as9716_32d_psu2
|
||||
};
|
||||
|
||||
static const struct i2c_device_id as9716_32d_psu_id[] = {
|
||||
{ "as9716_32d_psu1", as9716_32d_psu1 },
|
||||
{ "as9716_32d_psu2", as9716_32d_psu2 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as9716_32d_psu_id);
|
||||
|
||||
static struct i2c_driver as9716_32d_psu_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "as9716_32d_psu",
|
||||
},
|
||||
.probe = as9716_32d_psu_probe,
|
||||
.remove = as9716_32d_psu_remove,
|
||||
.id_table = as9716_32d_psu_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int as9716_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 as9716_32d_psu_data *as9716_32d_psu_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as9716_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 power_good = 0;
|
||||
|
||||
dev_dbg(&client->dev, "Starting as9716_32d update\n");
|
||||
|
||||
/* Read psu status */
|
||||
status = as9716_32d_cpld_read(0x60, 0x3);
|
||||
|
||||
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));
|
||||
power_good = (data->status >> (3-data->index) & 0x1);
|
||||
|
||||
if (power_good) {
|
||||
status = as9716_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);
|
||||
}
|
||||
else {
|
||||
data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0';
|
||||
|
||||
}
|
||||
/* Read from offset 0x2e ~ 0x3d (16 bytes) */
|
||||
status = as9716_32d_psu_read_block(client, 0x2e,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);
|
||||
}
|
||||
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(as9716_32d_psu_driver);
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as9716_32d_psu driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* An hwmon driver for the Accton Redundant Power Module
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define DRIVER_DESCRIPTION_NAME "accton i2c psu driver"
|
||||
/* PMBus Protocol. */
|
||||
#define PMBUS_LITERAL_DATA_MULTIPLIER 1000
|
||||
#define PMBUS_REGISTER_VOUT_MODE 0x20
|
||||
#define PMBUS_REGISTER_STATUS_BYTE 0x78
|
||||
#define PMBUS_REGISTER_STATUS_WORD 0x79
|
||||
#define PMBUS_REGISTER_STATUS_FAN 0x81
|
||||
#define PMBUS_REGISTER_READ_VIN 0x88
|
||||
#define PMBUS_REGISTER_READ_IIN 0x89
|
||||
#define PMBUS_REGISTER_READ_VOUT 0x8B
|
||||
#define PMBUS_REGISTER_READ_IOUT 0x8C
|
||||
#define PMBUS_REGISTER_READ_TEMPERATURE_1 0x8D
|
||||
#define PMBUS_REGISTER_READ_TEMPERATURE_2 0x8E
|
||||
#define PMBUS_REGISTER_READ_TEMPERATURE_3 0x8F
|
||||
#define PMBUS_REGISTER_READ_FAN_SPEED_1 0x90
|
||||
#define PMBUS_REGISTER_READ_FAN_SPEED_2 0x91
|
||||
|
||||
#define PMBUS_REGISTER_READ_FAN_CONFIG_1 0x3A
|
||||
#define PMBUS_REGISTER_FAN_COMMAND_1 0x3B
|
||||
|
||||
#define PMBUS_REGISTER_READ_POUT 0x96
|
||||
#define PMBUS_REGISTER_READ_PIN 0x97
|
||||
#define PMBUS_REGISTER_MFR_ID 0x99
|
||||
#define PMBUS_REGISTER_MFR_MODEL 0x9A
|
||||
#define PMBUS_REGISTER_MFR_REVISION 0x9B
|
||||
#define PMBUS_REGISTER_MFR_SERIAL 0x9E
|
||||
|
||||
|
||||
#define MAX_FAN_DUTY_CYCLE 100
|
||||
#define I2C_RW_RETRY_COUNT 10
|
||||
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
|
||||
|
||||
/* Addresses scanned
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
|
||||
|
||||
/* Each client has this additional data
|
||||
*/
|
||||
struct accton_i2c_psu_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 vout_mode; /* Register value */
|
||||
u16 v_in; /* Register value */
|
||||
u16 v_out; /* Register value */
|
||||
u16 i_in; /* Register value */
|
||||
u16 i_out; /* Register value */
|
||||
u16 p_in; /* Register value */
|
||||
u16 p_out; /* Register value */
|
||||
u16 temp_input[2]; /* Register value */
|
||||
u8 fan_fault; /* Register value */
|
||||
u16 fan_duty_cycle[2]; /* Register value */
|
||||
u16 fan_speed[2]; /* Register value */
|
||||
u8 pmbus_revision; /* Register value */
|
||||
u8 mfr_id[10]; /* Register value */
|
||||
u8 mfr_model[16]; /* Register value */
|
||||
u8 mfr_revsion[3]; /* Register value */
|
||||
u8 mfr_serial[26]; /* Register value */
|
||||
};
|
||||
|
||||
static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
|
||||
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
|
||||
static int accton_i2c_psu_write_word(struct i2c_client *client, u8 reg, u16 value);
|
||||
static struct accton_i2c_psu_data *accton_i2c_psu_update_device(struct device *dev);
|
||||
|
||||
enum accton_i2c_psu_sysfs_attributes {
|
||||
PSU_V_IN,
|
||||
PSU_V_OUT,
|
||||
PSU_I_IN,
|
||||
PSU_I_OUT,
|
||||
PSU_P_IN,
|
||||
PSU_P_OUT_UV,
|
||||
PSU_P_OUT,
|
||||
PSU_TEMP1_INPUT,
|
||||
PSU_FAN1_FAULT,
|
||||
PSU_FAN1_DUTY_CYCLE,
|
||||
PSU_FAN1_SPEED,
|
||||
PSU_PMBUS_REVISION,
|
||||
PSU_MFR_ID,
|
||||
PSU_MFR_MODEL,
|
||||
PSU_MFR_REVISION,
|
||||
PSU_MFR_SERIAL,
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN);
|
||||
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN);
|
||||
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN);
|
||||
static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
|
||||
static 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_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL);
|
||||
|
||||
|
||||
/*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 *accton_i2c_psu_attributes[] = {
|
||||
&sensor_dev_attr_psu_v_in.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_v_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_i_in.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_i_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_p_in.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_p_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
|
||||
&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_serial.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 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 accton_i2c_psu_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;
|
||||
accton_i2c_psu_write_word(client, PMBUS_REGISTER_FAN_COMMAND_1 + 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 accton_i2c_psu_data *data = accton_i2c_psu_update_device(dev);
|
||||
|
||||
u16 value = 0;
|
||||
int exponent, mantissa;
|
||||
int multiplier = 0;
|
||||
|
||||
switch (attr->index) {
|
||||
case PSU_V_IN:
|
||||
value = data->v_in;
|
||||
break;
|
||||
case PSU_I_IN:
|
||||
value = data->i_in;
|
||||
break;
|
||||
case PSU_I_OUT:
|
||||
value = data->i_out;
|
||||
break;
|
||||
case PSU_P_IN:
|
||||
value = data->p_in;
|
||||
break;
|
||||
case PSU_P_OUT_UV:
|
||||
multiplier=1;
|
||||
case PSU_P_OUT:
|
||||
value = data->p_out;
|
||||
break;
|
||||
case PSU_TEMP1_INPUT:
|
||||
value = data->temp_input[0];
|
||||
break;
|
||||
case PSU_FAN1_DUTY_CYCLE:
|
||||
multiplier = 1;
|
||||
value = data->fan_duty_cycle[0];
|
||||
break;
|
||||
case PSU_FAN1_SPEED:
|
||||
multiplier = 1;
|
||||
value = data->fan_speed[0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
|
||||
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
|
||||
|
||||
if(!multiplier)
|
||||
multiplier = PMBUS_LITERAL_DATA_MULTIPLIER;
|
||||
if(attr->index==PSU_P_OUT_UV)
|
||||
multiplier = 1000000;
|
||||
|
||||
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 accton_i2c_psu_data *data = accton_i2c_psu_update_device(dev);
|
||||
|
||||
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
|
||||
|
||||
return sprintf(buf, "%d\n", data->fan_fault >> shift);
|
||||
}
|
||||
|
||||
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct accton_i2c_psu_data *data = accton_i2c_psu_update_device(dev);
|
||||
int exponent, mantissa;
|
||||
|
||||
exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
|
||||
mantissa = data->v_out;
|
||||
|
||||
return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * PMBUS_LITERAL_DATA_MULTIPLIER) :
|
||||
sprintf(buf, "%d\n", (mantissa * PMBUS_LITERAL_DATA_MULTIPLIER) / (1 << -exponent));
|
||||
}
|
||||
|
||||
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 accton_i2c_psu_data *data = accton_i2c_psu_update_device(dev);
|
||||
|
||||
if (!data->valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) :
|
||||
sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct accton_i2c_psu_data *data = accton_i2c_psu_update_device(dev);
|
||||
u8 *ptr = NULL;
|
||||
|
||||
if (!data->valid) {
|
||||
return 0;
|
||||
}
|
||||
switch (attr->index) {
|
||||
|
||||
case PSU_MFR_ID:
|
||||
ptr = data->mfr_id;
|
||||
break;
|
||||
case PSU_MFR_MODEL:
|
||||
ptr = data->mfr_model;
|
||||
break;
|
||||
case PSU_MFR_REVISION:
|
||||
ptr = data->mfr_revsion;
|
||||
break;
|
||||
case PSU_MFR_SERIAL:
|
||||
ptr = data->mfr_serial;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", ptr);
|
||||
}
|
||||
|
||||
|
||||
static const struct attribute_group accton_i2c_psu_group = {
|
||||
.attrs = accton_i2c_psu_attributes,
|
||||
};
|
||||
|
||||
static int accton_i2c_psu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct accton_i2c_psu_data *data;
|
||||
int status;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(struct accton_i2c_psu_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, &accton_i2c_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, &accton_i2c_psu_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int accton_i2c_psu_remove(struct i2c_client *client)
|
||||
{
|
||||
struct accton_i2c_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &accton_i2c_psu_group);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Support psu moduel
|
||||
*/
|
||||
static const struct i2c_device_id accton_i2c_psu_id[] = {
|
||||
{ "acbel_fsh082", 0 },
|
||||
{ "yesm1300am", 1 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, accton_i2c_psu_id);
|
||||
|
||||
static struct i2c_driver accton_i2c_psu_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "accton_i2c_psu",
|
||||
},
|
||||
.probe = accton_i2c_psu_probe,
|
||||
.remove = accton_i2c_psu_remove,
|
||||
.id_table = accton_i2c_psu_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int accton_i2c_psu_read_byte(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int accton_i2c_psu_read_word(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_word_data(client, reg);
|
||||
}
|
||||
|
||||
static int accton_i2c_psu_write_word(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
return i2c_smbus_write_word_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int accton_i2c_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
|
||||
int data_len)
|
||||
{
|
||||
int status = 0, retry = I2C_RW_RETRY_COUNT;
|
||||
|
||||
while (retry) {
|
||||
status = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
|
||||
if (unlikely(status < 0)) {
|
||||
msleep(I2C_RW_RETRY_INTERVAL);
|
||||
retry--;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int accton_i2c_psu_read_block_data(struct i2c_client *client, u8 command, u8 *data, int data_length)
|
||||
{
|
||||
int status = -EIO;
|
||||
int length;
|
||||
u8 buffer[128] = {0}, *ptr = buffer;
|
||||
|
||||
status = accton_i2c_psu_read_byte(client, command);
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "Unable to get data from offset 0x%02X\r\n", command);
|
||||
status = -EIO;
|
||||
goto EXIT_READ_BLOCK_DATA;
|
||||
}
|
||||
|
||||
status = (status & 0xFF) + 1;
|
||||
if ( status > 128)
|
||||
{
|
||||
dev_dbg(&client->dev, "Unable to get big data from offset 0x%02X\r\n", command);
|
||||
status = -EINVAL;
|
||||
goto EXIT_READ_BLOCK_DATA;
|
||||
}
|
||||
|
||||
length = status;
|
||||
status = accton_i2c_psu_read_block(client, command, buffer, length);
|
||||
if (unlikely(status < 0))
|
||||
goto EXIT_READ_BLOCK_DATA;
|
||||
if (unlikely(status != length)) {
|
||||
status = -EIO;
|
||||
goto EXIT_READ_BLOCK_DATA;
|
||||
}
|
||||
/* The first byte is the count byte of string. */
|
||||
ptr++;
|
||||
status--;
|
||||
|
||||
length=status>(data_length-1)?(data_length-1):status;
|
||||
memcpy(data, ptr, length);
|
||||
data[length-1] = 0;
|
||||
|
||||
EXIT_READ_BLOCK_DATA:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
struct reg_data_byte {
|
||||
u8 reg;
|
||||
u8 *value;
|
||||
};
|
||||
|
||||
struct reg_data_word {
|
||||
u8 reg;
|
||||
u16 *value;
|
||||
};
|
||||
|
||||
static struct accton_i2c_psu_data *accton_i2c_psu_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct accton_i2c_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 i, status;
|
||||
//u8 command, buf;
|
||||
struct reg_data_byte regs_byte[] = { {PMBUS_REGISTER_VOUT_MODE, &data->vout_mode},
|
||||
{PMBUS_REGISTER_STATUS_FAN, &data->fan_fault}};
|
||||
struct reg_data_word regs_word[] = { {PMBUS_REGISTER_READ_VIN, &data->v_in},
|
||||
{PMBUS_REGISTER_READ_VOUT, &data->v_out},
|
||||
{PMBUS_REGISTER_READ_IIN, &data->i_in},
|
||||
{PMBUS_REGISTER_READ_IOUT, &data->i_out},
|
||||
{PMBUS_REGISTER_READ_POUT, &data->p_out},
|
||||
{PMBUS_REGISTER_READ_PIN, &data->p_in},
|
||||
{PMBUS_REGISTER_READ_TEMPERATURE_1, &(data->temp_input[0])},
|
||||
{PMBUS_REGISTER_READ_TEMPERATURE_2, &(data->temp_input[1])},
|
||||
{PMBUS_REGISTER_FAN_COMMAND_1, &(data->fan_duty_cycle[0])},
|
||||
{PMBUS_REGISTER_READ_FAN_SPEED_1, &(data->fan_speed[0])},
|
||||
{PMBUS_REGISTER_READ_FAN_SPEED_2, &(data->fan_speed[1])},
|
||||
};
|
||||
|
||||
dev_dbg(&client->dev, "Starting accton_i2c_psu update\n");
|
||||
|
||||
/* Read byte data */
|
||||
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
|
||||
status = accton_i2c_psu_read_byte(client, regs_byte[i].reg);
|
||||
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_byte[i].reg, status);
|
||||
}
|
||||
else {
|
||||
*(regs_byte[i].value) = status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read word data */
|
||||
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
|
||||
status = accton_i2c_psu_read_word(client, regs_word[i].reg);
|
||||
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_word[i].reg, status);
|
||||
}
|
||||
else {
|
||||
*(regs_word[i].value) = status;
|
||||
}
|
||||
|
||||
}
|
||||
/* Read mfr_id */
|
||||
status = accton_i2c_psu_read_block_data(client, PMBUS_REGISTER_MFR_ID, data->mfr_id,
|
||||
ARRAY_SIZE(data->mfr_id));
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", PMBUS_REGISTER_MFR_ID, status);
|
||||
goto exit;
|
||||
}
|
||||
/* Read mfr_model */
|
||||
status = accton_i2c_psu_read_block_data(client, PMBUS_REGISTER_MFR_MODEL, data->mfr_model,
|
||||
ARRAY_SIZE(data->mfr_model));
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", PMBUS_REGISTER_MFR_MODEL, status);
|
||||
goto exit;
|
||||
}
|
||||
/* Read mfr_revsion */
|
||||
status = accton_i2c_psu_read_block_data(client, PMBUS_REGISTER_MFR_REVISION, data->mfr_revsion,
|
||||
ARRAY_SIZE(data->mfr_revsion));
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", PMBUS_REGISTER_MFR_REVISION, status);
|
||||
goto exit;
|
||||
}
|
||||
/* Read mfr_serial */
|
||||
status = accton_i2c_psu_read_block_data(client, PMBUS_REGISTER_MFR_SERIAL, data->mfr_serial,
|
||||
ARRAY_SIZE(data->mfr_serial));
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", PMBUS_REGISTER_MFR_SERIAL, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init accton_i2c_psu_init(void)
|
||||
{
|
||||
return i2c_add_driver(&accton_i2c_psu_driver);
|
||||
}
|
||||
|
||||
static void __exit accton_i2c_psu_exit(void)
|
||||
{
|
||||
i2c_del_driver(&accton_i2c_psu_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESCRIPTION_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(accton_i2c_psu_init);
|
||||
module_exit(accton_i2c_psu_exit);
|
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Accton AS9716-32D Platform Monitoring FAN service
|
||||
Before=pmon.service
|
||||
After=as9716-32d-platform-monitor.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as9716_32d_monitor_fan.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Accton AS9716-32D Platform Monitoring PSU service
|
||||
Before=pmon.service
|
||||
After=as9716-32d-platform-monitor.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as9716_32d_monitor_psu.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=Accton AS9716-32D Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=sysinit.target
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/local/bin/accton_as9716_32d_util.py install
|
||||
ExecStart=/usr/local/bin/accton_as9716_32d_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
#StandardOutput=tty
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
16
platform/broadcom/sonic-platform-modules-accton/as9716-32d/setup.py
Executable file
16
platform/broadcom/sonic-platform-modules-accton/as9716-32d/setup.py
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from setuptools import setup
|
||||
os.listdir
|
||||
|
||||
setup(
|
||||
name='as9716_32d',
|
||||
version='1.0',
|
||||
description='Module to initialize Accton AS9716-32D platforms',
|
||||
|
||||
packages=['as9716_32d'],
|
||||
package_dir={'as9716_32d': 'as9716-32d/classes'},
|
||||
)
|
||||
|
117
platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/README
Executable file
117
platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/README
Executable file
@ -0,0 +1,117 @@
|
||||
Copyright (C) 2016 Accton Networks, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
It under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contents of this package:
|
||||
patch - files under patch/ is for kernel and ONIE installer
|
||||
for the kernel:
|
||||
config-accton-as5712_54x.patch
|
||||
for kernel configuration.
|
||||
driver-i2c-muxes-pca954x-always-deselect.patch
|
||||
for i2c_mux deselects after transaction.
|
||||
driver-patches-for-accton-as5712-fan-psu-cpld.patch
|
||||
for as5712's fan/psu/cpld/led/sfp drivers.
|
||||
for ONIE:
|
||||
onie_installer-accton-AS5712-54X.patch
|
||||
for console port setting and copy util script o rootfs.
|
||||
module - Contains source code of as5712 kernel driver modules.
|
||||
|
||||
The late Sonic building scripts, pushed @Dec 5 2016, will automatically
|
||||
create a docker container and run building process under it.
|
||||
User is not necessary to handle docker environment creation.
|
||||
|
||||
1. Download sonic-buildimage environment.
|
||||
- Run "git clone https://github.com/Azure/sonic-buildimage".
|
||||
- cd to sonic-buildimage and run "git submodule update --init --recursive".
|
||||
2. Build kernel
|
||||
- cd ./src/sonic-linux-kernel
|
||||
- Copy patches and series from patch/kernel of this release to
|
||||
sonic-linux-kernel/patch.
|
||||
- Build kernel by "make".
|
||||
- The built kernel package, linux-image-3.16.0-5-amd64_3.16.51-3+deb8u1_amd64.deb
|
||||
, is generated.
|
||||
3. Build installer
|
||||
- Change directory back to sonic-buildimage/.
|
||||
- Get onie_installer-accton-AS5712-54X.patch" from patch/installer.
|
||||
- Change setting for AS5712-54X by patching build_image.sh.
|
||||
"patch -p1 < onie_installer-accton-AS5712-54X.patch"
|
||||
!!NOTICE, patching onie_installer-accton-AS5712-54X.patch comments out the
|
||||
"git status" checking at build_image.sh.
|
||||
- The account and password of installed OS can be given at rules/config.
|
||||
The default user and password are "admin" & "YourPaSsWoRd" respectively.
|
||||
- Run "make configure PLATFORM=broadcom"
|
||||
- Copy the built kernel debian package to target/debs/.
|
||||
The file is linux-image-3.16.0-5-amd64_*_amd64.deb under directory
|
||||
src/sonic-linux-kernel/.
|
||||
- Run "make target/sonic-generic.bin"
|
||||
- Get the installer, target/sonic-generic.bin, to target machine and install.
|
||||
|
||||
All Linux kernel code is licensed under the GPLv1. All other code is
|
||||
licensed under the GPLv3. Please see the LICENSE file for copies of
|
||||
both licenses.
|
||||
|
||||
The code for integacting with Accton AS5712-54X has 2 parts,
|
||||
kernel drivers and operational script.
|
||||
The kernel drivers of peripherals are under module/ directory.
|
||||
1. These drivers are patched into kernel by
|
||||
driver-patches-for-accton-as5712-fan-psu-cpld.patch
|
||||
Or you can build the driver under module/ by setting environment variable,
|
||||
KERNEL_SRC, to proper linux built directory and run make.
|
||||
It may be sonic-linux-kernel/linux-3.*/debian/build/build_amd64_none_amd64/.
|
||||
2. A operational script, accton_as5712_util.py, for device initializatian and
|
||||
peripheral accessing should be installed at /usr/bin.
|
||||
This script is generated by onie_installer-accton-AS5712-54X.patch.
|
||||
It's done by patching onie_installer-accton-AS5712-54X.patch at build-image.
|
||||
Run "accton_as5712_util.py install" to install drivers.
|
||||
|
||||
To initialize the system, run "accton_as5712_util.py install".
|
||||
To clean up the drivers & devices, run "accton_as5712_util.py clean".
|
||||
To dump information of sensors, run "accton_as5712_util.py show".
|
||||
To dump SFP EEPROM, run "accton_as5712_util.py sff".
|
||||
To set fan speed, run "accton_as5712_util.py set fan".
|
||||
To enable/disable SFP emission, run "accton_as5712_util.py set sfp".
|
||||
To set system LEDs' color, run "accton_as5712_util.py set led"
|
||||
For more information, run "accton_as5712_util.py --help".
|
||||
|
||||
====================================================================
|
||||
Besides applying accton_as5712_util.py to access peripherals, you can
|
||||
access peripherals by sysfs nodes directly after the installation is run.
|
||||
|
||||
System LED:
|
||||
There are 5 system LEDs at the lower-left corner of front panel.
|
||||
They are loc, diag, fan, ps1, and ps2.
|
||||
The sysfs interface color mappings are as follows:
|
||||
Brightness:
|
||||
0 => off
|
||||
1 => green
|
||||
2 => amber
|
||||
3 => red
|
||||
4 => blue
|
||||
But not all colors are available for each LED.
|
||||
|
||||
Fan Control:
|
||||
There are 10 fans inside 5 fan modules.
|
||||
All fans share 1 duty setting, ranged from 0~100.
|
||||
|
||||
Thermal sensers:
|
||||
3 temperature sensors are controlled by the lm75 kernel modules.
|
||||
|
||||
PSUs:
|
||||
There 2 power supplies slot at the left/right side of the back.
|
||||
Once if a PSU is not plugged, the status of it is shown failed.
|
||||
|
||||
There are 48 SFP+ and 6 QSFP modules are equipped.
|
||||
Before operating on PSU and QSFP+, please make sure it is well plugged.
|
||||
Otherwise, operation is going to fail.
|
||||
|
@ -0,0 +1,344 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2017 Accton Technology Corporation
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)#
|
||||
# 12/19/2018:Jostar create for as9716_32d thermal plan
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import os
|
||||
import sys, getopt
|
||||
import subprocess
|
||||
import click
|
||||
import imp
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import types
|
||||
import time # this is only being used as part of the example
|
||||
import traceback
|
||||
from tabulate import tabulate
|
||||
from as9716_32d.fanutil import FanUtil
|
||||
from as9716_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_as9716_32x_monitor'
|
||||
|
||||
global log_file
|
||||
global log_level
|
||||
|
||||
|
||||
# Air Flow Front to Back :
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=38C : Keep 37.5%(0x04) Fan speed
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 38C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08)
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 46C : Change Fan speed from 62.5%(0x08) to 100%(0x0E)
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 58C : Send alarm message
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 66C : Shut down system
|
||||
# One Fan fail : Change Fan speed to 100%(0x0E)
|
||||
|
||||
|
||||
# Air Flow Back to Front :
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=34C : Keep 37.5%(0x04) Fan speed
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 34C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08)
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 44C : Change Fan speed from 62.5%(0x08) to 100%(0x0E)
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 59C : Send alarm message
|
||||
# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 67C : Shut down system
|
||||
# One Fan fail: Change Fan speed to 100%(0x0E)
|
||||
# sensor_LM75_CPU == sensor_LM75_4B
|
||||
|
||||
|
||||
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_policy_state=1
|
||||
fan_fail=0
|
||||
alarm_state = 0 #0->default or clear, 1-->alarm detect
|
||||
test_temp = 0
|
||||
test_temp_list = [0, 0, 0, 0, 0, 0]
|
||||
temp_test_data=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_pwm = 0
|
||||
pwm=0
|
||||
ori_pwm = 0
|
||||
default_pwm=0x4
|
||||
|
||||
def __init__(self, log_file, log_level):
|
||||
"""Needs a logger and a logger level."""
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
# set up logging to console
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(log_level)
|
||||
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = 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 get_state_from_fan_policy(self, temp, policy):
|
||||
state=0
|
||||
|
||||
logging.debug('temp=%d', temp)
|
||||
for i in range(0, len(policy)):
|
||||
#logging.debug('policy[%d][0]=%d, policy[%d][1]=%d, policy[%d][2]=%d', i,policy[i][0],i, policy[i][1], i, policy[i][2])
|
||||
if temp > policy[i][2]:
|
||||
if temp <= policy[i][3]:
|
||||
state =i
|
||||
logging.debug ('temp=%d >= policy[%d][2]=%d, temp=%d < policy[%d][3]=%d' , temp, i, policy[i][2], temp, i, policy[i][3])
|
||||
logging.debug ('fan_state=%d', state)
|
||||
break
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def manage_fans(self):
|
||||
|
||||
global fan_policy_state
|
||||
global fan_fail
|
||||
global test_temp
|
||||
global test_temp_list
|
||||
global alarm_state
|
||||
global temp_test_data
|
||||
|
||||
LEVEL_FAN_DEF=0
|
||||
LEVEL_FAN_MID=1
|
||||
LEVEL_FAN_MAX=2
|
||||
LEVEL_TEMP_HIGH=3
|
||||
LEVEL_TEMP_CRITICAL=4
|
||||
|
||||
|
||||
fan_policy_f2b = {
|
||||
LEVEL_FAN_DEF: [38, 0x4, 0, 38000],
|
||||
LEVEL_FAN_MID: [63, 0x6, 38000, 46000],
|
||||
LEVEL_FAN_MAX: [100, 0xE, 46000, 58000],
|
||||
LEVEL_TEMP_HIGH: [100, 0xE, 58000, 66000],
|
||||
LEVEL_TEMP_CRITICAL: [100, 0xE, 58000, 200000],
|
||||
}
|
||||
fan_policy_b2f = {
|
||||
LEVEL_FAN_DEF: [38, 0x4, 0, 34000],
|
||||
LEVEL_FAN_MID: [63, 0x8, 34000, 44000],
|
||||
LEVEL_FAN_MAX: [100, 0xE, 44000, 59000],
|
||||
LEVEL_TEMP_HIGH: [100, 0xE, 59000, 67000],
|
||||
LEVEL_TEMP_CRITICAL: [100, 0xE, 59000, 200000],
|
||||
}
|
||||
|
||||
fan_policy = fan_policy_f2b
|
||||
|
||||
thermal = ThermalUtil()
|
||||
fan = FanUtil()
|
||||
fan_dir=fan.get_fan_dir(1)
|
||||
if fan_dir == 1:
|
||||
fan_dri=1 #something wrong, set fan_dir to default val
|
||||
else:
|
||||
fan_policy = fan_policy_b2f
|
||||
|
||||
ori_pwm=fan.get_fan_duty_cycle()
|
||||
new_pwm=0
|
||||
logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm)
|
||||
logging.debug('test_temp=%d', test_temp)
|
||||
if test_temp==0:
|
||||
temp1 = thermal._get_thermal_val(1)
|
||||
temp2 = thermal._get_thermal_val(2)
|
||||
temp3 = thermal._get_thermal_val(3)
|
||||
temp4 = thermal._get_thermal_val(4)
|
||||
temp5 = thermal._get_thermal_val(5)
|
||||
else:
|
||||
temp1 = test_temp_list[0]
|
||||
temp2 = test_temp_list[1]
|
||||
temp3 = test_temp_list[2]
|
||||
temp4 = test_temp_list[3]
|
||||
temp5 = test_temp_list[4]
|
||||
fan_fail=0
|
||||
|
||||
if temp3==0:
|
||||
temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75%
|
||||
logging.debug('lm75_49 detect fail, so set temp_get=50000, let fan to 75%')
|
||||
elif temp4==0:
|
||||
temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75%
|
||||
logging.debug('lm75_4b detect fail, so set temp_get=50000, let fan to 75%')
|
||||
else:
|
||||
temp_get= (temp3 + temp4)/2 # Use (sensor_LM75_4a + sensor_LM75_4b) /2
|
||||
ori_state=fan_policy_state
|
||||
|
||||
#temp_test_data=temp_test_data+1000
|
||||
#temp_get = temp_get + temp_test_data
|
||||
#print "Unit test:temp_get=%d"%temp_get
|
||||
|
||||
fan_policy_state=self.get_state_from_fan_policy(temp_get, fan_policy)
|
||||
#print "temp3=%d"%temp3
|
||||
#print "temp4=%d"%temp4
|
||||
#print "temp_get=%d"%temp_get
|
||||
|
||||
logging.debug('lm75_48=%d, lm75_49=%d, lm75_4a=%d, lm_4b=%d, lm_4b=%d', temp1,temp2,temp3,temp4,temp5)
|
||||
logging.debug('ori_state=%d, fan_policy_state=%d', ori_state, fan_policy_state)
|
||||
new_pwm = fan_policy[fan_policy_state][0]
|
||||
if fan_fail==0:
|
||||
logging.debug('new_fan_cycle=%d', new_pwm)
|
||||
|
||||
if fan_fail==0:
|
||||
if new_pwm!=ori_pwm:
|
||||
fan.set_fan_duty_cycle(new_pwm)
|
||||
logging.info('Set fan speed from %d to %d', ori_pwm, new_pwm)
|
||||
|
||||
#Check Fan status
|
||||
for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1):
|
||||
if fan.get_fan_status(i)==0:
|
||||
new_pwm=100
|
||||
logging.debug('fan_%d fail, set pwm to 100',i)
|
||||
if test_temp==0:
|
||||
fan_fail=1
|
||||
fan.set_fan_duty_cycle(new_pwm)
|
||||
break
|
||||
else:
|
||||
fan_fail=0
|
||||
|
||||
#if fan_policy_state == ori_state:
|
||||
# return True
|
||||
#else:
|
||||
new_state = fan_policy_state
|
||||
|
||||
#logging.warning('Temperature high alarm testing')
|
||||
if ori_state==LEVEL_FAN_DEF:
|
||||
if new_state==LEVEL_TEMP_HIGH:
|
||||
if alarm_state==0:
|
||||
logging.warning('Alarm for temperature high is detected')
|
||||
alarm_state=1
|
||||
if new_state==LEVEL_TEMP_CRITICAL:
|
||||
logging.critical('Alarm for temperature critical is detected, reboot DUT')
|
||||
time.sleep(2)
|
||||
os.system('reboot')
|
||||
if ori_state==LEVEL_FAN_MID:
|
||||
if new_state==LEVEL_TEMP_HIGH:
|
||||
if alarm_state==0:
|
||||
logging.warning('Alarm for temperature high is detected')
|
||||
alarm_state=1
|
||||
if new_state==LEVEL_TEMP_CRITICAL:
|
||||
logging.critical('Alarm for temperature critical is detected')
|
||||
time.sleep(2)
|
||||
os.system('reboot')
|
||||
if ori_state==LEVEL_FAN_MAX:
|
||||
if new_state==LEVEL_TEMP_HIGH:
|
||||
if alarm_state==0:
|
||||
logging.warning('Alarm for temperature high is detected')
|
||||
alarm_state=1
|
||||
if new_state==LEVEL_TEMP_CRITICAL:
|
||||
logging.critical('Alarm for temperature critical is detected')
|
||||
time.sleep(2)
|
||||
os.system('reboot')
|
||||
if alarm_state==1:
|
||||
if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm
|
||||
logging.warning('Alarm for temperature high is cleared')
|
||||
alarm_state=0
|
||||
if ori_state==LEVEL_TEMP_HIGH:
|
||||
if new_state==LEVEL_TEMP_CRITICAL:
|
||||
logging.critical('Alarm for temperature critical is detected')
|
||||
time.sleep(2)
|
||||
os.system('reboot')
|
||||
if new_state <= LEVEL_FAN_MID:
|
||||
logging.warning('Alarm for temperature high is cleared')
|
||||
alarm_state=0
|
||||
if new_state <= LEVEL_FAN_MAX:
|
||||
if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm
|
||||
logging.warning('Alarm for temperature high is cleared')
|
||||
alarm_state=0
|
||||
if ori_state==LEVEL_TEMP_CRITICAL:
|
||||
if new_state <= LEVEL_FAN_MAX:
|
||||
logging.warning('Alarm for temperature critical is cleared')
|
||||
|
||||
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)!=7:
|
||||
print "temp test, need input six temp"
|
||||
return 0
|
||||
|
||||
i=0
|
||||
for x in range(2, 7):
|
||||
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(38)
|
||||
print "set default fan speed to 37.5%"
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
# Loop forever, doing something useful hopefully:
|
||||
while True:
|
||||
#monitor.manage_fans()
|
||||
time.sleep(5)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
|
@ -0,0 +1,197 @@
|
||||
#!/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.)
|
||||
# 12/13/2018: Jostar create for as9716-32d
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import os
|
||||
import sys, getopt
|
||||
import subprocess
|
||||
import click
|
||||
import imp
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import types
|
||||
import time # this is only being used as part of the example
|
||||
import traceback
|
||||
from tabulate import tabulate
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = '/usr/local/bin/accton_as9716_32d_monitor_fan'
|
||||
|
||||
global log_file
|
||||
global log_level
|
||||
|
||||
|
||||
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/17-0066/"
|
||||
self.present = {
|
||||
0: "fan1_present",
|
||||
1: "fan2_present",
|
||||
2: "fan3_present",
|
||||
3: "fan4_present",
|
||||
4: "fan5_present",
|
||||
5: "fan6_present",
|
||||
}
|
||||
|
||||
self.fault = {
|
||||
0: "fan1_fault",
|
||||
1: "fan2_fault",
|
||||
2: "fan3_fault",
|
||||
3: "fan4_fault",
|
||||
4: "fan5_fault",
|
||||
5: "fan6_fault",
|
||||
}
|
||||
|
||||
|
||||
"""Needs a logger and a logger level."""
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
|
||||
# set up logging to console
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||
#sys_handler.setLevel(logging.WARNING)
|
||||
sys_handler.setLevel(logging.INFO)
|
||||
logging.getLogger('').addHandler(sys_handler)
|
||||
|
||||
|
||||
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||
|
||||
def manage_fan(self):
|
||||
|
||||
FAN_STATE_REMOVE = 0
|
||||
FAN_STATE_INSERT = 1
|
||||
|
||||
FAN_STATUS_FAULT = 1
|
||||
FAN_STATUS_NORMAL = 0
|
||||
|
||||
global fan_state
|
||||
global fan_status_state
|
||||
|
||||
for idx in range (0, self.fan_num):
|
||||
node = self.fan_path + self.present[idx]
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if fan_state[idx]!=1:
|
||||
fan_state[idx]=FAN_STATE_INSERT
|
||||
logging.info("FAN-%d present is detected", idx+1);
|
||||
else:
|
||||
if fan_state[idx]!=0:
|
||||
fan_state[idx]=FAN_STATE_REMOVE
|
||||
logging.warning("Alarm for FAN-%d absent is detected", idx+1)
|
||||
|
||||
for idx in range (0, self.fan_num):
|
||||
node = self.fan_path + self.fault[idx]
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if fan_status_state[idx]!=FAN_STATUS_FAULT:
|
||||
if fan_state[idx] == FAN_STATE_INSERT:
|
||||
logging.warning("Alarm for FAN-%d failed is detected", idx+1);
|
||||
fan_status_state[idx]=FAN_STATUS_FAULT
|
||||
else:
|
||||
fan_status_state[idx]=FAN_STATUS_NORMAL
|
||||
|
||||
return True
|
||||
|
||||
def main(argv):
|
||||
log_file = '%s.log' % FUNCTION_NAME
|
||||
log_level = logging.INFO
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv,'hdl:',['lfile='])
|
||||
except getopt.GetoptError:
|
||||
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
|
||||
return 0
|
||||
elif opt in ('-d', '--debug'):
|
||||
log_level = logging.DEBUG
|
||||
elif opt in ('-l', '--lfile'):
|
||||
log_file = arg
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
while True:
|
||||
monitor.manage_fan()
|
||||
time.sleep(3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,169 @@
|
||||
#!/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.)
|
||||
# 12/12/2018: Jostar create for as9716-32d
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import os
|
||||
import sys, getopt
|
||||
import subprocess
|
||||
import click
|
||||
import imp
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import types
|
||||
import time # this is only being used as part of the example
|
||||
import traceback
|
||||
from tabulate import tabulate
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = '/usr/local/bin/accton_as9716_32d_monitor_psu'
|
||||
|
||||
global log_file
|
||||
global log_level
|
||||
|
||||
|
||||
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: "10-0051",
|
||||
}
|
||||
|
||||
"""Needs a logger and a logger level."""
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
# set up logging to console
|
||||
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(log_level)
|
||||
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||
#sys_handler.setLevel(logging.WARNING)
|
||||
sys_handler.setLevel(logging.INFO)
|
||||
logging.getLogger('').addHandler(sys_handler)
|
||||
|
||||
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||
|
||||
def manage_psu(self):
|
||||
|
||||
PSU_STATE_REMOVE = 0
|
||||
PSU_STATE_INSERT = 1
|
||||
|
||||
PSU_STATUS_NO_POWER = 0
|
||||
PSU_STATUS_POWER_GOOD = 1
|
||||
PSU_STATUS_IDLE =2
|
||||
|
||||
global psu_state
|
||||
|
||||
for idx in range (0, self.psu_num):
|
||||
node = self.psu_path + self.mapping[idx] + self.presence
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if psu_state[idx]!=1:
|
||||
psu_state[idx]=PSU_STATE_INSERT
|
||||
logging.info("PSU-%d present is detected", idx+1);
|
||||
#psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert, assume power is good. If no_power, next code will find it.
|
||||
else:
|
||||
if psu_state[idx]!=0:
|
||||
psu_state[idx]=PSU_STATE_REMOVE
|
||||
logging.warning("Alarm for PSU-%d absent is detected", idx+1);
|
||||
psu_status_state[idx]=PSU_STATUS_IDLE
|
||||
|
||||
for idx in range (0, self.psu_num):
|
||||
node = self.psu_path + self.mapping[idx] + self.oper_status
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print "Error: unable to open file: %s" % str(e)
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "0":
|
||||
if psu_status_state[idx]!=PSU_STATUS_NO_POWER:
|
||||
if psu_state[idx]==PSU_STATE_INSERT:
|
||||
logging.warning("Alarm for PSU-%d failed is detected", idx+1);
|
||||
psu_status_state[idx]=PSU_STATUS_NO_POWER
|
||||
else:
|
||||
if psu_state[idx]==PSU_STATE_INSERT:
|
||||
if psu_status_state[idx]!=PSU_STATUS_POWER_GOOD:
|
||||
logging.info("PSU-%d power_good is detected", idx+1);
|
||||
psu_status_state[idx]=PSU_STATUS_POWER_GOOD
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def main(argv):
|
||||
log_file = '%s.log' % FUNCTION_NAME
|
||||
log_level = logging.INFO
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv,'hdl:',['lfile='])
|
||||
except getopt.GetoptError:
|
||||
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
|
||||
return 0
|
||||
elif opt in ('-d', '--debug'):
|
||||
log_level = logging.DEBUG
|
||||
elif opt in ('-l', '--lfile'):
|
||||
log_file = arg
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
# Loop forever, doing something useful hopefully:
|
||||
while True:
|
||||
monitor.manage_psu()
|
||||
time.sleep(3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,571 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2016 Accton Networks, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Usage: %(scriptName)s [options] command object
|
||||
|
||||
options:
|
||||
-h | --help : this help message
|
||||
-d | --debug : run with debug mode
|
||||
-f | --force : ignore error during installation or clean
|
||||
command:
|
||||
install : install drivers and generate related sysfs nodes
|
||||
clean : uninstall drivers and remove related sysfs nodes
|
||||
show : show all systen status
|
||||
sff : dump SFP eeprom
|
||||
set : change board setting with fan|led|sfp
|
||||
"""
|
||||
|
||||
import os
|
||||
import commands
|
||||
import sys, getopt
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from collections import namedtuple
|
||||
|
||||
PROJECT_NAME = 'as9716_32d'
|
||||
version = '0.0.1'
|
||||
verbose = False
|
||||
DEBUG = False
|
||||
args = []
|
||||
ALL_DEVICE = {}
|
||||
DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':3, 'psu':2, 'sfp':34}
|
||||
|
||||
|
||||
led_prefix ='/sys/devices/platform/as9716_32d_led/leds/accton_'+PROJECT_NAME+'_led::'
|
||||
fan_prefix ='/sys/devices/platform/as9716_32d_'
|
||||
hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'],
|
||||
'fan1': ['fan'],
|
||||
'fan2': ['fan'],
|
||||
'fan3': ['fan'],
|
||||
'fan4': ['fan'],
|
||||
'fan5': ['fan'],
|
||||
'fan5': ['fan'],
|
||||
}
|
||||
hwmon_nodes = {'led': ['brightness'] ,
|
||||
'fan1': ['fan_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'],
|
||||
'fan2': ['fan_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'],
|
||||
'fan3': ['fan_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'],
|
||||
'fan4': ['fan_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'],
|
||||
'fan5': ['fan_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'],
|
||||
'fan6': ['fan_duty_cycle_percentage','fan6_fault', 'fan6_speed_rpm', 'fan6_direction', 'fanr5_fault', 'fanr5_speed_rpm'],
|
||||
}
|
||||
hwmon_prefix ={'led': led_prefix,
|
||||
'fan1': fan_prefix,
|
||||
'fan2': fan_prefix,
|
||||
'fan3': fan_prefix,
|
||||
'fan4': fan_prefix,
|
||||
'fan5': fan_prefix,
|
||||
}
|
||||
|
||||
i2c_prefix = '/sys/bus/i2c/devices/'
|
||||
i2c_bus = {'fan': ['54-0066'],
|
||||
'thermal': ['18-0048', '18-0049','18-004a', '18-004b', '18-004c', '18-004e', '18-004f'] ,
|
||||
'psu': ['9-0058', '10-0059'],
|
||||
'sfp': ['-0050']}
|
||||
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 = [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, 51, 52, 53, 54, 55, 56,
|
||||
57, 58]
|
||||
|
||||
#sfp_map = [25, 26]
|
||||
|
||||
mknod =[
|
||||
'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
|
||||
'echo as9716_32d_fpga 0x60 > /sys/bus/i2c/devices/i2c-19/new_device',
|
||||
'echo as9716_32d_cpld1 0x61 > /sys/bus/i2c/devices/i2c-20/new_device',
|
||||
'echo as9716_32d_cpld2 0x62 > /sys/bus/i2c/devices/i2c-21/new_device',
|
||||
'echo as9716_32d_cpld_cpu 0x65 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||
|
||||
'echo as9716_32d_fan 0x66 > /sys/bus/i2c/devices/i2c-17/new_device',
|
||||
|
||||
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x4e > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
'echo lm75 0x4f > /sys/bus/i2c/devices/i2c-18/new_device',
|
||||
|
||||
# PSU-1
|
||||
'echo as9716_32d_psu1 0x50 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||
'echo acbel_fsh082 0x58 > /sys/bus/i2c/devices/i2c-9/new_device',
|
||||
|
||||
# PSU-2
|
||||
'echo as9716_32d_psu2 0x51 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||
'echo acbel_fsh082 0x59 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||
|
||||
#EERPOM
|
||||
'echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||
]
|
||||
|
||||
|
||||
|
||||
FORCE = 0
|
||||
logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
if DEBUG == True:
|
||||
print sys.argv[0]
|
||||
print 'ARGV :', sys.argv[1:]
|
||||
|
||||
|
||||
def main():
|
||||
global DEBUG
|
||||
global args
|
||||
global FORCE
|
||||
|
||||
if len(sys.argv)<2:
|
||||
show_help()
|
||||
|
||||
options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
|
||||
'debug',
|
||||
'force',
|
||||
])
|
||||
if DEBUG == True:
|
||||
print options
|
||||
print args
|
||||
print len(sys.argv)
|
||||
|
||||
for opt, arg in options:
|
||||
if opt in ('-h', '--help'):
|
||||
show_help()
|
||||
elif opt in ('-d', '--debug'):
|
||||
DEBUG = True
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
elif opt in ('-f', '--force'):
|
||||
FORCE = 1
|
||||
else:
|
||||
logging.info('no option')
|
||||
for arg in args:
|
||||
if arg == 'install':
|
||||
do_install()
|
||||
elif arg == 'clean':
|
||||
do_uninstall()
|
||||
elif arg == 'show':
|
||||
device_traversal()
|
||||
elif arg == 'sff':
|
||||
if len(args)!=2:
|
||||
show_eeprom_help()
|
||||
elif int(args[1]) > DEVICE_NO['sfp'] -1:
|
||||
show_eeprom_help()
|
||||
else:
|
||||
show_eeprom(args[1])
|
||||
return
|
||||
elif arg == 'set':
|
||||
if len(args)<3:
|
||||
show_set_help()
|
||||
else:
|
||||
set_device(args[1:])
|
||||
return
|
||||
else:
|
||||
show_help()
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
|
||||
sys.exit(0)
|
||||
|
||||
def show_set_help():
|
||||
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
|
||||
print cmd +" [led|sfp|fan]"
|
||||
print " use \""+ cmd + " led 0-4 \" to set led color"
|
||||
print " use \""+ cmd + " fan 0-100\" to set fan duty percetage"
|
||||
print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable"
|
||||
sys.exit(0)
|
||||
|
||||
def show_eeprom_help():
|
||||
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
|
||||
print " use \""+ cmd + " 1-32 \" to dump sfp# eeprom"
|
||||
sys.exit(0)
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print "[ACCTON DBG]: "+txt
|
||||
return
|
||||
|
||||
def log_os_system(cmd, show):
|
||||
logging.info('Run :'+cmd)
|
||||
status = 1
|
||||
output = ""
|
||||
status, output = commands.getstatusoutput(cmd)
|
||||
my_log (cmd +"with result:" + str(status))
|
||||
my_log ("cmd:" + cmd)
|
||||
my_log (" output:"+output)
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_inserted():
|
||||
ret, lsmod = log_os_system("lsmod| grep accton", 0)
|
||||
logging.info('mods:'+lsmod)
|
||||
if len(lsmod) ==0:
|
||||
return False
|
||||
|
||||
|
||||
kos = [
|
||||
'depmod -ae',
|
||||
'modprobe i2c_dev',
|
||||
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
|
||||
'modprobe accton_i2c_psu',
|
||||
'modprobe accton_as9716_32d_cpld',
|
||||
'modprobe accton_as9716_32d_fan',
|
||||
'modprobe accton_as9716_32d_leds',
|
||||
'modprobe accton_as9716_32d_psu',
|
||||
'modprobe optoe',
|
||||
'modprobe lm75']
|
||||
|
||||
cpld_reset_stop='i2cset -y 0 0x65 0x3 0x0'
|
||||
|
||||
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
|
||||
log_os_system(cpld_reset_stop, 1)
|
||||
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)
|
||||
print "init i2c device instance"
|
||||
status, output = log_os_system(mknod[i], 1)
|
||||
if status:
|
||||
print output
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
for i in range(0,len(sfp_map)):
|
||||
status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
|
||||
if status:
|
||||
print output
|
||||
if FORCE == 0:
|
||||
return status
|
||||
status, output =log_os_system("echo port"+str(i)+" > /sys/bus/i2c/devices/"+str(sfp_map[i])+"-0050/port_name", 1)
|
||||
if status:
|
||||
print output
|
||||
if FORCE == 0:
|
||||
return status
|
||||
return
|
||||
|
||||
def device_uninstall():
|
||||
global FORCE
|
||||
|
||||
status, output =log_os_system("ls /sys/bus/i2c/devices/0-0070", 0)
|
||||
if status==0:
|
||||
I2C_ORDER=1
|
||||
else:
|
||||
I2C_ORDER=0
|
||||
|
||||
for i in range(0,len(sfp_map)):
|
||||
target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device"
|
||||
status, output =log_os_system("echo 0x50 > "+ target, 1)
|
||||
if status:
|
||||
print output
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
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
|
||||
|
||||
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...."
|
||||
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
|
||||
|
||||
return
|
||||
|
||||
def devices_info():
|
||||
global DEVICE_NO
|
||||
global ALL_DEVICE
|
||||
global i2c_bus, hwmon_types
|
||||
for key in DEVICE_NO:
|
||||
ALL_DEVICE[key]= {}
|
||||
for i in range(0,DEVICE_NO[key]):
|
||||
ALL_DEVICE[key][key+str(i+1)] = []
|
||||
|
||||
for key in i2c_bus:
|
||||
buses = i2c_bus[key]
|
||||
nodes = i2c_nodes[key]
|
||||
for i in range(0,len(buses)):
|
||||
for j in range(0,len(nodes)):
|
||||
if 'fan' == key:
|
||||
for k in range(0,DEVICE_NO[key]):
|
||||
node = key+str(k+1)
|
||||
path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
elif 'sfp' == key:
|
||||
for k in range(0,DEVICE_NO[key]):
|
||||
node = key+str(k+1)
|
||||
path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
else:
|
||||
node = key+str(i+1)
|
||||
path = i2c_prefix+ buses[i]+"/"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
|
||||
for key in hwmon_types:
|
||||
itypes = hwmon_types[key]
|
||||
nodes = hwmon_nodes[key]
|
||||
for i in range(0,len(itypes)):
|
||||
for j in range(0,len(nodes)):
|
||||
node = key+"_"+itypes[i]
|
||||
path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][ key+str(i+1)].append(path)
|
||||
|
||||
#show dict all in the order
|
||||
if DEBUG == True:
|
||||
for i in sorted(ALL_DEVICE.keys()):
|
||||
print(i+": ")
|
||||
for j in sorted(ALL_DEVICE[i].keys()):
|
||||
print(" "+j)
|
||||
for k in (ALL_DEVICE[i][j]):
|
||||
print(" "+" "+k)
|
||||
return
|
||||
|
||||
def show_eeprom(index):
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
#if len(ALL_DEVICE)==0:
|
||||
# devices_info()
|
||||
#node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0]
|
||||
#node = node.replace(node.split("/")[-1], 'eeprom')
|
||||
node= "/sys/bus/i2c/devices/"+str(sfp_map[int(index)])+"-0050" + "/eeprom"
|
||||
# check if got hexdump command in current environment
|
||||
ret, log = log_os_system("which hexdump", 0)
|
||||
ret, log2 = log_os_system("which busybox hexdump", 0)
|
||||
if len(log):
|
||||
hex_cmd = 'hexdump'
|
||||
elif len(log2):
|
||||
hex_cmd = ' busybox hexdump'
|
||||
else:
|
||||
log = 'Failed : no hexdump cmd!!'
|
||||
logging.info(log)
|
||||
print log
|
||||
return 1
|
||||
print "node=%s"%node
|
||||
#print node + ":"
|
||||
#ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
|
||||
ret, log = log_os_system(hex_cmd+" -C " + node, 1)
|
||||
if ret==0:
|
||||
print log
|
||||
else:
|
||||
print "**********device no found**********"
|
||||
return
|
||||
|
||||
def set_device(args):
|
||||
global DEVICE_NO
|
||||
global ALL_DEVICE
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
if len(ALL_DEVICE)==0:
|
||||
devices_info()
|
||||
|
||||
if args[0]=='led':
|
||||
if int(args[1])>4:
|
||||
show_set_help()
|
||||
return
|
||||
#print ALL_DEVICE['led']
|
||||
for i in range(0,len(ALL_DEVICE['led'])):
|
||||
for k in (ALL_DEVICE['led']['led'+str(i+1)]):
|
||||
ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
|
||||
if ret:
|
||||
return ret
|
||||
elif args[0]=='fan':
|
||||
if int(args[1])>100:
|
||||
show_set_help()
|
||||
return
|
||||
#print ALL_DEVICE['fan']
|
||||
#fan1~6 is all fine, all fan share same setting
|
||||
node = ALL_DEVICE['fan1'] ['fan11'][0]
|
||||
node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage')
|
||||
ret, log = log_os_system("cat "+ node, 1)
|
||||
if ret==0:
|
||||
print ("Previous fan duty: " + log.strip() +"%")
|
||||
ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
|
||||
if ret==0:
|
||||
print ("Current fan duty: " + args[1] +"%")
|
||||
return ret
|
||||
elif args[0]=='sfp':
|
||||
if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0:
|
||||
show_set_help()
|
||||
return
|
||||
if len(args)<2:
|
||||
show_set_help()
|
||||
return
|
||||
|
||||
if int(args[2])>1:
|
||||
show_set_help()
|
||||
return
|
||||
|
||||
#print ALL_DEVICE[args[0]]
|
||||
for i in range(0,len(ALL_DEVICE[args[0]])):
|
||||
for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]:
|
||||
if j.find('tx_disable')!= -1:
|
||||
ret, log = log_os_system("echo "+args[2]+" >"+ j, 1)
|
||||
if ret:
|
||||
return ret
|
||||
|
||||
return
|
||||
|
||||
#get digits inside a string.
|
||||
#Ex: 31 for "sfp31"
|
||||
def get_value(input):
|
||||
digit = re.findall('\d+', input)
|
||||
return int(digit[0])
|
||||
|
||||
def device_traversal():
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
if len(ALL_DEVICE)==0:
|
||||
devices_info()
|
||||
for i in sorted(ALL_DEVICE.keys()):
|
||||
print("============================================")
|
||||
print(i.upper()+": ")
|
||||
print("============================================")
|
||||
|
||||
for j in sorted(ALL_DEVICE[i].keys(), key=get_value):
|
||||
print " "+j+":",
|
||||
for k in (ALL_DEVICE[i][j]):
|
||||
ret, log = log_os_system("cat "+k, 0)
|
||||
func = k.split("/")[-1].strip()
|
||||
func = re.sub(j+'_','',func,1)
|
||||
func = re.sub(i.lower()+'_','',func,1)
|
||||
if ret==0:
|
||||
print func+"="+log+" ",
|
||||
else:
|
||||
print func+"="+"X"+" ",
|
||||
print
|
||||
print("----------------------------------------------------------------")
|
||||
|
||||
|
||||
print
|
||||
return
|
||||
|
||||
def device_exist():
|
||||
ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0)
|
||||
ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0)
|
||||
return not(ret1 or ret2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,7 +1,7 @@
|
||||
Source: sonic-accton-platform-modules
|
||||
Section: main
|
||||
Priority: extra
|
||||
Maintainer: Accton network <roy_lee@accton.com>, Accton Network <polly_hsu@accton.com>
|
||||
Maintainer: Accton network <roy_lee@accton.com>, Accton Network <polly_hsu@accton.com>, Accton Network <jostar_yang@accton.com>
|
||||
Build-Depends: debhelper (>= 9), bzip2
|
||||
Standards-Version: 3.9.3
|
||||
|
||||
@ -56,3 +56,8 @@ Description: kernel modules for platform devices such as fan, led, sfp
|
||||
Package: sonic-platform-accton-as5835-54x
|
||||
Architecture: amd64
|
||||
Description: kernel modules for platform devices such as fan, led, sfp
|
||||
|
||||
Package: sonic-platform-accton-as9716-32d
|
||||
Architecture: amd64
|
||||
Description: kernel modules for platform devices such as fan, led, sfp
|
||||
|
||||
|
@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton
|
||||
KVERSION ?= $(shell uname -r)
|
||||
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||
MOD_SRC_DIR:= $(shell pwd)
|
||||
MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x as5835-54x
|
||||
MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x as5835-54x as9716-32d
|
||||
MODULE_DIR := modules
|
||||
UTILS_DIR := utils
|
||||
SERVICE_DIR := service
|
||||
|
Loading…
Reference in New Issue
Block a user