[device]: Add a new supported device accton-as7116 (#1539)

* Upgrade SAI to v1.2.4

* Add a new supported device accton as7116

* Add maintainer info for deb
This commit is contained in:
simonJi2018 2018-04-02 19:06:00 -07:00 committed by lguohan
parent dc7c524426
commit 1c32321805
29 changed files with 5037 additions and 1 deletions

View File

@ -0,0 +1,58 @@
# name lanes alias index
Ethernet0 8 Ethernet1/1 0
Ethernet1 9 Ethernet2/1 1
Ethernet2 10 Ethernet3/1 2
Ethernet3 11 Ethernet4/1 3
Ethernet4 12 Ethernet5/1 4
Ethernet5 13 Ethernet6/1 5
Ethernet6 14 Ethernet7/1 6
Ethernet7 15 Ethernet8/1 7
Ethernet8 16 Ethernet9/1 8
Ethernet9 17 Ethernet10/1 9
Ethernet10 18 Ethernet11/1 10
Ethernet11 19 Ethernet12/1 11
Ethernet12 20 Ethernet13/1 12
Ethernet13 21 Ethernet14/1 13
Ethernet14 22 Ethernet15/1 14
Ethernet15 23 Ethernet16/1 15
Ethernet16 32 Ethernet17/1 16
Ethernet17 33 Ethernet18/1 17
Ethernet18 34 Ethernet19/1 18
Ethernet19 35 Ethernet20/1 19
Ethernet20 40 Ethernet21/1 20
Ethernet21 41 Ethernet22/1 21
Ethernet22 42 Ethernet23/1 22
Ethernet23 43 Ethernet24/1 23
Ethernet24 48 Ethernet25/1 24
Ethernet25 49 Ethernet26/1 25
Ethernet26 50 Ethernet27/1 26
Ethernet27 51 Ethernet28/1 27
Ethernet28 56 Ethernet29/1 28
Ethernet29 57 Ethernet30/1 29
Ethernet30 58 Ethernet31/1 30
Ethernet31 59 Ethernet32/1 31
Ethernet32 64 Ethernet33/1 32
Ethernet33 65 Ethernet34/1 33
Ethernet34 66 Ethernet35/1 34
Ethernet35 67 Ethernet36/1 35
Ethernet36 68 Ethernet37/1 36
Ethernet37 69 Ethernet38/1 37
Ethernet38 70 Ethernet39/1 38
Ethernet39 71 Ethernet40/1 39
Ethernet40 72 Ethernet41/1 40
Ethernet41 73 Ethernet42/1 41
Ethernet42 74 Ethernet43/1 42
Ethernet43 75 Ethernet44/1 43
Ethernet44 76 Ethernet45/1 44
Ethernet45 77 Ethernet46/1 45
Ethernet46 78 Ethernet47/1 46
Ethernet47 79 Ethernet48/1 47
Ethernet48 80 Ethernet49/1 48
Ethernet49 81 Ethernet50/1 49
Ethernet50 82 Ethernet51/1 50
Ethernet51 83 Ethernet52/1 51
Ethernet52 84,85,86,87 Ethernet53/1 52
Ethernet53 104,105,106,107 Ethernet54/1 53
Ethernet54 108,109,110,111 Ethernet55/1 54
Ethernet55 112,113,114,115 Ethernet56/1 55
Ethernet56 116,117,118,119 Ethernet57/1 56

View File

@ -0,0 +1,55 @@
# name lanes alias index
Ethernet0 8 Ethernet1/1 0
Ethernet1 9 Ethernet2/1 1
Ethernet2 10 Ethernet3/1 2
Ethernet3 11 Ethernet4/1 3
Ethernet4 12 Ethernet5/1 4
Ethernet5 13 Ethernet6/1 5
Ethernet6 14 Ethernet7/1 6
Ethernet7 15 Ethernet8/1 7
Ethernet8 16 Ethernet9/1 8
Ethernet9 17 Ethernet10/1 9
Ethernet10 18 Ethernet11/1 10
Ethernet11 19 Ethernet12/1 11
Ethernet12 20 Ethernet13/1 12
Ethernet13 21 Ethernet14/1 13
Ethernet14 22 Ethernet15/1 14
Ethernet15 23 Ethernet16/1 15
Ethernet16 32 Ethernet17/1 16
Ethernet17 33 Ethernet18/1 17
Ethernet18 34 Ethernet19/1 18
Ethernet19 35 Ethernet20/1 19
Ethernet20 40 Ethernet21/1 20
Ethernet21 41 Ethernet22/1 21
Ethernet22 42 Ethernet23/1 22
Ethernet23 43 Ethernet24/1 23
Ethernet24 48 Ethernet25/1 24
Ethernet25 49 Ethernet26/1 25
Ethernet26 50 Ethernet27/1 26
Ethernet27 51 Ethernet28/1 27
Ethernet28 56 Ethernet29/1 28
Ethernet29 57 Ethernet30/1 29
Ethernet30 58 Ethernet31/1 30
Ethernet31 59 Ethernet32/1 31
Ethernet32 64 Ethernet33/1 32
Ethernet33 65 Ethernet34/1 33
Ethernet34 66 Ethernet35/1 34
Ethernet35 67 Ethernet36/1 35
Ethernet36 68 Ethernet37/1 36
Ethernet37 69 Ethernet38/1 37
Ethernet38 70 Ethernet39/1 38
Ethernet39 71 Ethernet40/1 39
Ethernet40 72 Ethernet41/1 40
Ethernet41 73 Ethernet42/1 41
Ethernet42 74 Ethernet43/1 42
Ethernet43 75 Ethernet44/1 43
Ethernet44 76 Ethernet45/1 44
Ethernet45 77 Ethernet46/1 45
Ethernet46 78 Ethernet47/1 46
Ethernet47 79 Ethernet48/1 47
Ethernet48 80,81,82,83 Ethernet49/1 48
Ethernet49 84,85,86,87 Ethernet50/1 49
Ethernet50 104,105,106,107 Ethernet51/1 50
Ethernet51 108,109,110,111 Ethernet52/1 51
Ethernet52 112,113,114,115 Ethernet53/1 52
Ethernet53 116,117,118,119 Ethernet54/1 56

View File

@ -0,0 +1,2 @@
SAI_INIT_CONFIG_FILE=/etc/nps/tau-as7116-4806.cfg
SAI_DSH_CONFIG_FILE=/etc/nps/tau-as7116-4806.dsh

View File

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

View File

@ -0,0 +1,20 @@
#This configuration file is for customer init value feature. Please refer to mtk_cfg.h/mtk_cfg.c for detail.
#1. The lines beginning with # are comment lines. The lines beginning with number are the setting lines.
#2. There are five parameters which can be set.
# 1) the first is unit.
# 2) the second is NPS_CFG_TYPE_XXX. Refer to NPS_CFG_TYPE_T.
# 3) the 3-5 are {param0, param1, value} pairs. Refer to NPS_CFG_VALUE_T. Support HEX format.
# 4) the (unit, NPS_CFG_TYPE_XXX, param0, param1) group is the key to get the correspingding value.
# There should be no same (unit, NPS_CFG_TYPE_XXX, param0, param1) group.
#3. User must follow correct format to apply the setting. Please refer to below commentted example(#0 NPS_CFG_TYPE_L2_ADDR_MODE 0 0 1);
#4. Usage under the linux shell:
# 1) ./image-path/image-name -c cfg-path/NPS_Ari_EVB_24.cfg : mamually specify directory path if they are not in current work dirctory.
# 2) ./image-name -c NPS_Ari_EVB_24.cfg : the image and the NPS_Ari_EVB_24.cfg are in the current work directory.
#unit NPS_CFG_TYPE_XXX param0 param1 value
#---- ---------------- ------ ------ -----
0 NPS_CFG_TYPE_USE_UNIT_PORT 0 0 1
0 NPS_CFG_TYPE_LED_CFG 0 0 3
0 NPS_CFG_TYPE_USER_BUF_CTRL 0 0 1
0 NPS_CFG_TYPE_CPI_PORT_MODE 129 0 1
0 NPS_CFG_TYPE_CPI_PORT_MODE 130 0 1

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,155 @@
#!/usr/bin/env python
try:
import time
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class SfpUtil(SfpUtilBase):
"""Platform specific SfpUtill class"""
_port_start = 0
_port_end = 53
_qsfp_port_start = 48
_ports_in_block = 54
_port_to_eeprom_mapping = {}
_port_to_i2c_mapping = {
0 : 37,
1 : 38,
2 : 39,
3 : 40,
4 : 41,
5 : 42,
6 : 43,
7 : 44,
8 : 45,
9 : 46,
10 : 47,
11 : 48,
12 : 49,
13 : 50,
14 : 51,
15 : 52,
16 : 53,
17 : 54,
18 : 55,
19 : 56,
20 : 57,
21 : 58,
22 : 59,
23 : 60,
24 : 61,
25 : 62,
26 : 63,
27 : 64,
28 : 65,
29 : 66,
30 : 67,
31 : 68,
32 : 69,
33 : 70,
34 : 71,
35 : 72,
36 : 73,
37 : 74,
38 : 75,
39 : 76,
40 : 77,
41 : 78,
42 : 79,
43 : 80,
44 : 81,
45 : 82,
46 : 83,
47 : 84,
48 : 21,
49 : 22,
50 : 23,
51 : 24,
52 : 25,
53 : 26,
}
_qsfp_ports = range(_qsfp_port_start, _ports_in_block + 1)
def __init__(self):
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom'
for x in range(self._port_start, self._port_end + 1):
port_eeprom_path = eeprom_path.format(self._port_to_i2c_mapping[x])
if x == 53:
self._port_to_eeprom_mapping[56] = port_eeprom_path # ugly!!!!
else:
self._port_to_eeprom_mapping[x] = port_eeprom_path
SfpUtilBase.__init__(self)
def reset(self, port_num):
# Check for invalid port_num
if port_num < self._port_start or port_num > self._port_end:
return False
path = "/sys/bus/i2c/devices/{0}-0050/sfp_port_reset"
port_ps = path.format(self._port_to_i2c_mapping[port_num])
try:
reg_file = open(port_ps, 'w')
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
#toggle reset
reg_file.seek(0)
reg_file.write('1')
time.sleep(1)
reg_file.seek(0)
reg_file.write('0')
reg_file.close()
return True
def set_low_power_mode(self, port_nuM, lpmode):
raise NotImplementedError
def get_low_power_mode(self, port_num):
raise NotImplementedError
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self._port_start or port_num > self._port_end:
return False
path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present"
port_ps = path.format(self._port_to_i2c_mapping[port_num])
try:
reg_file = open(port_ps)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
reg_value = reg_file.readline().rstrip()
if reg_value == '1':
return True
return False
@property
def port_start(self):
return self._port_start
@property
def port_end(self):
return self._port_end
@property
def qsfp_ports(self):
return self._qsfp_ports
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping

View File

@ -5,6 +5,7 @@ $(SONIC_ONE_IMAGE)_MACHINE = nephos
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(NEPHOS_NPS_KERNEL)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9130_32X_PLATFORM_MODULE) \
$(INGRASYS_S9230_64X_PLATFORM_MODULE)
$(INGRASYS_S9230_64X_PLATFORM_MODULE) \
$(ACCTON_AS7116_54X_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)

