[devices]: Add support as7726-32x platform (#2340)

This commit is contained in:
jostar-yang 2018-12-05 02:11:02 +08:00 committed by lguohan
parent 989b60059b
commit 1d655dbf2b
26 changed files with 5308 additions and 1 deletions

1
platform/broadcom/one-image.mk Normal file → Executable file
View File

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

6
platform/broadcom/platform-modules-accton.mk Normal file → Executable file
View File

@ -8,6 +8,7 @@ ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1
ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION = 1.1
export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION
@ -17,6 +18,7 @@ export ACCTON_AS7312_54X_PLATFORM_MODULE_VERSION
export ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION
export ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION
export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION
export ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION
ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton
@ -52,4 +54,8 @@ ACCTON_AS6712_32X_PLATFORM_MODULE = sonic-platform-accton-as6712-32x_$(ACCTON_AS
$(ACCTON_AS6712_32X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as6712_32x-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS6712_32X_PLATFORM_MODULE)))
ACCTON_AS7726_32X_PLATFORM_MODULE = sonic-platform-accton-as7726-32x_$(ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION)_amd64.deb
$(ACCTON_AS7726_32X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7726_32x-r0
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7726_32X_PLATFORM_MODULE)))
SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE)

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

View File

@ -0,0 +1,131 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 Accton Technology Corporation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------
# HISTORY:
# mm/dd/yyyy (A.D.)
# 11/13/2017: Polly Hsu, Create
# 1/10/2018:Jostar modify for as7716_32x
# 12/03/2018:Jostar modify for as7726_32x thermal plan
# ------------------------------------------------------------------
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 = 5
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
""" 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: ['55', '48'],
THERMAL_NUM_2_IDX: ['55', '49'],
THERMAL_NUM_3_IDX: ['55', '4a'],
THERMAL_NUM_4_IDX: ['55', '4b'],
THERMAL_NUM_5_IDX: ['54', '4c'],
}
thermal_sysfspath ={
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/55-0048/hwmon/hwmon4/temp1_input"],
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/55-0049/hwmon/hwmon5/temp1_input"],
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/55-004a/hwmon/hwmon6/temp1_input"],
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/55-004b/hwmon/hwmon7/temp1_input"],
THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/54-004c/hwmon/hwmon3/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)
if(os.path.isfile(device_path)):
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)
else:
print "No such device_path=%s"%device_path
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_1_val(self):
return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX)
def get_thermal_2_val(self):
return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX)
def get_thermal_temp(self):
return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX))
def main():
thermal = ThermalUtil()
print "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 'get_size_node_map : %d' % thermal.get_size_node_map()
# print 'get_size_path_map : %d' % thermal.get_size_path_map()
# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
# print thermal.get_thermal_to_device_path(x)
#
if __name__ == '__main__':
main()

View File

@ -0,0 +1,19 @@
ifneq ($(KERNELRELEASE),)
obj-m:= accton_as7726_32x_cpld.o accton_as7726_32x_fan.o \
accton_as7726_32x_leds.o accton_as7726_32x_psu.o ym2651y.o
else
ifeq (,$(KERNEL_SRC))
#$(error KERNEL_SRC is not defined)
KVERSION=3.16.0-6-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 .tmp_versions Module.markers Module.symvers modules.order
endif

View File

@ -0,0 +1,919 @@
/*
* 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 as7726_32x CPLD1/CPLD2/CPLD3
*
* Based on:
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
* Copyright (C) 2006
*
* Based on:
* pca954x.c from Ken Harrenstien
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
*
* Based on:
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
* and
* pca9540.c from Jean Delvare <khali@linux-fr.org>.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/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 {
as7726_32x_cpld1,
as7726_32x_cpld2,
as7726_32x_cpld3
};
struct as7726_32x_cpld_data {
enum cpld_type type;
struct device *hwmon_dev;
struct mutex update_lock;
};
static const struct i2c_device_id as7726_32x_cpld_id[] = {
{ "as7726_32x_cpld1", as7726_32x_cpld1 },
{ "as7726_32x_cpld2", as7726_32x_cpld2 },
{ "as7726_32x_cpld3", as7726_32x_cpld3 },
{ }
};
MODULE_DEVICE_TABLE(i2c, as7726_32x_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_RESET_ATTR_ID(index) MODULE_RESET_##index
//#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
enum as7726_32x_cpld1_sysfs_attributes {
CPLD_VERSION,
ACCESS,
MODULE_PRESENT_ALL,
MODULE_RXLOS_ALL,
/* transceiver attributes */
TRANSCEIVER_PRESENT_ATTR_ID(1),
TRANSCEIVER_PRESENT_ATTR_ID(2),
TRANSCEIVER_PRESENT_ATTR_ID(3),
TRANSCEIVER_PRESENT_ATTR_ID(4),
TRANSCEIVER_PRESENT_ATTR_ID(5),
TRANSCEIVER_PRESENT_ATTR_ID(6),
TRANSCEIVER_PRESENT_ATTR_ID(7),
TRANSCEIVER_PRESENT_ATTR_ID(8),
TRANSCEIVER_PRESENT_ATTR_ID(9),
TRANSCEIVER_PRESENT_ATTR_ID(10),
TRANSCEIVER_PRESENT_ATTR_ID(11),
TRANSCEIVER_PRESENT_ATTR_ID(12),
TRANSCEIVER_PRESENT_ATTR_ID(13),
TRANSCEIVER_PRESENT_ATTR_ID(14),
TRANSCEIVER_PRESENT_ATTR_ID(15),
TRANSCEIVER_PRESENT_ATTR_ID(16),
TRANSCEIVER_PRESENT_ATTR_ID(17),
TRANSCEIVER_PRESENT_ATTR_ID(18),
TRANSCEIVER_PRESENT_ATTR_ID(19),
TRANSCEIVER_PRESENT_ATTR_ID(20),
TRANSCEIVER_PRESENT_ATTR_ID(21),
TRANSCEIVER_PRESENT_ATTR_ID(22),
TRANSCEIVER_PRESENT_ATTR_ID(23),
TRANSCEIVER_PRESENT_ATTR_ID(24),
TRANSCEIVER_PRESENT_ATTR_ID(25),
TRANSCEIVER_PRESENT_ATTR_ID(26),
TRANSCEIVER_PRESENT_ATTR_ID(27),
TRANSCEIVER_PRESENT_ATTR_ID(28),
TRANSCEIVER_PRESENT_ATTR_ID(29),
TRANSCEIVER_PRESENT_ATTR_ID(30),
TRANSCEIVER_PRESENT_ATTR_ID(31),
TRANSCEIVER_PRESENT_ATTR_ID(32),
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_RESET_ATTR_ID(1),
TRANSCEIVER_RESET_ATTR_ID(2),
TRANSCEIVER_RESET_ATTR_ID(3),
TRANSCEIVER_RESET_ATTR_ID(4),
TRANSCEIVER_RESET_ATTR_ID(5),
TRANSCEIVER_RESET_ATTR_ID(6),
TRANSCEIVER_RESET_ATTR_ID(7),
TRANSCEIVER_RESET_ATTR_ID(8),
TRANSCEIVER_RESET_ATTR_ID(9),
TRANSCEIVER_RESET_ATTR_ID(10),
TRANSCEIVER_RESET_ATTR_ID(11),
TRANSCEIVER_RESET_ATTR_ID(12),
TRANSCEIVER_RESET_ATTR_ID(13),
TRANSCEIVER_RESET_ATTR_ID(14),
TRANSCEIVER_RESET_ATTR_ID(15),
TRANSCEIVER_RESET_ATTR_ID(16),
TRANSCEIVER_RESET_ATTR_ID(17),
TRANSCEIVER_RESET_ATTR_ID(18),
TRANSCEIVER_RESET_ATTR_ID(19),
TRANSCEIVER_RESET_ATTR_ID(20),
TRANSCEIVER_RESET_ATTR_ID(21),
TRANSCEIVER_RESET_ATTR_ID(22),
TRANSCEIVER_RESET_ATTR_ID(23),
TRANSCEIVER_RESET_ATTR_ID(24),
TRANSCEIVER_RESET_ATTR_ID(25),
TRANSCEIVER_RESET_ATTR_ID(26),
TRANSCEIVER_RESET_ATTR_ID(27),
TRANSCEIVER_RESET_ATTR_ID(28),
TRANSCEIVER_RESET_ATTR_ID(29),
TRANSCEIVER_RESET_ATTR_ID(30),
TRANSCEIVER_RESET_ATTR_ID(31),
TRANSCEIVER_RESET_ATTR_ID(32)
};
/* sysfs attributes for hwmon
*/
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_rxlos_all(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 set_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t show_version(struct device *dev, struct device_attribute *da,
char *buf);
static int as7726_32x_cpld_read_internal(struct i2c_client *client, u8 reg);
static int as7726_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
/* transceiver attributes */
#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index)
#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr
#define DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO|S_IWUSR, show_status, set_reset, MODULE_RESET_##index)
#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##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);
#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
static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
/* transceiver attributes */
static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL);
static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32);
DECLARE_TRANSCEIVER_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_RESET_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(6);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(7);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(8);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(9);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(10);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(11);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(12);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(13);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(14);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(15);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(16);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(17);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(18);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(19);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(20);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(21);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(22);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(23);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(24);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(25);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(26);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(27);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(28);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(29);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(30);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(31);
DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(32);
static struct attribute *as7726_32x_cpld1_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
&sensor_dev_attr_module_present_all.dev_attr.attr,
&sensor_dev_attr_module_rx_los_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(1),
DECLARE_TRANSCEIVER_PRESENT_ATTR(2),
DECLARE_TRANSCEIVER_PRESENT_ATTR(3),
DECLARE_TRANSCEIVER_PRESENT_ATTR(4),
DECLARE_TRANSCEIVER_PRESENT_ATTR(5),
DECLARE_TRANSCEIVER_PRESENT_ATTR(6),
DECLARE_TRANSCEIVER_PRESENT_ATTR(7),
DECLARE_TRANSCEIVER_PRESENT_ATTR(8),
DECLARE_TRANSCEIVER_PRESENT_ATTR(9),
DECLARE_TRANSCEIVER_PRESENT_ATTR(10),
DECLARE_TRANSCEIVER_PRESENT_ATTR(11),
DECLARE_TRANSCEIVER_PRESENT_ATTR(12),
DECLARE_TRANSCEIVER_PRESENT_ATTR(13),
DECLARE_TRANSCEIVER_PRESENT_ATTR(14),
DECLARE_TRANSCEIVER_PRESENT_ATTR(15),
DECLARE_TRANSCEIVER_PRESENT_ATTR(16),
DECLARE_TRANSCEIVER_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(1),
DECLARE_TRANSCEIVER_RESET_ATTR(2),
DECLARE_TRANSCEIVER_RESET_ATTR(3),
DECLARE_TRANSCEIVER_RESET_ATTR(4),
DECLARE_TRANSCEIVER_RESET_ATTR(5),
DECLARE_TRANSCEIVER_RESET_ATTR(6),
DECLARE_TRANSCEIVER_RESET_ATTR(7),
DECLARE_TRANSCEIVER_RESET_ATTR(8),
DECLARE_TRANSCEIVER_RESET_ATTR(9),
DECLARE_TRANSCEIVER_RESET_ATTR(10),
DECLARE_TRANSCEIVER_RESET_ATTR(11),
DECLARE_TRANSCEIVER_RESET_ATTR(12),
DECLARE_TRANSCEIVER_RESET_ATTR(13),
DECLARE_TRANSCEIVER_RESET_ATTR(14),
DECLARE_TRANSCEIVER_RESET_ATTR(15),
DECLARE_TRANSCEIVER_RESET_ATTR(16),
DECLARE_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 as7726_32x_cpld1_group = {
.attrs = as7726_32x_cpld1_attributes,
};
static struct attribute *as7726_32x_cpld2_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
NULL
};
static const struct attribute_group as7726_32x_cpld2_group = {
.attrs = as7726_32x_cpld2_attributes,
};
static struct attribute *as7726_32x_cpld3_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
NULL
};
static const struct attribute_group as7726_32x_cpld3_group = {
.attrs = as7726_32x_cpld3_attributes,
};
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int i, status;
u8 values[5] = {0};
u8 regs[] = {0x30, 0x31, 0x32, 0x33, 0x50};
struct i2c_client *client = to_i2c_client(dev);
struct as7726_32x_cpld_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
status = as7726_32x_cpld_read_internal(client, regs[i]);
if (status < 0) {
goto exit;
}
values[i] = ~(u8)status;
}
mutex_unlock(&data->update_lock);
values[4] &= 0x3;
return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x\n",
values[0], values[1], values[2], values[3], values[4]);
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int status;
u8 value=0;
u8 reg = 0x50;
struct i2c_client *client = to_i2c_client(dev);
struct as7726_32x_cpld_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
status = as7726_32x_cpld_read_internal(client, reg);
if (status < 0)
goto exit;
value = (u8)status;
value &= 0x0C;
value = value >> 2;
mutex_unlock(&data->update_lock);
/* Return values 1 -> 34 in order */
return sprintf(buf, "00 00 00 00 %.2x\n", value);
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct as7726_32x_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 = 0x30;
mask = 0x1 << (attr->index - MODULE_PRESENT_1);
break;
case MODULE_PRESENT_9 ... MODULE_PRESENT_16:
reg = 0x31;
mask = 0x1 << (attr->index - MODULE_PRESENT_9);
break;
case MODULE_PRESENT_17 ... MODULE_PRESENT_24:
reg = 0x32;
mask = 0x1 << (attr->index - MODULE_PRESENT_17);
break;
case MODULE_PRESENT_25 ... MODULE_PRESENT_32:
reg = 0x33;
mask = 0x1 << (attr->index - MODULE_PRESENT_25);
break;
case MODULE_PRESENT_33:
reg = 0x50;
mask = 0x1;
break;
case MODULE_PRESENT_34:
reg = 0x50;
mask = 0x2;
break;
case MODULE_RESET_1 ... MODULE_RESET_8:
reg = 0x4;
mask = 0x1 << (attr->index - MODULE_RESET_1);
break;
case MODULE_RESET_9 ... MODULE_RESET_16:
reg = 0x5;
mask = 0x1 << (attr->index - MODULE_RESET_9);
break;
case MODULE_RESET_17 ... MODULE_RESET_24:
reg = 0x6;
mask = 0x1 << (attr->index - MODULE_RESET_17);
break;
case MODULE_RESET_25 ... MODULE_RESET_32:
reg = 0x7;
mask = 0x1 << (attr->index - MODULE_RESET_25);
break;
case MODULE_RXLOS_33:
reg = 0x50;
mask = 0x4;
break;
case MODULE_RXLOS_34:
reg = 0x50;
mask = 0x8;
break;
case MODULE_TXDISABLE_33:
reg = 0x49;
mask = 0x1;
break;
case MODULE_TXDISABLE_34:
reg = 0x49;
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 = as7726_32x_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 as7726_32x_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 = 0x49;
mask = 0x1;
break;
case MODULE_TXDISABLE_34:
reg = 0x49;
mask = 0x2;
break;
default:
return 0;
}
/* Read current status */
mutex_lock(&data->update_lock);
status = as7726_32x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
/* Update tx_disable status */
if (disable) {
status |= mask;
}
else {
status &= ~mask;
}
status = as7726_32x_cpld_write_internal(client, reg, status);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t set_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 as7726_32x_cpld_data *data = i2c_get_clientdata(client);
long reset;
int status;
u8 reg = 0, mask = 0;
status = kstrtol(buf, 10, &reset);
if (status) {
return status;
}
switch (attr->index)
{
case MODULE_RESET_1 ... MODULE_RESET_8:
reg = 0x4;
mask = 0x1 << (attr->index - MODULE_RESET_1);
break;
case MODULE_RESET_9 ... MODULE_RESET_16:
reg = 0x5;
mask = 0x1 << (attr->index - MODULE_RESET_9);
break;
case MODULE_RESET_17 ... MODULE_RESET_24:
reg = 0x6;
mask = 0x1 << (attr->index - MODULE_RESET_17);
break;
case MODULE_RESET_25 ... MODULE_RESET_32:
reg = 0x7;
mask = 0x1 << (attr->index - MODULE_RESET_25);
break;
default:
return 0;
}
/* Read current status */
mutex_lock(&data->update_lock);
status = as7726_32x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
/* Update tx_disable status */
if (!reset) {
status |= mask;
}
else {
status &= ~mask;
}
status = as7726_32x_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 as7726_32x_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 = as7726_32x_cpld_write_internal(client, addr, val);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
static void as7726_32x_cpld_add_client(struct i2c_client *client)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
if (!node) {
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
return;
}
node->client = client;
mutex_lock(&list_lock);
list_add(&node->list, &cpld_client_list);
mutex_unlock(&list_lock);
}
static void as7726_32x_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int found = 0;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client == client) {
found = 1;
break;
}
}
if (found) {
list_del(list_node);
kfree(cpld_node);
}
mutex_unlock(&list_lock);
}
static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0x1);
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
}
return sprintf(buf, "%d\n", val);
}
/*
* I2C init/probing/exit functions
*/
static int as7726_32x_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct as7726_32x_cpld_data *data;
int ret = -ENODEV;
const struct attribute_group *group = NULL;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
goto exit;
data = kzalloc(sizeof(struct as7726_32x_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 as7726_32x_cpld1:
group = &as7726_32x_cpld1_group;
break;
case as7726_32x_cpld2:
group = &as7726_32x_cpld2_group;
break;
case as7726_32x_cpld3:
group = &as7726_32x_cpld3_group;
break;
default:
break;
}
if (group) {
ret = sysfs_create_group(&client->dev.kobj, group);
if (ret) {
goto exit_free;
}
}
as7726_32x_cpld_add_client(client);
return 0;
exit_free:
kfree(data);
exit:
return ret;
}
static int as7726_32x_cpld_remove(struct i2c_client *client)
{
struct as7726_32x_cpld_data *data = i2c_get_clientdata(client);
const struct attribute_group *group = NULL;
as7726_32x_cpld_remove_client(client);
/* Remove sysfs hooks */
switch (data->type) {
case as7726_32x_cpld1:
group = &as7726_32x_cpld1_group;
break;
case as7726_32x_cpld2:
group = &as7726_32x_cpld2_group;
break;
case as7726_32x_cpld3:
group = &as7726_32x_cpld3_group;
break;
default:
break;
}
if (group) {
sysfs_remove_group(&client->dev.kobj, group);
}
kfree(data);
return 0;
}
static int as7726_32x_cpld_read_internal(struct i2c_client *client, u8 reg)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_read_byte_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int as7726_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_write_byte_data(client, reg, value);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
int as7726_32x_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as7726_32x_cpld_read_internal(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as7726_32x_cpld_read);
int as7726_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as7726_32x_cpld_write_internal(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as7726_32x_cpld_write);
static struct i2c_driver as7726_32x_cpld_driver = {
.driver = {
.name = "as7726_32x_cpld",
.owner = THIS_MODULE,
},
.probe = as7726_32x_cpld_probe,
.remove = as7726_32x_cpld_remove,
.id_table = as7726_32x_cpld_id,
};
static int __init as7726_32x_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&as7726_32x_cpld_driver);
}
static void __exit as7726_32x_cpld_exit(void)
{
i2c_del_driver(&as7726_32x_cpld_driver);
}
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
MODULE_DESCRIPTION("Accton I2C CPLD driver");
MODULE_LICENSE("GPL");
module_init(as7726_32x_cpld_init);
module_exit(as7726_32x_cpld_exit);

View File

@ -0,0 +1,763 @@
/*
* A hwmon driver for the Accton as7726 32x 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 "as7726_32x_fan"
#define NUM_THERMAL_SENSORS (5) /* Get sum of this number of sensors.*/
#define THERMAL_SENSORS_DRIVER "lm75"
#define THERMAL_SENSORS_ADDRS {0x48, 0x49, 0x4a, 0x4b, 0x4c}
#define IN
#define OUT
static struct as7726_32x_fan_data *as7726_32x_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 as7726_32x_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 *as7726_32x_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 as7726_32x_fan_read_value(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int as7726_32x_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 as7726_32x_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;
as7726_32x_fan_write_value(client, 0x33, 0); /* Disable fan speed watch dog */
as7726_32x_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,
OUT 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 as7726_32x_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 as7726_32x_fan_data *data = as7726_32x_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 as7726_32x_fan_data *data = as7726_32x_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 as7726_32x_fan_group = {
.attrs = as7726_32x_fan_attributes,
};
static struct as7726_32x_fan_data *as7726_32x_fan_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as7726_32x_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 as7726_32x_fan update\n");
data->valid = 0;
/* Update fan data
*/
for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) {
int status = as7726_32x_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 as7726_32x_fan_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as7726_32x_fan_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as7726_32x_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, &as7726_32x_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, &as7726_32x_fan_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as7726_32x_fan_remove(struct i2c_client *client)
{
struct as7726_32x_fan_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as7726_32x_fan_group);
return 0;
}
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x66, I2C_CLIENT_END };
static const struct i2c_device_id as7726_32x_fan_id[] = {
{ "as7726_32x_fan", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, as7726_32x_fan_id);
static struct i2c_driver as7726_32x_fan_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DRVNAME,
},
.probe = as7726_32x_fan_probe,
.remove = as7726_32x_fan_remove,
.id_table = as7726_32x_fan_id,
.address_list = normal_i2c,
};
module_i2c_driver(as7726_32x_fan_driver);
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
MODULE_DESCRIPTION("as7726_32x_fan driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,438 @@
/*
* A LED driver for the accton_as7726_32x_led
*
* Copyright (C) 2014 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*#define DEBUG*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/dmi.h>
extern int as7726_32x_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as7726_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern void led_classdev_unregister(struct led_classdev *led_cdev);
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
extern void led_classdev_resume(struct led_classdev *led_cdev);
extern void led_classdev_suspend(struct led_classdev *led_cdev);
#define DRVNAME "accton_as7726_32x_led"
struct accton_as7726_32x_led_data {
struct platform_device *pdev;
struct mutex update_lock;
char valid; /* != 0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 reg_val[1]; /* only 1 register*/
};
static struct accton_as7726_32x_led_data *ledctl = NULL;
/* LED related data
*/
#define LED_CNTRLER_I2C_ADDRESS (0x60)
#define LED_TYPE_DIAG_REG_MASK (0x3)
#define LED_MODE_DIAG_GREEN_VALUE (0x02)
#define LED_MODE_DIAG_RED_VALUE (0x01)
#define LED_MODE_DIAG_AMBER_VALUE (0x00) /*It's yellow actually. Green+Red=Yellow*/
#define LED_MODE_DIAG_OFF_VALUE (0x03)
#define LED_TYPE_LOC_REG_MASK (0x80)
#define LED_MODE_LOC_ON_VALUE (0)
#define LED_MODE_LOC_OFF_VALUE (0x80)
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_LOC) | (1<<LED_TYPE_DIAG), 0x41},
};
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_BLUE, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_ON_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_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE},
{LED_TYPE_DIAG, LED_MODE_RED, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_RED_VALUE},
};
static void accton_as7726_32x_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 & (type<<1)) {
*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_as7726_32x_led_read_value(u8 reg)
{
return as7726_32x_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg);
}
static int accton_as7726_32x_led_write_value(u8 reg, u8 value)
{
return as7726_32x_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value);
}
static void accton_as7726_32x_led_update(void)
{
mutex_lock(&ledctl->update_lock);
if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
|| !ledctl->valid) {
int i;
dev_dbg(&ledctl->pdev->dev, "Starting accton_as7726_32x_led update\n");
/* Update LED data
*/
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
int status = accton_as7726_32x_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_as7726_32x_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, &reg))
{
dev_dbg(&ledctl->pdev->dev, "Not match item for %d.\n", type);
}
reg_val = accton_as7726_32x_led_read_value(reg);
if (reg_val < 0) {
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val);
goto exit;
}
reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val);
accton_as7726_32x_led_write_value(reg, reg_val);
/* to prevent the slow-update issue */
ledctl->valid = 0;
exit:
mutex_unlock(&ledctl->update_lock);
}
static void accton_as7726_32x_led_diag_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as7726_32x_led_set(led_cdev, led_light_mode, LED_TYPE_DIAG);
}
static enum led_brightness accton_as7726_32x_led_diag_get(struct led_classdev *cdev)
{
accton_as7726_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
}
static void accton_as7726_32x_led_loc_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
accton_as7726_32x_led_set(led_cdev, led_light_mode, LED_TYPE_LOC);
}
static enum led_brightness accton_as7726_32x_led_loc_get(struct led_classdev *cdev)
{
accton_as7726_32x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]);
}
static void accton_as7726_32x_led_auto_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
}
static enum led_brightness accton_as7726_32x_led_auto_get(struct led_classdev *cdev)
{
return LED_MODE_AUTO;
}
static struct led_classdev accton_as7726_32x_leds[] = {
[LED_TYPE_DIAG] = {
.name = "accton_as7726_32x_led::diag",
.default_trigger = "unused",
.brightness_set = accton_as7726_32x_led_diag_set,
.brightness_get = accton_as7726_32x_led_diag_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_RED,
},
[LED_TYPE_LOC] = {
.name = "accton_as7726_32x_led::loc",
.default_trigger = "unused",
.brightness_set = accton_as7726_32x_led_loc_set,
.brightness_get = accton_as7726_32x_led_loc_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_BLUE,
},
[LED_TYPE_FAN] = {
.name = "accton_as7726_32x_led::fan",
.default_trigger = "unused",
.brightness_set = accton_as7726_32x_led_auto_set,
.brightness_get = accton_as7726_32x_led_auto_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU1] = {
.name = "accton_as7726_32x_led::psu1",
.default_trigger = "unused",
.brightness_set = accton_as7726_32x_led_auto_set,
.brightness_get = accton_as7726_32x_led_auto_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU2] = {
.name = "accton_as7726_32x_led::psu2",
.default_trigger = "unused",
.brightness_set = accton_as7726_32x_led_auto_set,
.brightness_get = accton_as7726_32x_led_auto_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_AUTO,
},
};
static int accton_as7726_32x_led_suspend(struct platform_device *dev,
pm_message_t state)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as7726_32x_leds); i++) {
led_classdev_suspend(&accton_as7726_32x_leds[i]);
}
return 0;
}
static int accton_as7726_32x_led_resume(struct platform_device *dev)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(accton_as7726_32x_leds); i++) {
led_classdev_resume(&accton_as7726_32x_leds[i]);
}
return 0;
}
static int accton_as7726_32x_led_probe(struct platform_device *pdev)
{
int ret, i;
for (i = 0; i < ARRAY_SIZE(accton_as7726_32x_leds); i++) {
ret = led_classdev_register(&pdev->dev, &accton_as7726_32x_leds[i]);
if (ret < 0)
break;
}
/* Check if all LEDs were successfully registered */
if (i != ARRAY_SIZE(accton_as7726_32x_leds)) {
int j;
/* only unregister the LEDs that were successfully registered */
for (j = 0; j < i; j++) {
led_classdev_unregister(&accton_as7726_32x_leds[i]);
}
}
return ret;
}
static int accton_as7726_32x_led_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(accton_as7726_32x_leds); i++) {
led_classdev_unregister(&accton_as7726_32x_leds[i]);
}
return 0;
}
static struct platform_driver accton_as7726_32x_led_driver = {
.probe = accton_as7726_32x_led_probe,
.remove = accton_as7726_32x_led_remove,
.suspend = accton_as7726_32x_led_suspend,
.resume = accton_as7726_32x_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init accton_as7726_32x_led_init(void)
{
int ret;
ret = platform_driver_register(&accton_as7726_32x_led_driver);
if (ret < 0) {
goto exit;
}
ledctl = kzalloc(sizeof(struct accton_as7726_32x_led_data), GFP_KERNEL);
if (!ledctl) {
ret = -ENOMEM;
platform_driver_unregister(&accton_as7726_32x_led_driver);
goto exit;
}
mutex_init(&ledctl->update_lock);
ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(ledctl->pdev)) {
ret = PTR_ERR(ledctl->pdev);
platform_driver_unregister(&accton_as7726_32x_led_driver);
kfree(ledctl);
goto exit;
}
exit:
return ret;
}
static void __exit accton_as7726_32x_led_exit(void)
{
platform_device_unregister(ledctl->pdev);
platform_driver_unregister(&accton_as7726_32x_led_driver);
kfree(ledctl);
}
module_init(accton_as7726_32x_led_init);
module_exit(accton_as7726_32x_led_exit);
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as7726_32x_led driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,276 @@
/*
* An hwmon driver for accton as7726_32x 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>
static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf);
static int as7726_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as7726_32x_cpld_read(unsigned short cpld_addr, u8 reg);
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { 0x50, 0x53, I2C_CLIENT_END };
/* Each client has this additional data
*/
struct as7726_32x_psu_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 index; /* PSU index */
u8 status; /* Status(present/power_good) register read from CPLD */
char model_name[9]; /* Model name, read from eeprom */
};
static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *dev);
enum as7726_32x_psu_sysfs_attributes {
PSU_PRESENT,
PSU_MODEL_NAME,
PSU_POWER_GOOD
};
/* 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_model_name,NULL, PSU_MODEL_NAME);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
static struct attribute *as7726_32x_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,
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 as7726_32x_psu_data *data = as7726_32x_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_model_name(struct device *dev, struct device_attribute *da,
char *buf)
{
struct as7726_32x_psu_data *data = as7726_32x_psu_update_device(dev);
return sprintf(buf, "%s\n", data->model_name);
}
static const struct attribute_group as7726_32x_psu_group = {
.attrs = as7726_32x_psu_attributes,
};
static int as7726_32x_psu_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as7726_32x_psu_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as7726_32x_psu_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->valid = 0;
data->index = dev_id->driver_data;
mutex_init(&data->update_lock);
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &as7726_32x_psu_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: psu '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &as7726_32x_psu_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as7726_32x_psu_remove(struct i2c_client *client)
{
struct as7726_32x_psu_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as7726_32x_psu_group);
kfree(data);
return 0;
}
enum psu_index
{
as7726_32x_psu1,
as7726_32x_psu2
};
static const struct i2c_device_id as7726_32x_psu_id[] = {
{ "as7726_32x_psu1", as7726_32x_psu1 },
{ "as7726_32x_psu2", as7726_32x_psu2 },
{}
};
MODULE_DEVICE_TABLE(i2c, as7726_32x_psu_id);
static struct i2c_driver as7726_32x_psu_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as7726_32x_psu",
},
.probe = as7726_32x_psu_probe,
.remove = as7726_32x_psu_remove,
.id_table = as7726_32x_psu_id,
.address_list = normal_i2c,
};
static int as7726_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = 0;
int retry_count = 5;
while (retry_count) {
retry_count--;
result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(result < 0)) {
msleep(10);
continue;
}
if (unlikely(result != data_len)) {
result = -EIO;
msleep(10);
continue;
}
result = 0;
break;
}
return result;
}
static struct as7726_32x_psu_data *as7726_32x_psu_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as7726_32x_psu_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int status;
int power_good = 0;
dev_dbg(&client->dev, "Starting as7726_32x update\n");
/* Read psu status */
status = as7726_32x_cpld_read(0x60, 0x2);
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));
power_good = (data->status >> (3-data->index) & 0x1);
if (power_good) {
status = as7726_32x_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';
}
}
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
module_i2c_driver(as7726_32x_psu_driver);
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
MODULE_DESCRIPTION("as7726_32x_psu driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,603 @@
/*
* An hwmon driver for the 3Y Power YM-2651Y Power Module
*
* Copyright (C) 2014 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#define MAX_FAN_DUTY_CYCLE 100
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END };
/* Each client has this additional data
*/
struct ym2651y_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 capability; /* Register value */
u16 status_word; /* Register value */
u8 fan_fault; /* Register value */
u8 over_temp; /* Register value */
u16 v_out; /* Register value */
u16 i_out; /* Register value */
u16 p_out; /* Register value */
u16 temp; /* Register value */
u16 fan_speed; /* Register value */
u16 fan_duty_cycle[2]; /* Register value */
u8 fan_dir[4]; /* Register value */
u8 pmbus_revision; /* Register value */
u8 mfr_id[10]; /* Register value */
u8 mfr_model[10]; /* Register value */
u8 mfr_revsion[3]; /* Register value */
u16 mfr_vin_min; /* Register value */
u16 mfr_vin_max; /* Register value */
u16 mfr_iin_max; /* Register value */
u16 mfr_iout_max; /* Register value */
u16 mfr_pin_max; /* Register value */
u16 mfr_pout_max; /* Register value */
u16 mfr_vout_min; /* Register value */
u16 mfr_vout_max; /* Register value */
};
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_word(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
char *buf);
static struct ym2651y_data *ym2651y_update_device(struct device *dev);
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value);
enum ym2651y_sysfs_attributes {
PSU_POWER_ON = 0,
PSU_TEMP_FAULT,
PSU_POWER_GOOD,
PSU_FAN1_FAULT,
PSU_FAN_DIRECTION,
PSU_OVER_TEMP,
PSU_V_OUT,
PSU_I_OUT,
PSU_P_OUT,
PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/
PSU_TEMP1_INPUT,
PSU_FAN1_SPEED,
PSU_FAN1_DUTY_CYCLE,
PSU_PMBUS_REVISION,
PSU_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
PSU_MFR_VIN_MIN,
PSU_MFR_VIN_MAX,
PSU_MFR_VOUT_MIN,
PSU_MFR_VOUT_MAX,
PSU_MFR_IIN_MAX,
PSU_MFR_IOUT_MAX,
PSU_MFR_PIN_MAX,
PSU_MFR_POUT_MAX
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON);
static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD);
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP);
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_linear, NULL, PSU_V_OUT);
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX);
/*Duplicate nodes for lm-sensors.*/
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
static struct attribute *ym2651y_attributes[] = {
&sensor_dev_attr_psu_power_on.dev_attr.attr,
&sensor_dev_attr_psu_temp_fault.dev_attr.attr,
&sensor_dev_attr_psu_power_good.dev_attr.attr,
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
&sensor_dev_attr_psu_over_temp.dev_attr.attr,
&sensor_dev_attr_psu_v_out.dev_attr.attr,
&sensor_dev_attr_psu_i_out.dev_attr.attr,
&sensor_dev_attr_psu_p_out.dev_attr.attr,
&sensor_dev_attr_psu_temp1_input.dev_attr.attr,
&sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr,
/*Duplicate nodes for lm-sensors.*/
&sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
NULL
};
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) :
sprintf(buf, "0\n");
}
static ssize_t show_word(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u16 status = 0;
switch (attr->index) {
case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */
status = (data->status_word & 0x40) ? 0 : 1;
break;
case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */
status = (data->status_word & 0x4) >> 2;
break;
case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */
status = (data->status_word & 0x800) ? 0 : 1;
break;
}
return sprintf(buf, "%d\n", status);
}
static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
{
u16 valid_data = data & mask;
bool is_negative = valid_data >> (valid_bit - 1);
return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data;
}
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct ym2651y_data *data = i2c_get_clientdata(client);
int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1;
long speed;
int error;
error = kstrtol(buf, 10, &speed);
if (error)
return error;
if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE)
return -EINVAL;
mutex_lock(&data->update_lock);
data->fan_duty_cycle[nr] = speed;
ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u16 value = 0;
int exponent, mantissa;
int multiplier = 1000;
switch (attr->index) {
case PSU_V_OUT:
value = data->v_out;
break;
case PSU_I_OUT:
value = data->i_out;
break;
case PSU_P_OUT_UV:
multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
/*Passing through*/
case PSU_P_OUT:
value = data->p_out;
break;
case PSU_TEMP1_INPUT:
value = data->temp;
break;
case PSU_FAN1_SPEED:
value = data->fan_speed;
multiplier = 1;
break;
case PSU_FAN1_DUTY_CYCLE:
value = data->fan_duty_cycle[0];
multiplier = 1;
break;
case PSU_MFR_VIN_MIN:
value = data->mfr_vin_min;
break;
case PSU_MFR_VIN_MAX:
value = data->mfr_vin_max;
break;
case PSU_MFR_VOUT_MIN:
value = data->mfr_vout_min;
break;
case PSU_MFR_VOUT_MAX:
value = data->mfr_vout_max;
break;
case PSU_MFR_PIN_MAX:
value = data->mfr_pin_max;
break;
case PSU_MFR_POUT_MAX:
value = data->mfr_pout_max;
break;
case PSU_MFR_IOUT_MAX:
value = data->mfr_iout_max;
break;
case PSU_MFR_IIN_MAX:
value = data->mfr_iin_max;
break;
}
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
}
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
return sprintf(buf, "%d\n", data->fan_fault >> shift);
}
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
char *buf)
{
struct ym2651y_data *data = ym2651y_update_device(dev);
return sprintf(buf, "%d\n", data->over_temp >> 7);
}
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ym2651y_data *data = ym2651y_update_device(dev);
u8 *ptr = NULL;
switch (attr->index) {
case PSU_FAN_DIRECTION: /* psu_fan_dir */
ptr = data->fan_dir;
break;
case PSU_MFR_ID: /* psu_mfr_id */
ptr = data->mfr_id;
break;
case PSU_MFR_MODEL: /* psu_mfr_model */
ptr = data->mfr_model;
break;
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion;
break;
default:
return 0;
}
return sprintf(buf, "%s\n", ptr);
}
static const struct attribute_group ym2651y_group = {
.attrs = ym2651y_attributes,
};
static int ym2651y_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct ym2651y_data *data;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
dev_info(&client->dev, "chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &ym2651y_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: psu '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
exit_free:
kfree(data);
exit:
return status;
}
static int ym2651y_remove(struct i2c_client *client)
{
struct ym2651y_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
kfree(data);
return 0;
}
static const struct i2c_device_id ym2651y_id[] = {
{ "ym2651", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ym2651y_id);
static struct i2c_driver ym2651y_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "ym2651",
},
.probe = ym2651y_probe,
.remove = ym2651y_remove,
.id_table = ym2651y_id,
.address_list = normal_i2c,
};
static int ym2651y_read_byte(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int ym2651y_read_word(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_word_data(client, reg);
}
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value)
{
return i2c_smbus_write_word_data(client, reg, value);
}
static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(result < 0))
goto abort;
if (unlikely(result != data_len)) {
result = -EIO;
goto abort;
}
result = 0;
abort:
return result;
}
struct reg_data_byte {
u8 reg;
u8 *value;
};
struct reg_data_word {
u8 reg;
u16 *value;
};
static struct ym2651y_data *ym2651y_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ym2651y_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int i, status;
u8 command;
u8 fan_dir[5] = {0};
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
{0x7d, &data->over_temp},
{0x81, &data->fan_fault},
{0x98, &data->pmbus_revision}};
struct reg_data_word regs_word[] = { {0x79, &data->status_word},
{0x8b, &data->v_out},
{0x8c, &data->i_out},
{0x96, &data->p_out},
{0x8d, &data->temp},
{0x3b, &(data->fan_duty_cycle[0])},
{0x3c, &(data->fan_duty_cycle[1])},
{0x90, &data->fan_speed},
{0xa0, &data->mfr_vin_min},
{0xa1, &data->mfr_vin_max},
{0xa2, &data->mfr_iin_max},
{0xa3, &data->mfr_pin_max},
{0xa4, &data->mfr_vout_min},
{0xa5, &data->mfr_vout_max},
{0xa6, &data->mfr_iout_max},
{0xa7, &data->mfr_pout_max}};
dev_dbg(&client->dev, "Starting ym2651 update\n");
/* Read byte data */
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
status = ym2651y_read_byte(client, regs_byte[i].reg);
if (status < 0)
{
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_byte[i].reg, status);
}
else {
*(regs_byte[i].value) = status;
}
}
/* Read word data */
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
status = ym2651y_read_word(client, regs_word[i].reg);
if (status < 0)
{
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_word[i].reg, status);
}
else {
*(regs_word[i].value) = status;
}
}
/* Read fan_direction */
command = 0xC3;
status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
}
strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1);
data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0';
/* Read mfr_id */
command = 0x99;
status = ym2651y_read_block(client, command, data->mfr_id,
ARRAY_SIZE(data->mfr_id)-1);
data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0';
if (status < 0)
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
/* Read mfr_model */
command = 0x9a;
status = ym2651y_read_block(client, command, data->mfr_model,
ARRAY_SIZE(data->mfr_model)-1);
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
if (status < 0)
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
/* Read mfr_revsion */
command = 0x9b;
status = ym2651y_read_block(client, command, data->mfr_revsion,
ARRAY_SIZE(data->mfr_revsion)-1);
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
if (status < 0)
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
module_i2c_driver(ym2651y_driver);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("3Y Power YM-2651Y driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,16 @@
[Unit]
Description=Accton AS7726-32X Platform MAC hnadle service
Before=pmon.service
After=sysinit.target
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/accton_handle_idt.sh
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

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

View File

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

View File

@ -0,0 +1,18 @@
[Unit]
Description=Accton AS7726-32X Platform Monitoring service
Before=pmon.service
After=as7726-32x-platform-handle_mac.service
DefaultDependencies=no
[Service]
ExecStartPre=/usr/local/bin/accton_as7726_32x_util.py install
ExecStart=/usr/local/bin/accton_as7726_32x_monitor.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
#StandardOutput=tty
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

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

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

View File

@ -0,0 +1,345 @@
#!/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.)#
# 4/20/2018: Jostar modify for as7726_32x
# 12/03/2018:Jostar modify for as7726_32x 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 as7726_32x.fanutil import FanUtil
from as7726_32x.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_as7726_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:])

View File

@ -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.)
# 7/2/2018: Jostar create for as7326-56x
# ------------------------------------------------------------------
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_as7726_32x_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, 2] #init state=2, insert=1, remove=0
fan_status_state=[2, 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/54-0066/"
self.present = {
0: "fan1_present",
1: "fan2_present",
2: "fan3_present",
3: "fan4_present",
4: "fan5_present",
5: "fan6_present",
}
self.fault = {
0: "fan1_fault",
1: "fan2_fault",
2: "fan3_fault",
3: "fan4_fault",
4: "fan5_fault",
5: "fan6_fault",
}
"""Needs a logger and a logger level."""
# set up logging to file
logging.basicConfig(
filename=log_file,
filemode='w',
level=log_level,
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
# set up logging to console
if log_level == logging.DEBUG:
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
#sys_handler.setLevel(logging.WARNING)
sys_handler.setLevel(logging.INFO)
logging.getLogger('').addHandler(sys_handler)
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
def manage_fan(self):
FAN_STATE_REMOVE = 0
FAN_STATE_INSERT = 1
FAN_STATUS_FAULT = 1
FAN_STATUS_NORMAL = 0
global fan_state
global fan_status_state
for idx in range (0, self.fan_num):
node = self.fan_path + self.present[idx]
try:
val_file = open(node)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
# content is a string, either "0" or "1"
if content == "1":
if fan_state[idx]!=1:
fan_state[idx]=FAN_STATE_INSERT
logging.info("FAN-%d present is detected", idx+1);
else:
if fan_state[idx]!=0:
fan_state[idx]=FAN_STATE_REMOVE
logging.warning("Alarm for FAN-%d absent is detected", idx+1)
for idx in range (0, self.fan_num):
node = self.fan_path + self.fault[idx]
try:
val_file = open(node)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
# content is a string, either "0" or "1"
if content == "1":
if fan_status_state[idx]!=FAN_STATUS_FAULT:
if fan_state[idx] == FAN_STATE_INSERT:
logging.warning("Alarm for FAN-%d failed is detected", idx+1);
fan_status_state[idx]=FAN_STATUS_FAULT
else:
fan_status_state[idx]=FAN_STATUS_NORMAL
return True
def main(argv):
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.INFO
if len(sys.argv) != 1:
try:
opts, args = getopt.getopt(argv,'hdl:',['lfile='])
except getopt.GetoptError:
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
for opt, arg in opts:
if opt == '-h':
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
elif opt in ('-d', '--debug'):
log_level = logging.DEBUG
elif opt in ('-l', '--lfile'):
log_file = arg
monitor = device_monitor(log_file, log_level)
while True:
monitor.manage_fan()
time.sleep(3)
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,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.)
# 7/2/2018: Jostar create for as7326-56x
# ------------------------------------------------------------------
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_as7726_32x_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: "50-0053",
1: "49-0050",
}
"""Needs a logger and a logger level."""
# set up logging to file
logging.basicConfig(
filename=log_file,
filemode='w',
level=log_level,
format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
# set up logging to console
if log_level == logging.DEBUG:
console = logging.StreamHandler()
console.setLevel(log_level)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
sys_handler = logging.handlers.SysLogHandler(address = '/dev/log')
#sys_handler.setLevel(logging.WARNING)
sys_handler.setLevel(logging.INFO)
logging.getLogger('').addHandler(sys_handler)
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
def manage_psu(self):
PSU_STATE_REMOVE = 0
PSU_STATE_INSERT = 1
PSU_STATUS_NO_POWER = 0
PSU_STATUS_POWER_GOOD = 1
PSU_STATUS_IDLE =2
global psu_state
for idx in range (0, self.psu_num):
node = self.psu_path + self.mapping[idx] + self.presence
try:
val_file = open(node)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
# content is a string, either "0" or "1"
if content == "1":
if psu_state[idx]!=1:
psu_state[idx]=PSU_STATE_INSERT
logging.info("PSU-%d present is detected", idx+1);
#psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert, assume power is good. If no_power, next code will find it.
else:
if psu_state[idx]!=0:
psu_state[idx]=PSU_STATE_REMOVE
logging.warning("Alarm for PSU-%d absent is detected", idx+1);
psu_status_state[idx]=PSU_STATUS_IDLE
for idx in range (0, self.psu_num):
node = self.psu_path + self.mapping[idx] + self.oper_status
try:
val_file = open(node)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = val_file.readline().rstrip()
val_file.close()
# content is a string, either "0" or "1"
if content == "0":
if psu_status_state[idx]!=PSU_STATUS_NO_POWER:
if psu_state[idx]==PSU_STATE_INSERT:
logging.warning("Alarm for PSU-%d failed is detected", idx+1);
psu_status_state[idx]=PSU_STATUS_NO_POWER
else:
if psu_state[idx]==PSU_STATE_INSERT:
if psu_status_state[idx]!=PSU_STATUS_POWER_GOOD:
logging.info("PSU-%d power_good is detected", idx+1);
psu_status_state[idx]=PSU_STATUS_POWER_GOOD
return True
def main(argv):
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.INFO
if len(sys.argv) != 1:
try:
opts, args = getopt.getopt(argv,'hdl:',['lfile='])
except getopt.GetoptError:
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
for opt, arg in opts:
if opt == '-h':
print 'Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
elif opt in ('-d', '--debug'):
log_level = logging.DEBUG
elif opt in ('-l', '--lfile'):
log_file = arg
monitor = device_monitor(log_file, log_level)
# Loop forever, doing something useful hopefully:
while True:
monitor.manage_psu()
time.sleep(3)
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,572 @@
#!/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 = 'as7726_32x'
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':54}
led_prefix ='/sys/devices/platform/as7716_32x_led/leds/accton_'+PROJECT_NAME+'_led::'
fan_prefix ='/sys/devices/platform/as7716_32x_'
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': ['fan4_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'],
}
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': ['54-004c', '55-0048','55-0049', '55-004a', '55-004b'] ,
'psu': ['49-0050','50-0053'],
'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 = [21, 22, 23, 24, 26, 25, 28, 27,
17, 18, 19, 20, 29, 30, 31, 32,
33, 34, 35, 36, 45, 46, 47, 48,
37, 38, 39, 40, 41, 42, 43, 44,
15, 16]
mknod =[
'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device',
'echo as7726_32x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-11/new_device',
'echo as7726_32x_cpld2 0x62 > /sys/bus/i2c/devices/i2c-12/new_device',
'echo as7726_32x_cpld3 0x64 > /sys/bus/i2c/devices/i2c-13/new_device',
'echo as7726_32x_fan 0x66 > /sys/bus/i2c/devices/i2c-54/new_device',
'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-54/new_device',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-55/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-55/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-55/new_device',
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-55/new_device',
# PSU-1
'echo as7726_32x_psu1 0x53 > /sys/bus/i2c/devices/i2c-50/new_device',
'echo ym2651 0x5b > /sys/bus/i2c/devices/i2c-50/new_device',
# PSU-2
'echo as7726_32x_psu2 0x50> /sys/bus/i2c/devices/i2c-49/new_device',
'echo ym2651 0x58 > /sys/bus/i2c/devices/i2c-49/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]) ==0 or int(args[1]) > DEVICE_NO['sfp']:
show_eeprom_help()
else:
show_eeprom(args[1])
return
elif arg == 'set':
if len(args)<3:
show_set_help()
else:
set_device(args[1:])
return
else:
show_help()
return 0
def show_help():
print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
sys.exit(0)
def show_set_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print cmd +" [led|sfp|fan]"
print " use \""+ cmd + " led 0-4 \" to set led color"
print " use \""+ cmd + " fan 0-100\" to set fan duty percetage"
print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable"
sys.exit(0)
def show_eeprom_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print " use \""+ cmd + " 1-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
def cpld_reset_mac():
ret, lsmod = log_os_system("i2cset -y 0 0x77 0x1", 0)
ret, lsmod = log_os_system("i2cset -y 0 0x76 0x4", 0)
ret, lsmod = log_os_system("i2cset -y 0 0x60 0x8 0x77", 0)
time.sleep(1)
ret, lsmod = log_os_system("i2cset -y 0 0x60 0x8 0xf7", 0)
return True
#'modprobe cpr_4011_4mxx',
kos = [
'depmod -ae',
'modprobe i2c_dev',
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
'modprobe ym2651y',
'modprobe accton_as7726_32x_cpld',
'modprobe accton_as7726_32x_fan',
'modprobe accton_as7726_32x_leds',
'modprobe accton_as7726_32x_psu',
'modprobe optoe']
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
#status=cpld_reset_mac()
return 0
def driver_uninstall():
global FORCE
for i in range(0,len(kos)):
rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
lst = rm.split(" ")
print "lst=%s"%lst
if len(lst) > 3:
del(lst[3])
rm = " ".join(lst)
status, output = log_os_system(rm, 1)
if status:
if FORCE == 0:
return status
return 0
def device_install():
global FORCE
for i in range(0,len(mknod)):
#for pca954x need times to built new i2c buses
if mknod[i].find('pca954') != -1:
time.sleep(2)
status, output = log_os_system(mknod[i], 1)
if status:
print output
if FORCE == 0:
return status
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')
# check if got hexdump command in current environment
ret, log = log_os_system("which hexdump", 0)
ret, log2 = log_os_system("which busybox hexdump", 0)
if len(log):
hex_cmd = 'hexdump'
elif len(log2):
hex_cmd = ' busybox hexdump'
else:
log = 'Failed : no hexdump cmd!!'
logging.info(log)
print log
return 1
print "node=%s"%node
print node + ":"
ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
if ret==0:
print log
else:
print "**********device no found**********"
return
def set_device(args):
global DEVICE_NO
global ALL_DEVICE
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
if args[0]=='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()

View File

@ -0,0 +1,19 @@
#!/bin/bash
if [ -s /usr/local/bin/done_idt_init ];then
echo "There is a done_idt_init file"
else
cat /etc/init.d/opennsl-modules-3.16.0-5-amd64|grep mac_handle.sh
if [ $? -ne 0 ];then
echo "Add idt_init.sh to opennsl-modules for TD3 MAC"
sed -i '/modprobe linux-kernel-bde/i sleep 1' /etc/init.d/opennsl-modules-3.16.0-5-amd64
sed -i '/sleep/i /usr/local/bin/idt_init.sh' /etc/init.d/opennsl-modules-3.16.0-5-amd64
sed -i '/idt_init/i echo "IDT init" ' /etc/init.d/opennsl-modules-3.16.0-5-amd64
sed -i '/IDT init/i echo 1 > /usr/local/bin/done_idt_init' /etc/init.d/opennsl-modules-3.16.0-5-amd64
fi
fi

View File

@ -0,0 +1,152 @@
#!/bin/bash
test_log=/usr/local/bin/check_idt_status.txt
modprobe i2c-i801
modprobe i2c-dev
i2cset -y 0 0x77 0x1
i2cset -y 0 0x76 0x1
i2cget -y 0 0x54 0 b > /dev/null
if [ $? -ne 0 ];then
printf "Device 8v89307(0x54) not found\n"
exit 1
fi
echo "IDT 82V89307 "
echo "idt init 1"
# Title = --- IDT 82V89307 Registers ---
#Select to Page 0
i2cset -y 0 0x54 0x2D 0x00
i2cset -y 0 0x54 0x7F 0x05
i2cset -y 0 0x54 0x7E 0x85
i2cset -y 0 0x54 0x7B 0x00
i2cset -y 0 0x54 0x7A 0x00
i2cset -y 0 0x54 0x79 0x40
i2cset -y 0 0x54 0x78 0x06
i2cset -y 0 0x54 0x73 0x40
i2cset -y 0 0x54 0x72 0x40
# OUT3:25MHz
i2cset -y 0 0x54 0x71 0x0A
i2cset -y 0 0x54 0x70 0x00
# OUT1:1pps
i2cset -y 0 0x54 0x6B 0x4E
i2cset -y 0 0x54 0x69 0x00
i2cset -y 0 0x54 0x68 0x00
i2cset -y 0 0x54 0x67 0x19
i2cset -y 0 0x54 0x66 0xAB
i2cset -y 0 0x54 0x65 0x8C
i2cset -y 0 0x54 0x64 0x00
i2cset -y 0 0x54 0x63 0x00
i2cset -y 0 0x54 0x62 0x00
i2cset -y 0 0x54 0x5F 0x00
i2cset -y 0 0x54 0x5E 0x00
i2cset -y 0 0x54 0x5D 0x00
i2cset -y 0 0x54 0x5C 0x78
i2cset -y 0 0x54 0x5B 0x02
i2cset -y 0 0x54 0x5A 0xE5
i2cset -y 0 0x54 0x59 0x88
i2cset -y 0 0x54 0x58 0x4B
i2cset -y 0 0x54 0x57 0x6C
i2cset -y 0 0x54 0x56 0x6C
# Lock to DPLL, output 625MHz
i2cset -y 0 0x54 0x55 0x80
i2cset -y 0 0x54 0x53 0x00
i2cset -y 0 0x54 0x52 0x81
i2cset -y 0 0x54 0x50 0x00
i2cset -y 0 0x54 0x4F 0x00
i2cset -y 0 0x54 0x4E 0x00
i2cset -y 0 0x54 0x4C 0xCB
i2cset -y 0 0x54 0x4A 0x00
i2cset -y 0 0x54 0x45 0x66
i2cset -y 0 0x54 0x44 0x66
i2cset -y 0 0x54 0x42 0x80
i2cset -y 0 0x54 0x41 0x03
i2cset -y 0 0x54 0x40 0x01
i2cset -y 0 0x54 0x3F 0x08
i2cset -y 0 0x54 0x3E 0x04
i2cset -y 0 0x54 0x3D 0x20
i2cset -y 0 0x54 0x3C 0x13
i2cset -y 0 0x54 0x3B 0x00
i2cset -y 0 0x54 0x3A 0x98
i2cset -y 0 0x54 0x39 0x01
i2cset -y 0 0x54 0x38 0xE6
i2cset -y 0 0x54 0x37 0x04
i2cset -y 0 0x54 0x36 0xCE
i2cset -y 0 0x54 0x35 0x7C
i2cset -y 0 0x54 0x34 0x01
i2cset -y 0 0x54 0x33 0x08
i2cset -y 0 0x54 0x32 0x08
i2cset -y 0 0x54 0x31 0x08
i2cset -y 0 0x54 0x30 0x03
i2cset -y 0 0x54 0x2F 0x23
i2cset -y 0 0x54 0x2E 0x0B
i2cset -y 0 0x54 0x2D 0x00
i2cset -y 0 0x54 0x28 0x76
i2cset -y 0 0x54 0x27 0x54
i2cset -y 0 0x54 0x25 0x00
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x23 0x06
i2cset -y 0 0x54 0x1A 0x8C
i2cset -y 0 0x54 0x19 0x8C
i2cset -y 0 0x54 0x18 0x00
i2cset -y 0 0x54 0x16 0x0D
i2cset -y 0 0x54 0x11 0x00
i2cset -y 0 0x54 0x10 0x00
i2cset -y 0 0x54 0x0E 0x3F
i2cset -y 0 0x54 0x0D 0xFF
i2cset -y 0 0x54 0x0C 0x02
i2cset -y 0 0x54 0x0B 0xA1
i2cset -y 0 0x54 0x0A 0x89
i2cset -y 0 0x54 0x09 0xA2
i2cset -y 0 0x54 0x08 0x32
i2cset -y 0 0x54 0x06 0x00
i2cset -y 0 0x54 0x05 0x00
i2cset -y 0 0x54 0x04 0x00
i2cset -y 0 0x54 0x03 0x00
i2cset -y 0 0x54 0x02 0x05
i2cset -y 0 0x54 0x01 0x33
i2cset -y 0 0x54 0x00 0x91
echo "idt init 2"
# PreDivider_Parameters
#IN1
i2cset -y 0 0x54 0x23 0x05
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x25 0x00
#IN2
i2cset -y 0 0x54 0x23 0x06
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x25 0x00
#IN3
i2cset -y 0 0x54 0x23 0x03
i2cset -y 0 0x54 0x24 0x00
i2cset -y 0 0x54 0x25 0x00
echo "idt init 3"
# Page1_Parameters
#Select to Page 1
i2cset -y 0 0x54 0x2D 0x01
i2cset -y 0 0x54 0x30 0x03
i2cset -y 0 0x54 0x31 0x08
i2cset -y 0 0x54 0x32 0x08
i2cset -y 0 0x54 0x33 0x08
i2cset -y 0 0x54 0x35 0x7C
i2cset -y 0 0x54 0x36 0xCE
i2cset -y 0 0x54 0x37 0x04
i2cset -y 0 0x54 0x38 0xE6
i2cset -y 0 0x54 0x39 0x01
i2cset -y 0 0x54 0x3A 0x98
i2cset -y 0 0x54 0x3B 0x00
i2cset -y 0 0x54 0x3C 0x13
i2cset -y 0 0x54 0x3D 0x20
#Return to Page 0
i2cset -y 0 0x54 0x2D 0x00
echo "idt init 4"
#reset the in-path mux
i2cset -y 0 0x76 0x0
i2cset -y 0 0x77 0x0

View File

@ -0,0 +1,242 @@
#!/bin/bash
test_log=/usr/local/bin/check_mac_status.txt
modprobe i2c-i801
modprobe i2c-dev
i2cset -y 0 0x77 0x1
i2cset -y 0 0x76 0x1
i2cget -y 0 0x54 0 b > /dev/null
if [ $? -ne 0 ];then
printf "Device 8v89307(0x54) not found\n"
i2cdetect -y 0
echo "Reset both MAC and PCI (write 0x6F)"
i2cset -y 0 0x60 0x8 0x6f
echo "Sleep 1s"
sleep 1
echo "Pull back MAC reset, keep PCIE reset (write 0xEF)"
i2cset -y 0 0x60 0x7 0xef
echo "Sleep 1s"
sleep 1
echo "Set to default normal state (write 0xFF)"
i2cset -y 0 0x60 0x8 0xff
echo "remove PCI device"
echo 1 > /sys/bus/pci/devices/0000:07:00.0/remove
ls /sys/bus/pci/devices/
echo "rescan PCI device"
echo 1 > /sys/bus/pci/rescan
ls /sys/bus/pci/devices/
echo "Sleep 1s"
sleep 1
lspci -n|grep 07:00.0
if [ $? -ne 0 ];then
echo "Broadcom Corporation Device is not detect">>$test_log
echo "rescan PCI again" >>$test_log
echo 1 > /sys/bus/pci/rescan
sleep 1
lspci -n|grep 07:00.0
if [ $? -ne 0 ];then
echo "Broadcom Corporation Device NG">>$test_log
echo "rescan PCI again-2" >>$test_log
echo 1 > /sys/bus/pci/rescan
sleep 1
else
echo "done mac_pci_reset_rescan"
fi
fi
exit 1
fi
echo "idt init 1"
# Title = --- IDT 82V89307 Registers ---
#Select to Page 0
i2cset -y 0 0x54 0x2D 0x00
i2cset -y 0 0x54 0x7F 0x05
i2cset -y 0 0x54 0x7E 0x85
i2cset -y 0 0x54 0x7B 0x00
i2cset -y 0 0x54 0x7A 0x00
i2cset -y 0 0x54 0x79 0x40
i2cset -y 0 0x54 0x78 0x06
i2cset -y 0 0x54 0x73 0x40
i2cset -y 0 0x54 0x72 0x40
# OUT3:25MHz
i2cset -y 0 0x54 0x71 0x0A
i2cset -y 0 0x54 0x70 0x00
# OUT1:1pps
i2cset -y 0 0x54 0x6B 0x4E
i2cset -y 0 0x54 0x69 0x00
i2cset -y 0 0x54 0x68 0x00
i2cset -y 0 0x54 0x67 0x19
i2cset -y 0 0x54 0x66 0xAB
i2cset -y 0 0x54 0x65 0x8C
i2cset -y 0 0x54 0x64 0x00
i2cset -y 0 0x54 0x63 0x00
i2cset -y 0 0x54 0x62 0x00
i2cset -y 0 0x54 0x5F 0x00
i2cset -y 0 0x54 0x5E 0x00
i2cset -y 0 0x54 0x5D 0x00
i2cset -y 0 0x54 0x5C 0x78
i2cset -y 0 0x54 0x5B 0x02
i2cset -y 0 0x54 0x5A 0xE5
i2cset -y 0 0x54 0x59 0x88
i2cset -y 0 0x54 0x58 0x4B
i2cset -y 0 0x54 0x57 0x6C
i2cset -y 0 0x54 0x56 0x6C
# Lock to DPLL, output 625MHz
i2cset -y 0 0x54 0x55 0x80
i2cset -y 0 0x54 0x53 0x00
i2cset -y 0 0x54 0x52 0x81
i2cset -y 0 0x54 0x50 0x00
i2cset -y 0 0x54 0x4F 0x00
i2cset -y 0 0x54 0x4E 0x00
i2cset -y 0 0x54 0x4C 0xCB
i2cset -y 0 0x54 0x4A 0x00
i2cset -y 0 0x54 0x45 0x66
i2cset -y 0 0x54 0x44 0x66
i2cset -y 0 0x54 0x42 0x80
i2cset -y 0 0x54 0x41 0x03
i2cset -y 0 0x54 0x40 0x01
i2cset -y 0 0x54 0x3F 0x08
i2cset -y 0 0x54 0x3E 0x04
i2cset -y 0 0x54 0x3D 0x20
i2cset -y 0 0x54 0x3C 0x13
i2cset -y 0 0x54 0x3B 0x00
i2cset -y 0 0x54 0x3A 0x98
i2cset -y 0 0x54 0x39 0x01
i2cset -y 0 0x54 0x38 0xE6
i2cset -y 0 0x54 0x37 0x04
i2cset -y 0 0x54 0x36 0xCE
i2cset -y 0 0x54 0x35 0x7C
i2cset -y 0 0x54 0x34 0x01
i2cset -y 0 0x54 0x33 0x08
i2cset -y 0 0x54 0x32 0x08
i2cset -y 0 0x54 0x31 0x08
i2cset -y 0 0x54 0x30 0x03
i2cset -y 0 0x54 0x2F 0x23
i2cset -y 0 0x54 0x2E 0x0B
i2cset -y 0 0x54 0x2D 0x00
i2cset -y 0 0x54 0x28 0x76
i2cset -y 0 0x54 0x27 0x54
i2cset -y 0 0x54 0x25 0x00
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x23 0x06
i2cset -y 0 0x54 0x1A 0x8C
i2cset -y 0 0x54 0x19 0x8C
i2cset -y 0 0x54 0x18 0x00
i2cset -y 0 0x54 0x16 0x0D
i2cset -y 0 0x54 0x11 0x00
i2cset -y 0 0x54 0x10 0x00
i2cset -y 0 0x54 0x0E 0x3F
i2cset -y 0 0x54 0x0D 0xFF
i2cset -y 0 0x54 0x0C 0x02
i2cset -y 0 0x54 0x0B 0xA1
i2cset -y 0 0x54 0x0A 0x89
i2cset -y 0 0x54 0x09 0xA2
i2cset -y 0 0x54 0x08 0x32
i2cset -y 0 0x54 0x06 0x00
i2cset -y 0 0x54 0x05 0x00
i2cset -y 0 0x54 0x04 0x00
i2cset -y 0 0x54 0x03 0x00
i2cset -y 0 0x54 0x02 0x05
i2cset -y 0 0x54 0x01 0x33
i2cset -y 0 0x54 0x00 0x91
echo "idt init 2"
# PreDivider_Parameters
#IN1
i2cset -y 0 0x54 0x23 0x05
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x25 0x00
#IN2
i2cset -y 0 0x54 0x23 0x06
i2cset -y 0 0x54 0x24 0x03
i2cset -y 0 0x54 0x25 0x00
#IN3
i2cset -y 0 0x54 0x23 0x03
i2cset -y 0 0x54 0x24 0x00
i2cset -y 0 0x54 0x25 0x00
echo "idt init 3"
# Page1_Parameters
#Select to Page 1
i2cset -y 0 0x54 0x2D 0x01
i2cset -y 0 0x54 0x30 0x03
i2cset -y 0 0x54 0x31 0x08
i2cset -y 0 0x54 0x32 0x08
i2cset -y 0 0x54 0x33 0x08
i2cset -y 0 0x54 0x35 0x7C
i2cset -y 0 0x54 0x36 0xCE
i2cset -y 0 0x54 0x37 0x04
i2cset -y 0 0x54 0x38 0xE6
i2cset -y 0 0x54 0x39 0x01
i2cset -y 0 0x54 0x3A 0x98
i2cset -y 0 0x54 0x3B 0x00
i2cset -y 0 0x54 0x3C 0x13
i2cset -y 0 0x54 0x3D 0x20
#Return to Page 0
i2cset -y 0 0x54 0x2D 0x00
echo "idt init 4"
#reset the in-path mux
i2cset -y 0 0x76 0x0
i2cset -y 0 0x77 0x0
#flip MAC reset at CPLD
echo "Work around: We need to reset MAC after set 8v89307 clock output"
echo " or it is possible to get sdk init failure sometimes"
echo "MAC reset at CPLD"
i2cset -y 0 0x77 0x1
i2cset -y 0 0x76 0x4
#i2cset -y 0 0x60 0x8 0x7f
#sleep 1
#i2cset -y 0 0x60 0x8 0xff
echo "Reset both MAC and PCI (write 0x6F)"
i2cset -y 0 0x60 0x8 0x6f
echo "Sleep 1s"
sleep 1
echo "Pull back MAC reset, keep PCIE reset (write 0xEF)"
i2cset -y 0 0x60 0x7 0xef
echo "Sleep 1s"
sleep 1
echo "Set to default normal state (write 0xFF)"
i2cset -y 0 0x60 0x8 0xff
echo "remove PCI device"
echo 1 > /sys/bus/pci/devices/0000:07:00.0/remove
ls /sys/bus/pci/devices/
echo "rescan PCI device"
echo 1 > /sys/bus/pci/rescan
ls /sys/bus/pci/devices/
echo "Sleep 1s"
sleep 1
lspci -n|grep 07:00.0
if [ $? -ne 0 ];then
echo "Broadcom Corporation Device is not detect">>$test_log
echo "rescan PCI again" >>$test_log
echo 1 > /sys/bus/pci/rescan
sleep 1
lspci -n|grep 07:00.0
if [ $? -ne 0 ];then
echo "Broadcom Corporation Device NG">>$test_log
echo "rescan PCI again-2" >>$test_log
echo 1 > /sys/bus/pci/rescan
sleep 1
else
echo "done mac_pci_reset_rescan"
fi
fi

View File

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

View File

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