View File

@ -1,6 +1,7 @@
include $(PLATFORM_PATH)/sdk.mk
include $(PLATFORM_PATH)/sai.mk
include $(PLATFORM_PATH)/platform-modules-ingrasys.mk
include $(PLATFORM_PATH)/platform-modules-accton.mk
include $(PLATFORM_PATH)/docker-orchagent-nephos.mk
include $(PLATFORM_PATH)/docker-syncd-nephos.mk
include $(PLATFORM_PATH)/docker-syncd-nephos-rpc.mk

View File

@ -0,0 +1,16 @@
Copyright (C) 2016 Microsoft, Inc
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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@ -0,0 +1 @@
platform drivers of Accton products for the SONiC project

View File

@ -0,0 +1,2 @@
obj-m := x86-64-accton-as7116-54x-cpld.o x86-64-accton-as7116-54x-fan.o \
x86-64-accton-as7116-54x-led.o x86-64-accton-as7116-54x-psu.o x86-64-accton-as7116-54x-sfp.o

View File

@ -0,0 +1,242 @@
/*
* A hwmon driver for the as7116_54x_cpld
*
* Copyright (C) 2017 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/i2c.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/dmi.h>
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
/* Addresses scanned for as7116_54x_cpld
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
static ssize_t show_cpld_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0x1);
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
}
return sprintf(buf, "%d\n", val);
}
static struct device_attribute ver = __ATTR(version, 0600, show_cpld_version, NULL);
static void as7116_54x_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 as7116_54x_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 int as7116_54x_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr);
status = -EIO;
goto exit;
}
status = sysfs_create_file(&client->dev.kobj, &ver.attr);
if (status) {
goto exit;
}
dev_info(&client->dev, "chip found\n");
as7116_54x_cpld_add_client(client);
return 0;
exit:
return status;
}
static int as7116_54x_cpld_remove(struct i2c_client *client)
{
sysfs_remove_file(&client->dev.kobj, &ver.attr);
as7116_54x_cpld_remove_client(client);
return 0;
}
enum cpld_chips
{
as7116_54x_cpld1,
as7116_54x_cpld2,
as7116_54x_cpld3
};
static const struct i2c_device_id as7116_54x_cpld_id[] = {
{ "as7116_54x_cpld1", as7116_54x_cpld1 },
{ "as7116_54x_cpld2", as7116_54x_cpld2 },
{ "as7116_54x_cpld3", as7116_54x_cpld3 },
{}
};
MODULE_DEVICE_TABLE(i2c, as7116_54x_cpld_id);
static struct i2c_driver as7116_54x_cpld_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as7116_54x_cpld",
},
.probe = as7116_54x_cpld_probe,
.remove = as7116_54x_cpld_remove,
.id_table = as7116_54x_cpld_id,
.address_list = normal_i2c,
};
int as7116_54x_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 = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as7116_54x_cpld_read);
int as7116_54x_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 = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as7116_54x_cpld_write);
static int __init as7116_54x_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&as7116_54x_cpld_driver);
}
static void __exit as7116_54x_cpld_exit(void)
{
i2c_del_driver(&as7116_54x_cpld_driver);
}
static struct dmi_system_id as7116_54x_dmi_table[] = {
{
.ident = "Accton AS7716",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Accton"),
DMI_MATCH(DMI_PRODUCT_NAME, "AS7116"),
},
}
};
int platform_accton_as7116_54x(void)
{
//return dmi_check_system(as7116_54x_dmi_table);
return 1;
}
EXPORT_SYMBOL(platform_accton_as7116_54x);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as7116_54x driver");
MODULE_LICENSE("GPL");
module_init(as7116_54x_cpld_init);
module_exit(as7116_54x_cpld_exit);

View File

@ -0,0 +1,494 @@
/*
* A hwmon driver for the Accton as7716 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>
#define DRVNAME "as7116_54x_fan"
static struct as7116_54x_fan_data *as7116_54x_fan_update_device(struct device *dev);
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
/* fan related data, the index should match sysfs_fan_attributes
*/
static const u8 fan_reg[] = {
0x02, /* fan 1-6 present status */
0x03, /* fan 1-6 direction(0:F2B 1:B2F) */
0x06, /* fan PWM(for all fan) */
0x04, /* front fan fault */
0x05, /* rear fan fault */
0x07, /* front fan 1 speed(rpm) */
0x08, /* front fan 2 speed(rpm) */
0x09, /* front fan 3 speed(rpm) */
0x0A, /* front fan 4 speed(rpm) */
0x0B, /* front fan 5 speed(rpm) */
0x0C, /* rear fan 1 speed(rpm) */
0x0D, /* rear fan 2 speed(rpm) */
0x0E, /* rear fan 3 speed(rpm) */
0x0f, /* rear fan 4 speed(rpm) */
0x10, /* rear fan 5 speed(rpm) */
};
/* Each client has this additional data */
struct as7116_54x_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 */
};
enum fan_id {
FAN1_ID,
FAN2_ID,
FAN3_ID,
FAN4_ID,
FAN5_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 */
FAN_FRONT_FAULT_REG,
FAN_REAR_FAULT_REG,
FAN1_FRONT_SPEED_RPM,
FAN2_FRONT_SPEED_RPM,
FAN3_FRONT_SPEED_RPM,
FAN4_FRONT_SPEED_RPM,
FAN5_FRONT_SPEED_RPM,
FAN1_REAR_SPEED_RPM,
FAN2_REAR_SPEED_RPM,
FAN3_REAR_SPEED_RPM,
FAN4_REAR_SPEED_RPM,
FAN5_REAR_SPEED_RPM,
FAN1_DIRECTION,
FAN2_DIRECTION,
FAN3_DIRECTION,
FAN4_DIRECTION,
FAN5_DIRECTION,
FAN1_PRESENT,
FAN2_PRESENT,
FAN3_PRESENT,
FAN4_PRESENT,
FAN5_PRESENT,
FAN1_FRONT_FAULT,
FAN2_FRONT_FAULT,
FAN3_FRONT_FAULT,
FAN4_FRONT_FAULT,
FAN5_FRONT_FAULT,
FAN1_REAR_FAULT,
FAN2_REAR_FAULT,
FAN3_REAR_FAULT,
FAN4_REAR_FAULT,
FAN5_REAR_FAULT
};
/* Define attributes
*/
#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_front_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_FAULT);\
static SENSOR_DEVICE_ATTR(fan##index##_rear_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_FAULT)
#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_front_fault.dev_attr.attr,\
&sensor_dev_attr_fan##index##_rear_fault.dev_attr.attr
#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION)
#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr
#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE)
#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr
#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT)
#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr
#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index) \
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)
#define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \
&sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr
/* 6 fan fault attributes in this platform */
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1);
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2);
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3);
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4);
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5);
/* 6 fan speed(rpm) attributes in this platform */
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1);
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2);
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3);
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4);
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5);
/* 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);
/* 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);
/* 1 fan duty cycle attribute in this platform */
DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR();
static struct attribute *as7116_54x_fan_attributes[] = {
/* fan related attributes */
DECLARE_FAN_FAULT_ATTR(1),
DECLARE_FAN_FAULT_ATTR(2),
DECLARE_FAN_FAULT_ATTR(3),
DECLARE_FAN_FAULT_ATTR(4),
DECLARE_FAN_FAULT_ATTR(5),
DECLARE_FAN_SPEED_RPM_ATTR(1),
DECLARE_FAN_SPEED_RPM_ATTR(2),
DECLARE_FAN_SPEED_RPM_ATTR(3),
DECLARE_FAN_SPEED_RPM_ATTR(4),
DECLARE_FAN_SPEED_RPM_ATTR(5),
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_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_DUTY_CYCLE_ATTR(),
NULL
};
#define FAN_DUTY_CYCLE_REG_MASK 0x1F
#define FAN_MIN_DUTY_CYCLE 20
#define FAN_MAX_DUTY_CYCLE 100
#define FAN_REG_VAL_TO_SPEED_RPM_STEP 150
static int as7116_54x_fan_read_value(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int as7116_54x_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)
{
return (reg_val & FAN_DUTY_CYCLE_REG_MASK) * 5;
}
static u8 duty_cycle_to_reg_val(u8 duty_cycle)
{
return (duty_cycle / 5);
}
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)
{
return !!(reg_val & (1 << id));
}
static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id)
{
return !(reg_val & (1 << id));
}
static u8 is_fan_fault(u8 reg_val, enum fan_id id)
{
return !!(reg_val & (1 << id));
}
#if 0
static u8 is_fan_fault(struct as7116_54x_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;
}
#endif
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 < FAN_MIN_DUTY_CYCLE) {
value = FAN_MIN_DUTY_CYCLE;
}
if (value > FAN_MAX_DUTY_CYCLE) {
value = FAN_MAX_DUTY_CYCLE;
}
as7116_54x_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value));
return count;
}
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 as7116_54x_fan_data *data = as7116_54x_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 FAN1_REAR_SPEED_RPM:
case FAN2_REAR_SPEED_RPM:
case FAN3_REAR_SPEED_RPM:
case FAN4_REAR_SPEED_RPM:
case FAN5_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:
ret = sprintf(buf, "%d\n",
reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG],
attr->index - FAN1_PRESENT));
break;
case FAN1_FRONT_FAULT:
case FAN2_FRONT_FAULT:
case FAN3_FRONT_FAULT:
case FAN4_FRONT_FAULT:
case FAN5_FRONT_FAULT:
ret = sprintf(buf, "%d\n",
is_fan_fault(data->reg_val[FAN_FRONT_FAULT_REG],
attr->index - FAN1_FRONT_FAULT));
break;
case FAN1_REAR_FAULT:
case FAN2_REAR_FAULT:
case FAN3_REAR_FAULT:
case FAN4_REAR_FAULT:
case FAN5_REAR_FAULT:
ret = sprintf(buf, "%d\n",
is_fan_fault(data->reg_val[FAN_REAR_FAULT_REG],
attr->index - FAN1_REAR_FAULT));
break;
case FAN1_DIRECTION:
case FAN2_DIRECTION:
case FAN3_DIRECTION:
case FAN4_DIRECTION:
case FAN5_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 as7116_54x_fan_group = {
.attrs = as7116_54x_fan_attributes,
};
static struct as7116_54x_fan_data *as7116_54x_fan_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct as7116_54x_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 as7116_54x_fan update\n");
data->valid = 0;
/* Update fan data
*/
for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) {
int status = as7116_54x_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 as7116_54x_fan_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as7116_54x_fan_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as7116_54x_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, &as7116_54x_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, &as7116_54x_fan_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as7116_54x_fan_remove(struct i2c_client *client)
{
struct as7116_54x_fan_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as7116_54x_fan_group);
return 0;
}
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x66, I2C_CLIENT_END };
static const struct i2c_device_id as7116_54x_fan_id[] = {
{ "as7116_54x_fan", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, as7116_54x_fan_id);
static struct i2c_driver as7116_54x_fan_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DRVNAME,
},
.probe = as7116_54x_fan_probe,
.remove = as7116_54x_fan_remove,
.id_table = as7116_54x_fan_id,
.address_list = normal_i2c,
};
static int __init as7116_54x_fan_init(void)
{
#if 0
extern int platform_accton_as7116_54x(void);
if (!platform_accton_as7116_54x()) {
return -ENODEV;
}
#endif
return i2c_add_driver(&as7116_54x_fan_driver);
}
static void __exit as7116_54x_fan_exit(void)
{
i2c_del_driver(&as7116_54x_fan_driver);
}
module_init(as7116_54x_fan_init);
module_exit(as7116_54x_fan_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as7116_54x_fan driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,448 @@
/*
* A LED driver for the accton_as7116_54x_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.
*/
#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>
#define DRVNAME "as7116_54x_fan"
#define DEBUG_MODE 0
#if (DEBUG_MODE == 1)
#define DEBUG_PRINT(fmt, args...) \
printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args)
#else
#define DEBUG_PRINT(fmt, args...)
#endif
extern int as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as7116_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
struct as7116_54x_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]; /* LOC/DIAG LED */
};
static struct as7116_54x_led_data *ledctl = NULL;
/* LED related data
*/
#define LED_CNTRLER_I2C_ADDRESS (0x60)
#define LED_TYPE_DIAG_REG_MASK (0x0C)
#define LED_MODE_DIAG_GREEN_VALUE (0x08)
#define LED_MODE_DIAG_AMBER_VALUE (0x04)
#define LED_MODE_DIAG_YELLOW_VALUE (0x00)
#define LED_MODE_DIAG_OFF_VALUE (0x0C)
#define LED_TYPE_FAN_REG_MASK (0x03)
#define LED_MODE_FAN_GREEN_VALUE (0x02)
#define LED_MODE_FAN_AMBER_VALUE (0x01)
#define LED_MODE_FAN_OFF_VALUE (0x03)
#define LED_MODE_FAN_AUTO_VALUE (0x00)
#define LED_TYPE_PSU1_REG_MASK (0x03)
#define LED_MODE_PSU1_GREEN_VALUE (0x02)
#define LED_MODE_PSU1_AMBER_VALUE (0x01)
#define LED_MODE_PSU1_OFF_VALUE (0x03)
#define LED_MODE_PSU1_AUTO_VALUE (0x00)
#define LED_TYPE_PSU2_REG_MASK (0x0C)
#define LED_MODE_PSU2_GREEN_VALUE (0x08)
#define LED_MODE_PSU2_AMBER_VALUE (0x04)
#define LED_MODE_PSU2_OFF_VALUE (0x0C)
#define LED_MODE_PSU2_AUTO_VALUE (0x00)
#define LED_TYPE_LOC_REG_MASK (0x30)
#define LED_MODE_LOC_AMBER_VALUE (0x00)
#define LED_MODE_LOC_AMBER_BLINKING_VALUE1 (0x20)
#define LED_MODE_LOC_AMBER_BLINKING_VALUE2 (0x30)
#define LED_MODE_LOC_OFF_VALUE (0x10)
static const u8 led_reg[] = {
0x0A, /* LOC/DIAG/FAN LED */
0x0B, /* PSU1/PSU2 LED */
};
enum led_type {
LED_TYPE_DIAG,
LED_TYPE_LOC,
LED_TYPE_FAN,
LED_TYPE_PSU1,
LED_TYPE_PSU2
};
enum led_light_mode {
LED_MODE_OFF = 0,
LED_MODE_GREEN,
LED_MODE_GREEN_BLINK,
LED_MODE_AMBER,
LED_MODE_AMBER_BLINK,
LED_MODE_YELLOW,
LED_MODE_YELLOW_BLINK,
LED_MODE_BLUE,
LED_MODE_BLUE_BLINK,
LED_MODE_AUTO,
LED_MODE_UNKNOWN
};
struct led_type_mode {
enum led_type type;
enum led_light_mode mode;
int type_mask;
int mode_value;
};
static struct led_type_mode led_type_mode_data[] = {
{LED_TYPE_FAN, LED_MODE_OFF, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_OFF_VALUE},
{LED_TYPE_FAN, LED_MODE_GREEN, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_GREEN_VALUE},
{LED_TYPE_FAN, LED_MODE_AMBER, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AMBER_VALUE},
{LED_TYPE_FAN, LED_MODE_AUTO, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AUTO_VALUE},
{LED_TYPE_PSU1, LED_MODE_OFF, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_OFF_VALUE},
{LED_TYPE_PSU1, LED_MODE_GREEN, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_GREEN_VALUE},
{LED_TYPE_PSU1, LED_MODE_AMBER, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AMBER_VALUE},
{LED_TYPE_PSU1, LED_MODE_AUTO, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AUTO_VALUE},
{LED_TYPE_PSU2, LED_MODE_OFF, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_OFF_VALUE},
{LED_TYPE_PSU2, LED_MODE_GREEN, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_GREEN_VALUE},
{LED_TYPE_PSU2, LED_MODE_AMBER, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AMBER_VALUE},
{LED_TYPE_PSU2, LED_MODE_AUTO, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AUTO_VALUE},
{LED_TYPE_DIAG, LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE},
{LED_TYPE_DIAG, LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE},
{LED_TYPE_DIAG, LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE},
{LED_TYPE_DIAG, LED_MODE_YELLOW, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_YELLOW_VALUE},
{LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE},
{LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE},
{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINKING_VALUE1},
{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINKING_VALUE2}
};
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].type_mask & reg_val) ==
led_type_mode_data[i].mode_value) {
return led_type_mode_data[i].mode;
}
}
return LED_MODE_UNKNOWN;
}
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++) {
int type_mask, mode_value;
if (type != led_type_mode_data[i].type)
continue;
if (mode != led_type_mode_data[i].mode)
continue;
type_mask = led_type_mode_data[i].type_mask;
mode_value = led_type_mode_data[i].mode_value;
reg_val = (reg_val & ~type_mask) | mode_value;
}
return reg_val;
}
static int as7116_54x_led_read_value(u8 reg)
{
return as7116_54x_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg);
}
static int as7116_54x_led_write_value(u8 reg, u8 value)
{
return as7116_54x_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value);
}
static void as7116_54x_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_as7116_54x_led update\n");
ledctl->valid = 0;
/* Update LED data
*/
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
int status = as7116_54x_led_read_value(led_reg[i]);
if (status < 0) {
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status);
goto exit;
}
else {
ledctl->reg_val[i] = status;
}
}
ledctl->last_updated = jiffies;
ledctl->valid = 1;
}
exit:
mutex_unlock(&ledctl->update_lock);
}
static void as7116_54x_led_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode,
u8 reg, enum led_type type)
{
int reg_val;
mutex_lock(&ledctl->update_lock);
reg_val = as7116_54x_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);
as7116_54x_led_write_value(reg, reg_val);
/* to prevent the slow-update issue */
ledctl->valid = 0;
exit:
mutex_unlock(&ledctl->update_lock);
}
static void as7116_54x_led_diag_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG);
}
static enum led_brightness as7116_54x_led_diag_get(struct led_classdev *cdev)
{
as7116_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
}
static void as7116_54x_led_loc_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC);
}
static enum led_brightness as7116_54x_led_loc_get(struct led_classdev *cdev)
{
as7116_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]);
}
static void as7116_54x_led_fan_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN);
}
static enum led_brightness as7116_54x_led_fan_get(struct led_classdev *cdev)
{
as7116_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
}
static void as7116_54x_led_psu1_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
as7116_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1);
}
static enum led_brightness as7116_54x_led_psu1_get(struct led_classdev *cdev)
{
as7116_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]);
}
static void as7116_54x_led_psu2_set(struct led_classdev *led_cdev,
enum led_brightness led_light_mode)
{
as7116_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2);
}
static enum led_brightness as7116_54x_led_psu2_get(struct led_classdev *cdev)
{
as7116_54x_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
}
static struct led_classdev as7116_54x_leds[] = {
[LED_TYPE_DIAG] = {
.name = "as7116_54x_led::diag",
.default_trigger = "unused",
.brightness_set = as7116_54x_led_diag_set,
.brightness_get = as7116_54x_led_diag_get,
.max_brightness = LED_MODE_YELLOW,
},
[LED_TYPE_LOC] = {
.name = "as7116_54x_led::loc",
.default_trigger = "unused",
.brightness_set = as7116_54x_led_loc_set,
.brightness_get = as7116_54x_led_loc_get,
.max_brightness = LED_MODE_AMBER_BLINK,
},
[LED_TYPE_FAN] = {
.name = "as7116_54x_led::fan",
.default_trigger = "unused",
.brightness_set = as7116_54x_led_fan_set,
.brightness_get = as7116_54x_led_fan_get,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU1] = {
.name = "as7116_54x_led::psu1",
.default_trigger = "unused",
.brightness_set = as7116_54x_led_psu1_set,
.brightness_get = as7116_54x_led_psu1_get,
.max_brightness = LED_MODE_AUTO,
},
[LED_TYPE_PSU2] = {
.name = "as7116_54x_led::psu2",
.default_trigger = "unused",
.brightness_set = as7116_54x_led_psu2_set,
.brightness_get = as7116_54x_led_psu2_get,
.max_brightness = LED_MODE_AUTO,
},
};
static int as7116_54x_led_probe(struct platform_device *pdev)
{
int ret, i;
for (i = 0; i < ARRAY_SIZE(as7116_54x_leds); i++) {
ret = led_classdev_register(&pdev->dev, &as7116_54x_leds[i]);
if (ret < 0) {
break;
}
}
/* Check if all LEDs were successfully registered */
if (i != ARRAY_SIZE(as7116_54x_leds)){
int j;
/* only unregister the LEDs that were successfully registered */
for (j = 0; j < i; j++) {
led_classdev_unregister(&as7116_54x_leds[i]);
}
}
return ret;
}
static int as7116_54x_led_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(as7116_54x_leds); i++) {
led_classdev_unregister(&as7116_54x_leds[i]);
}
return 0;
}
static struct platform_driver as7116_54x_led_driver = {
.probe = as7116_54x_led_probe,
.remove = as7116_54x_led_remove,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init as7116_54x_led_init(void)
{
int ret;
#if 0
extern int platform_accton_as7116_54x(void);
if (!platform_accton_as7116_54x()) {
return -ENODEV;
}
#endif
ret = platform_driver_register(&as7116_54x_led_driver);
if (ret < 0) {
goto exit;
}
ledctl = kzalloc(sizeof(struct as7116_54x_led_data), GFP_KERNEL);
if (!ledctl) {
ret = -ENOMEM;
goto exit_driver;
}
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);
goto exit_free;
}
return 0;
exit_free:
kfree(ledctl);
exit_driver:
platform_driver_unregister(&as7116_54x_led_driver);
exit:
return ret;
}
static void __exit as7116_54x_led_exit(void)
{
platform_device_unregister(ledctl->pdev);
platform_driver_unregister(&as7116_54x_led_driver);
kfree(ledctl);
}
module_init(as7116_54x_led_init);
module_exit(as7116_54x_led_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_as7116_54x_led driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,349 @@
/*
* An hwmon driver for accton as7116_54x Power Module
*
* Copyright (C) 2014 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#define PSU_STATUS_I2C_ADDR 0x60
#define PSU_STATUS_I2C_REG_OFFSET 0x2
#define MODEL_NAME_LEN 11
#define MODEL_NAME_REG_OFFSET 0x20
#define SERIAL_NUM_LEN 18
#define SERIAL_NUM_REG_OFFSET 0x35
#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1)))
#define IS_PRESENT(id, value) (!(value & BIT(id*4)))
static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf);
static int as7116_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg);
static struct as7116_54x_psu_data *as7116_54x_psu_update_device(struct device *dev, u8 update_eeprom);
/* Addresses scanned
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Each client has this additional data
*/
struct as7116_54x_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[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */
char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/
};
enum as7116_54x_psu_sysfs_attributes {
PSU_PRESENT,
PSU_MODEL_NAME,
PSU_POWER_GOOD,
PSU_SERIAL_NUMBER
};
/* sysfs attributes for hwmon
*/
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME);
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
static SENSOR_DEVICE_ATTR(psu_serial_numer, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER);
static struct attribute *as7116_54x_psu_attributes[] = {
&sensor_dev_attr_psu_present.dev_attr.attr,
&sensor_dev_attr_psu_model_name.dev_attr.attr,
&sensor_dev_attr_psu_power_good.dev_attr.attr,
&sensor_dev_attr_psu_serial_numer.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 as7116_54x_psu_data *data = as7116_54x_psu_update_device(dev, 0);
u8 status = 0;
if (!data->valid) {
return -EIO;
}
if (attr->index == PSU_PRESENT) {
status = IS_PRESENT(data->index, data->status);
}
else { /* PSU_POWER_GOOD */
status = IS_POWER_GOOD(data->index, data->status);
}
return sprintf(buf, "%d\n", status);
}
static ssize_t show_string(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct as7116_54x_psu_data *data = as7116_54x_psu_update_device(dev, 1);
char *ptr = NULL;
if (!data->valid) {
return -EIO;
}
if (!IS_PRESENT(data->index, data->status)) {
return -ENXIO;
}
if (attr->index == PSU_MODEL_NAME) {
ptr = data->model_name;
}
else { /* PSU_SERIAL_NUBMER */
ptr = data->serial;
}
return sprintf(buf, "%s\n", ptr);
}
static const struct attribute_group as7116_54x_psu_group = {
.attrs = as7116_54x_psu_attributes,
};
static int as7116_54x_psu_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct as7116_54x_psu_data *data;
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct as7116_54x_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, &as7116_54x_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, &as7116_54x_psu_group);
exit_free:
kfree(data);
exit:
return status;
}
static int as7116_54x_psu_remove(struct i2c_client *client)
{
struct as7116_54x_psu_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &as7116_54x_psu_group);
kfree(data);
return 0;
}
enum psu_index
{
as7116_54x_psu1,
as7116_54x_psu2
};
static const struct i2c_device_id as7116_54x_psu_id[] = {
{ "as7116_54x_psu1", as7116_54x_psu1 },
{ "as7116_54x_psu2", as7116_54x_psu2 },
{}
};
MODULE_DEVICE_TABLE(i2c, as7116_54x_psu_id);
static struct i2c_driver as7116_54x_psu_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "as7116_54x_psu",
},
.probe = as7116_54x_psu_probe,
.remove = as7116_54x_psu_remove,
.id_table = as7116_54x_psu_id,
.address_list = normal_i2c,
};
static int as7116_54x_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 as7116_54x_psu_data *as7116_54x_psu_update_device(struct device *dev, u8 update_eeprom)
{
struct i2c_client *client = to_i2c_client(dev);
struct as7116_54x_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;
data->valid = 0;
dev_dbg(&client->dev, "Starting as7116_54x update\n");
/* Read psu status */
status = as7116_54x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET);
if (status < 0) {
dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status);
goto exit;
}
else {
data->status = status;
}
memset(data->model_name, 0, sizeof(data->model_name));
memset(data->serial, 0, sizeof(data->serial));
if (update_eeprom && IS_PRESENT(data->index, data->status)) {
/* Read model name */
status = as7116_54x_psu_read_block(client, MODEL_NAME_REG_OFFSET, 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);
goto exit;
}
else {
/* Skip the meaningless data byte 8*/
data->model_name[8] = data->model_name[9];
data->model_name[9] = data->model_name[10];
data->model_name[10] = '\0';
}
/* Read serial number */
status = as7116_54x_psu_read_block(client, SERIAL_NUM_REG_OFFSET, data->serial,
ARRAY_SIZE(data->serial)-1);
if (status < 0) {
data->serial[0] = '\0';
dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr);
goto exit;
}
else {
data->serial[SERIAL_NUM_LEN] = '\0';
}
}
data->last_updated = jiffies;
data->valid = 1;
}
exit:
mutex_unlock(&data->update_lock);
return data;
}
static int __init as7116_54x_psu_init(void)
{
//extern int platform_accton_as7116_54x(void);
//if (!platform_accton_as7116_54x()) {
// return -ENODEV;
//}
return i2c_add_driver(&as7116_54x_psu_driver);
}
static void __exit as7116_54x_psu_exit(void)
{
i2c_del_driver(&as7116_54x_psu_driver);
}
module_init(as7116_54x_psu_init);
module_exit(as7116_54x_psu_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as7116_54x_psu driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,13 @@
[Unit]
Description=Accton AS7116-54X Platform initialization service
Before=pmon.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/accton_as7116_util.py install
ExecStop=/usr/local/bin/accton_as7116_util.py clean
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
import sys
from setuptools import setup
os.listdir
setup(
name='as7116-54x',
version='1.0.0',
description='Module to initialize Accton AS7116-54X platforms',
packages=['as7116-54x'],
package_dir={'as7116-54x': 'as7116-54x/classes'},
)

View File

@ -0,0 +1,60 @@
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/>.
To initialize the system, run "accton_as7712_util.py install".
To clean up the drivers & devices, run "accton_as7712_util.py clean".
To dump information of sensors, run "accton_as7712_util.py show".
To dump SFP EEPROM, run "accton_as7712_util.py sff".
To set fan speed, run "accton_as7712_util.py set fan".
To enable/disable SFP emission, run "accton_as7712_util.py set sfp".
To set system LEDs' color, run "accton_as7712_util.py set led"
For more information, run "accton_as7712_util.py --help".
====================================================================
Besides applying accton_as7712_util.py to access peripherals, you can
access peripherals by sysfs nodes directly after the installation is run.
LED controls can be found under /sys/class/leds. The sysfs interface
color mappings are as follows:
Brightness:
0 => off
1 => green
2 => amber
3 => red
4 => blue
There are 5 system LEDs, loc, diag, fan, ps1, and ps2.
They are lit automatically by CPLD, but the loc and diag.
The loc led has only 1 color, blue.
The diag one has 3 colors: red, amber, and green.
Fan controls can be found in /sys/bus/i2c/devices/2-0066.
There are 12 fans inside 6 fan modules.
All fans share 1 duty setting, ranged from 0~100.
Three temperature sensors are controlled by the lm75 kernel modules.
They should already be visible under /sys/bus/i2c/drivers/lm75/.
Two power supplies are controlled by the CPLD.
Here provide their status under
/sys/bus/i2c/devices/10-0050 and /sys/bus/i2c/devices/11-0053.
There are 32 QSFP+ modules are equipped.
Apply "accton_as7712_util.py show" to get their status.
Apply "accton_as7712_util.py set sfp" to turn on/off light transmission.
Apply "accton_as7712_util.py sff" to dump EEPROM information.
Before operating on that QSFP+, please make sure it is well plugged.
Otherwise, operation is going to fail.

View File

@ -0,0 +1,518 @@
#!/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 = 'as7116_54x'
version = '0.1.0'
verbose = False
DEBUG = False
args = []
ALL_DEVICE = {}
DEVICE_NO = {'led':5, 'fan':1, 'thermal':3, 'psu':2, 'sfp':54}
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-54 {0|1}\" to set sfp# tx_disable"
sys.exit(0)
def show_eeprom_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom"
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print "[ROY]"+txt
return
def log_os_system(cmd, show):
logging.info('Run :'+cmd)
status, output = commands.getstatusoutput(cmd)
my_log (cmd +"with result:" + str(status))
my_log (" output:"+output)
if status:
logging.info('Failed :'+cmd)
if show:
print('Failed :'+cmd)
return status, output
def driver_check():
ret, lsmod = log_os_system("lsmod| grep accton", 0)
logging.info('mods:'+lsmod)
if len(lsmod) ==0:
return False
return True
kos = [
'depmod',
'modprobe i2c_dev',
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
'modprobe x86-64-accton-as7116-54x-cpld' ,
'modprobe x86-64-accton-as7116-54x-fan' ,
'modprobe x86-64-accton-as7116-54x-psu' ,
'modprobe x86-64-accton-as7116-54x-sfp' ,
'modprobe x86-64-accton-as7116-54x-led' ]
def driver_install():
global FORCE
for i in range(0,len(kos)):
status, output = log_os_system(kos[i], 1)
if status:
if FORCE == 0:
return status
return 0
def driver_uninstall():
global FORCE
for i in range(0,len(kos)):
rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
rm = rm.replace("insmod", "rmmod")
status, output = log_os_system(rm, 1)
if status:
if FORCE == 0:
return status
return 0
led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::'
hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']}
hwmon_nodes = {'led': ['brightness'] }
hwmon_prefix ={'led': led_prefix}
i2c_prefix = '/sys/bus/i2c/devices/'
i2c_bus = {'fan': ['1-0063'] ,
'thermal': ['17-004b','19-0049', '20-004a'] ,
'psu': ['10-0050','11-0058'],
'sfp': ['-0050']}
i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] ,
'thermal': ['hwmon/hwmon*/temp1_input'] ,
'psu': ['psu_present ', 'psu_power_good'] ,
'sfp': ['sfp_is_present ', 'sfp_tx_disable_all']}
sfp_map = [37,38,39,40,
41,42,43,44,45,46,47,48,49,50,
51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,69,70,
71,72,73,74,75,76,77,78,79,80,
81,82,83,84,
21,22,23,24,25,26]
mknod =[
'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9545 0x71 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo as7116_54x_fan 0x63 > /sys/bus/i2c/devices/i2c-1/new_device',
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-17/new_device',
'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-19/new_device',
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-20/new_device',
'echo as7116_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-2/new_device',
'echo as7116_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-2/new_device',
'echo as7116_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-2/new_device',
'echo as7116_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-10/new_device',
'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-10/new_device',
'echo as7116_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-11/new_device',
'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-11/new_device',
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-2/new_device',
'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-29/new_device',
'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-30/new_device',
'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-31/new_device',
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-32/new_device',
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-33/new_device',
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-34/new_device',
'echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-0/new_device']
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(1)
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 as7116_54x_sfp"+str(i+1)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 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/1-0077", 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_check() == False:
return False
if not device_exist():
return False
return True
def do_install():
print "Checking system...."
if driver_check() == False:
print "No driver, installing...."
status = driver_install()
if status:
if FORCE == 0:
return status
else:
print PROJECT_NAME.upper()+" drivers detected...."
if not device_exist():
print "No device, installing...."
status = device_install()
if status:
if FORCE == 0:
return status
else:
print PROJECT_NAME.upper()+" devices detected...."
return
def do_uninstall():
print "Checking system...."
if not device_exist():
print PROJECT_NAME.upper() +" has no device installed...."
else:
print "Removing device...."
status = device_uninstall()
if status:
if FORCE == 0:
return status
if driver_check()== 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], 'sfp_eeprom')
# check if got hexdump command in current environment
ret, log = log_os_system("which hexdump", 0)
ret, log2 = log_os_system("which busybox hexdump", 0)
if len(log):
hex_cmd = 'hexdump'
elif len(log2):
hex_cmd = ' busybox hexdump'
else:
log = 'Failed : no hexdump cmd!!'
logging.info(log)
print log
return 1
print node + ":"
ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
if ret==0:
print log
else:
print "**********device no found**********"
return
def set_device(args):
global DEVICE_NO
global ALL_DEVICE
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
if args[0]=='led':
if int(args[1])>4:
show_set_help()
return
#print ALL_DEVICE['led']
for i in range(0,len(ALL_DEVICE['led'])):
for k in (ALL_DEVICE['led']['led'+str(i+1)]):
ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
if ret:
return ret
elif args[0]=='fan':
if int(args[1])>100:
show_set_help()
return
#print ALL_DEVICE['fan']
#fan1~6 is all fine, all fan share same setting
node = ALL_DEVICE['fan'] ['fan1'][0]
node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage')
ret, log = log_os_system("cat "+ node, 1)
if ret==0:
print ("Previous fan duty: " + log.strip() +"%")
ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
if ret==0:
print ("Current fan duty: " + args[1] +"%")
return ret
elif args[0]=='sfp':
if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==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,6 @@
sonic-accton-platform-modules (1.0.0) unstable; urgency=low
* Add support for AS7116-54X series
-- developer <developer@nephos.com> Wed, 29 Mar 2017 11:00:00 +0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,11 @@
Source: sonic-accton-platform-modules
Section: main
Priority: extra
Maintainer: simon.ji@nephosinc.com
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
Package: sonic-platform-accton-as7116-54x
Architecture: amd64
Depends: linux-image-3.16.0-5-amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -0,0 +1,86 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
include /usr/share/dpkg/pkg-info.mk
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export INSTALL_MOD_DIR:=extra
PYTHON ?= python2
PACKAGE_PRE_NAME := sonic-platform-accton
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= as7116-54x
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service
CLASSES_DIR := classes
CONF_DIR := conf
%:
dh $@ --with systemd,python2,python3 --buildsystem=pybuild
clean:
dh_testdir
dh_testroot
dh_clean
build:
#make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
(for mod in $(MODULE_DIRS); do \
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
$(PYTHON) $${mod}/setup.py build; \
done)
binary: binary-arch binary-indep
# Nothing to do
binary-arch:
# Nothing to do
#install: build
#dh_testdir
#dh_testroot
#dh_clean -k
#dh_installdirs
binary-indep:
dh_testdir
dh_installdirs
# Custom package commands
(for mod in $(MODULE_DIRS); do \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin; \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system; \
cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
$(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
done)
# Resuming debhelper scripts
dh_testroot
dh_install
dh_installchangelogs
dh_installdocs
dh_systemd_enable
dh_installinit
dh_systemd_start
dh_link
dh_fixperms
dh_compress
dh_strip
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
.PHONY: build binary binary-arch binary-indep clean