[platform] Add a new supported platform, Delta-ag9032v1 (#1168)

CPU : Intel Rangeley C2538
    Swich ASIC: Broadcom Tomahawk BCM56960
    Ports : 32x100G
    Switch SKU : Delta-ag9032v1

Signed-off-by: neal <neal.tai@deltaww.com>
This commit is contained in:
nealtai 2017-11-28 06:29:22 +08:00 committed by Joe LeVeque
parent 98fbddf60f
commit 8602360ffd
29 changed files with 5219 additions and 1 deletions

View File

@ -0,0 +1,33 @@
# name lanes alias
Ethernet0 49,50,51,52 hundredGigE1/1
Ethernet4 53,54,55,56 hundredGigE1/2
Ethernet8 57,58,59,60 hundredGigE1/3
Ethernet12 61,62,63,64 hundredGigE1/4
Ethernet16 65,66,67,68 hundredGigE1/5
Ethernet20 69,70,71,72 hundredGigE1/6
Ethernet24 73,74,75,76 hundredGigE1/7
Ethernet28 77,78,79,80 hundredGigE1/8
Ethernet32 37,38,39,40 hundredGigE1/9
Ethernet36 33,34,35,36 hundredGigE1/10
Ethernet40 45,46,47,48 hundredGigE1/11
Ethernet44 41,42,43,44 hundredGigE1/12
Ethernet48 81,82,83,84 hundredGigE1/13
Ethernet52 85,86,87,88 hundredGigE1/14
Ethernet56 89,90,91,92 hundredGigE1/15
Ethernet60 93,94,95,96 hundredGigE1/16
Ethernet64 97,98,99,100 hundredGigE1/17
Ethernet68 101,102,103,104 hundredGigE1/18
Ethernet72 105,106,107,108 hundredGigE1/19
Ethernet76 109,110,111,112 hundredGigE1/20
Ethernet80 21,22,23,24 hundredGigE1/21
Ethernet84 17,18,19,20 hundredGigE1/22
Ethernet88 29,30,31,32 hundredGigE1/23
Ethernet92 25,26,27,28 hundredGigE1/24
Ethernet96 117,118,119,120 hundredGigE1/25
Ethernet100 113,114,115,116 hundredGigE1/26
Ethernet104 125,126,127,128 hundredGigE1/27
Ethernet108 121,122,123,124 hundredGigE1/28
Ethernet112 5,6,7,8 hundredGigE1/29
Ethernet116 1,2,3,4 hundredGigE1/30
Ethernet120 13,14,15,16 hundredGigE1/31
Ethernet124 9,10,11,12 hundredGigE1/32

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/etc/bcm/th-ag9032v1-32x100G.config.bcm

View File

@ -0,0 +1,10 @@
INTERVAL=10
DEVPATH=hwmon1=/sys/bus/i2c/devices
DEVNAME=hwmon1=emc2305
FCTEMPS=hwmon1/2-004d/hwmon/hwmon*/temp1_input hwmon1/7-004c/hwmon/hwmon*/temp1_input hwmon1/7-004d/hwmon/hwmon*/temp1_input hwmon1/7-004e/hwmon/hwmon*/temp1_input hwmon1/30-004f/hwmon/hwmon*/temp1_input hwmon1/40-0058/temp1_input hwmon1/41-0058/temp1_input
FCFANS=hwmon1/37-002c/fan1_input hwmon1/37-002c/fan2_input hwmon1/37-002c/fan3_input hwmon1/37-002c/fan4_input hwmon1/37-002c/fan5_input hwmon1/38-002d/fan1_input hwmon1/38-002d/fan2_input hwmon1/38-002d/fan3_input hwmon1/38-002d/fan4_input hwmon1/38-002d/fan5_input
MINTEMP=20
MAXTEMP=60
MINSTART=75
MINSTOP=22

View File

@ -0,0 +1,244 @@
#!/bin/bash
#
# Simple script implementing a temperature dependent fan speed control
# Supported Linux kernel versions: 2.6.5 and later
#
# Version 0.70
#
# Usage: fancontrol [CONFIGFILE]
#
# Dependencies:
# bash, egrep, sed, cut, sleep, readlink, lm_sensors :)
#
# Please send any questions, comments or success stories to
# marius.reiner@hdev.de
# Thanks!
#
# For configuration instructions and warnings please see fancontrol.txt, which
# can be found in the doc/ directory or at the website mentioned above.
#
#
# Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
# Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
#
# 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.
#
#
PIDFILE="/var/run/fancontrol.pid"
#DEBUG=1
MAX=255
function LoadConfig
{
local fcvcount fcv
echo "Loading configuration from $1 ..."
if [ ! -r "$1" ]
then
echo "Error: Can't read configuration file" >&2
exit 1
fi
# grep configuration from file
INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
DEVPATH=`egrep '^DEVPATH=.*$' $1 | sed -e 's/DEVPATH= *//g'`
DEVNAME=`egrep '^DEVNAME=.*$' $1 | sed -e 's/DEVNAME= *//g'`
FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
HWMON=$( echo "$DEVPATH" | sed 's/=.*$//g')
FCDEVPATH=$( echo "$DEVPATH" | sed 's/^.*=//g')
FCMINTEMP=$MINTEMP
FCMAXTEMP=$MAXTEMP
FCMINSTART=$MINSTART
FCMINSTOP=$MINSTOP
FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
# Check whether all mandatory settings are set
if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
then
echo "Some mandatory settings missing, please check your config file!" >&2
exit 1
fi
if [ "$INTERVAL" -le 0 ]
then
echo "Error in configuration file:" >&2
echo "INTERVAL must be at least 1" >&2
exit 1
fi
# write settings to arrays for easier use and print them
echo
echo "Common settings:"
temp_string=$FCTEMPS
let fcvcount=0
for fcv in $FCTEMPS
do
fcvcount=$((fcvcount+1))
AFCTEMP[$fcvcount]=$( echo "$temp_string" | cut -d" " -f $fcvcount )
AFCTEMP[$fcvcount]=$( echo "${AFCTEMP[$fcvcount]}" | sed 's/hwmon1/\/sys\/bus\/i2c\/devices/g' )
AFCTEMP_PATH[$fcvcount]=$( echo "${AFCTEMP[$fcvcount]}" | sed 's/hwmon1/\/sys\/bus\/i2c\/devices/g' )
AFCTEMP[$fcvcount]=$( cat ${AFCTEMP[$fcvcount]} )
AFCTEMP[$fcvcount]=$(( AFCTEMP[$fcvcount]/1000 ))
done
fan_string=$FCFANS
fcvcount=0
zero=0
for fcv in $FCFANS
do
fcvcount=$((fcvcount+1))
AFCFAN[$fcvcount]=$( echo "$fan_string" | cut -d" " -f $fcvcount )
AFCFAN_PATH[$fcvcount]=$( echo "${AFCFAN[$fcvcount]}" | sed 's/hwmon1/\/sys\/bus\/i2c\/devices/g' )
AFCFAN_TARGET[$fcvcount]=$( echo "${AFCFAN_PATH[$fcvcount]}" | sed 's/hwmon1/\/sys\/bus\/i2c\/devices/g' )
AFCFAN_TARGET[$fcvcount]=$( echo "${AFCFAN_TARGET[$fcvcount]}" | sed 's/$/_percentage/g')
AFCFAN[$fcvcount]=$( cat ${AFCFAN_PATH[$fcvcount]} )
if [ "${AFCFAN[$fcvcount]}" == 960 ]
then
AFCFAN[$fcvcount]=$zero
fi
done
}
# Check that all referenced sysfs files exist
function CheckFiles
{
local outdated=0 fcvcount tsen fan
if [ $outdated -eq 1 ]
then
echo >&2
echo "At least one referenced file is missing. Either some required kernel" >&2
echo "modules haven't been loaded, or your configuration file is outdated." >&2
echo "In the latter case, you should run pwmconfig again." >&2
fi
return $outdated
}
LoadConfig $1
# Detect path to sensors
if [ ! -d $DIR ]
then
echo $0: 'No sensors found! (did you load the necessary modules?)' >&2
exit 1
fi
cd $DIR
# Check for configuration change
if [ "$DIR" != "/" ] && [ -z "$DEVPATH" -o -z "$DEVNAME" ]
then
echo "Configuration is too old, please run pwmconfig again" >&2
exit 1
fi
if [ "$DIR" = "/" -a -n "$DEVPATH" ]
then
echo "Unneeded DEVPATH with absolute device paths" >&2
exit 1
fi
CheckFiles || exit 1
if [ -f "$PIDFILE" ]
then
echo "File $PIDFILE exists, is fancontrol already running?" >&2
exit 1
fi
echo $$ > "$PIDFILE"
# main function
function UpdateThermalSensors
{
echo ""
TEMP_HIGHEST=0
FAN_PERCENTAGE=0
for i in ${AFCTEMP_PATH[@]}; do
if (( $(cat $i) > $TEMP_HIGHEST )); then
TEMP_HIGHEST=$(cat $i);
fi;
done
TEMP_HIGHEST=$((TEMP_HIGHEST/1000))
echo "The highest temperature of thermal sensors: $TEMP_HIGHEST °C"
}
function UpdateFanSpeeds
{
if [ $TEMP_HIGHEST -lt 51 ]; then #TEMP<=50
FAN_PERCENTAGE=40
elif [ $TEMP_HIGHEST -lt 56 -a $TEMP_HIGHEST -gt 50 ]; then #50<TEMP<=55
FAN_PERCENTAGE=60
elif [ $TEMP_HIGHEST -lt 61 -a $TEMP_HIGHEST -gt 55 ]; then #55<TEMP<=60
FAN_PERCENTAGE=80
elif [ $TEMP_HIGHEST -lt 66 -a $TEMP_HIGHEST -gt 60 ]; then #60<TEMP<=65
FAN_PERCENTAGE=90
elif [ $TEMP_HIGHEST -gt 65 ]; then # 65<TEMP
FAN_PERCENTAGE=100
else
FAN_PERCENTAGE=100
fi
echo "Trying to set fan speed to $FAN_PERCENTAGE %"
#Set speed to fan1~fan10
let fcvcount=0
for fcv in $FCFANS
do
fcvcount=$(( fcvcount + 1 ))
echo $FAN_PERCENTAGE > ${AFCFAN_TARGET[$fcvcount]}
AFCFAN[$fcvcount]=$( cat ${AFCFAN_PATH[$fcvcount]} )
if [ "${AFCFAN[$fcvcount]}" == 960 ]
then
AFCFAN[$fcvcount]=$zero
fi
done
if [ $TEMP_HIGHEST -lt 51 ]; then #TEMP<=50
FAN_ON_PSU_PERCENTAGE=50
elif [ $TEMP_HIGHEST -lt 100 -a $TEMP_HIGHEST -gt 50 ]; then #50<TEMP<100
FAN_ON_PSU_PERCENTAGE=100
else
echo "Unable to get thermal temperature"
FAN_ON_PSU_PERCENTAGE=100
fi
#Set speed to PSU_FAN1
#echo "0x00" > '/sys/bus/i2c/devices/4-0058/psu_select_member'
echo "$FAN_ON_PSU_PERCENTAGE" > '/sys/bus/i2c/devices/40-0058/fan1_set_percentage'
echo "PSU fan1 =$( cat '/sys/bus/i2c/devices/40-0058/fan1_input' ) (rpm)"
#Set speed to PSU_FAN2
#echo "0x20" > '/sys/bus/i2c/devices/4-0058/psu_select_member'
echo "$FAN_ON_PSU_PERCENTAGE" > '/sys/bus/i2c/devices/41-0058/fan1_set_percentage'
echo "PSU fan2 =$( cat '/sys/bus/i2c/devices/41-0058/fan1_input' ) (rpm)"
rm -f "$PIDFILE"
}
# main loop calling the main function at specified intervals
while true
do
UpdateThermalSensors
UpdateFanSpeeds
echo "Sleep $INTERVAL seconds ..."
# Sleep while still handling signals
sleep $INTERVAL &
wait $!
done

View File

@ -0,0 +1,2 @@
CONSOLE_PORT=0x3f8
CONSOLE_SPEED=115200

View File

@ -0,0 +1,45 @@
s CMIC_LEDUP0_PROGRAM_RAM 0
s CMIC_LEDUP1_PROGRAM_RAM 0
led 0 stop
led 0 prog 02 00 60 E0 86 ED 2E E0 32 08 97 02 00 0E 00 60 E3 2E E0 32 00 32 01 B7 97 02 00 0E 00 12 E7 50 86 E0 86 E0 86 E0 86 E0 16 E7 61 EB 06 E3 67 4E 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 06 E0 D2 40 74 06 3A C0 D2 01 74 66 06 EB D2 00 70 62 16 ED 99 99 1A 00 71 62 77 66 32 0F 87 57 32 0E 87 57
led 0 auto on
led 0 start
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=31 REMAP_PORT_1=30 REMAP_PORT_2=29 REMAP_PORT_3=28
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=27 REMAP_PORT_5=26 REMAP_PORT_6=25 REMAP_PORT_7=24
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=23 REMAP_PORT_9=22 REMAP_PORT_10=21 REMAP_PORT_11=20
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=19 REMAP_PORT_13=18 REMAP_PORT_14=17 REMAP_PORT_15=16
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=15 REMAP_PORT_17=14 REMAP_PORT_18=13 REMAP_PORT_19=12
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=11 REMAP_PORT_21=10 REMAP_PORT_22=9 REMAP_PORT_23=8
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=7 REMAP_PORT_25=6 REMAP_PORT_26=5 REMAP_PORT_27=4
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=3 REMAP_PORT_29=2 REMAP_PORT_30=1 REMAP_PORT_31=0
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=63 REMAP_PORT_33=62 REMAP_PORT_34=61 REMAP_PORT_35=60
m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=59 REMAP_PORT_37=58 REMAP_PORT_38=57 REMAP_PORT_39=56
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=55 REMAP_PORT_41=54 REMAP_PORT_42=53 REMAP_PORT_43=52
m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=51 REMAP_PORT_45=50 REMAP_PORT_46=49 REMAP_PORT_47=48
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=47 REMAP_PORT_49=46 REMAP_PORT_50=45 REMAP_PORT_51=44
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=43 REMAP_PORT_53=42 REMAP_PORT_54=41 REMAP_PORT_55=40
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=39 REMAP_PORT_57=38 REMAP_PORT_58=37 REMAP_PORT_59=36
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=35 REMAP_PORT_61=34 REMAP_PORT_62=33 REMAP_PORT_63=32
led 1 stop
led 1 prog 02 00 60 E0 86 ED 2E E0 32 08 97 02 00 0E 00 60 E3 2E E0 32 00 32 01 B7 97 02 00 0E 00 12 E7 50 86 E0 86 E0 86 E0 86 E0 16 E7 61 EB 06 E3 67 4E 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 67 66 06 E0 D2 40 74 06 3A C0 D2 01 74 66 06 EB D2 00 70 62 16 ED 99 99 1A 00 71 62 77 66 32 0F 87 57 32 0E 87 57
led 1 auto on
led 1 start
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=3 REMAP_PORT_1=2 REMAP_PORT_2=1 REMAP_PORT_3=0
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=7 REMAP_PORT_5=6 REMAP_PORT_6=5 REMAP_PORT_7=4
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=11 REMAP_PORT_9=10 REMAP_PORT_10=9 REMAP_PORT_11=8
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=15 REMAP_PORT_13=14 REMAP_PORT_14=13 REMAP_PORT_15=12
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=19 REMAP_PORT_17=18 REMAP_PORT_18=17 REMAP_PORT_19=16
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=23 REMAP_PORT_21=22 REMAP_PORT_22=21 REMAP_PORT_23=20
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=27 REMAP_PORT_25=26 REMAP_PORT_26=25 REMAP_PORT_27=24
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=31 REMAP_PORT_29=30 REMAP_PORT_30=29 REMAP_PORT_31=28
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=35 REMAP_PORT_33=34 REMAP_PORT_34=33 REMAP_PORT_35=32
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=39 REMAP_PORT_37=38 REMAP_PORT_38=37 REMAP_PORT_39=36
m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=43 REMAP_PORT_41=42 REMAP_PORT_42=41 REMAP_PORT_43=40
m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=47 REMAP_PORT_45=46 REMAP_PORT_46=45 REMAP_PORT_47=44
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=51 REMAP_PORT_49=50 REMAP_PORT_50=49 REMAP_PORT_51=48
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=55 REMAP_PORT_53=54 REMAP_PORT_54=53 REMAP_PORT_55=52
m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=59 REMAP_PORT_57=58 REMAP_PORT_58=57 REMAP_PORT_59=56
m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=63 REMAP_PORT_61=62 REMAP_PORT_62=61 REMAP_PORT_63=60

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#############################################################################
# Mellanox
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
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/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-2/2-0053/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,175 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 0
PORT_END = 31
PORTS_IN_BLOCK = 32
EEPROM_OFFSET = 50
_port_to_eeprom_mapping = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self):
return range(0, self.PORTS_IN_BLOCK + 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def __init__(self):
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for x in range(0, self.port_end + 1):
self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET)
SfpUtilBase.__init__(self)
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
try:
reg_file = open("/sys/devices/platform/delta-ag9032v1-cpld.0/sfp_present")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = reg_file.readline().rstrip()
# content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# ModPrsL is active low
if reg_value & mask == 0:
return True
return False
def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
try:
reg_file = open("/sys/devices/platform/delta-ag9032v1-cpld.0/sfp_lpmode")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
content = reg_file.readline().rstrip()
# content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# LPMode is active high
if reg_value & mask == 0:
return False
return True
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
try:
reg_file = open("/sys/devices/platform/delta-ag9032v1-cpld.0/sfp_lpmode", "r+")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = reg_file.readline().rstrip()
# content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
else:
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
content = hex(reg_value)
reg_file.seek(0)
reg_file.write(content)
reg_file.close()
return True
def reset(self, port_num):
QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/devices/platform/delta-ag9032v1-cpld.0/sfp_reset"
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
try:
reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = reg_file.readline().rstrip()
# File content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# ResetL is active low
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
reg_file.seek(0)
reg_file.write(hex(reg_value))
reg_file.close()
# Sleep 1 second to allow it to settle
time.sleep(1)
# Flip the bit back high and write back to the register to take port out of reset
try:
reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "w")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
reg_value = reg_value | mask
reg_file.seek(0)
reg_file.write(hex(reg_value))
reg_file.close()
return True

View File

@ -0,0 +1,61 @@
# libsensors configuration file for DCS-7060CX-32S
# ------------------------------------------------
#
bus "i2c-2" "i2c-1-mux (chan_id 0)"
bus "i2c-3" "i2c-1-mux (chan_id 1)"
bus "i2c-4" "i2c-1-mux (chan_id 2)"
bus "i2c-7" "i2c-1-mux (chan_id 5)"
# tmp75-i2c-2-4d CPU below side thermal sensor.
# tmp75-i2c-3-4f Wind thermal sensor.
# tmp75-i2c-7-4c MAC up side thermal sensor.
# tmp75-i2c-7-4d MAC down side thermal sensor.
# tmp75-i2c-7-4e Surroundings thermal sensor.
chip "tmp75-i2c-2-4d"
label temp1 "CPU below side thermal sensor"
set temp1_max 60
set temp1_max_hyst 55
chip "tmp75-i2c-*-4f"
label temp1 "Wind thermal sensor"
set temp1_max 65
set temp1_max_hyst 60
chip "tmp75-i2c-7-4c"
label temp1 "MAC up side thermal sensor"
set temp1_max 80
set temp1_max_hyst 75
chip "tmp75-i2c-7-4d"
label temp1 "MAC down side thermal sensor"
set temp1_max 75
set temp1_max_hyst 70
chip "tmp75-i2c-7-4e"
label temp1 "Surroundings thermal sensor"
set temp1_max 65
set temp1_max_hyst 60
chip "emc2305-i2c-3-2d"
label fan1 "FANTRAY 1 REAR"
label fan2 "FANTRAY 2 REAR"
label fan3 "FANTRAY 3 REAR"
label fan4 "FANTRAY 4 REAR"
label fan5 "FANTRAY 5 REAR"
chip "emc2305-i2c-3-2c"
label fan1 "FANTRAY 1 FRONT"
label fan2 "FANTRAY 2 FRONT"
label fan3 "FANTRAY 3 FRONT"
label fan4 "FANTRAY 4 FRONT"
label fan5 "FANTRAY 5 FRONT"
chip "pmbus-i2c-4-50"
label temp1 "Fan of power supply controller 1 sensor 1"
label temp2 "Fan of Power supply controller 1 sensor 2"
chip "pmbus-i2c-4-40"
label temp1 "Power supply 1 hotspot sensor"
chip "pmbus-i2c-4-40"
label temp1 "Power supply 2 hotspot sensor"

View File

@ -15,6 +15,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(ACCTON_AS5712_54X_PLATFORM_MODULE) \ $(ACCTON_AS5712_54X_PLATFORM_MODULE) \
$(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \
$(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \
$(CEL_DX010_PLATFORM_MODULE) $(CEL_DX010_PLATFORM_MODULE) \
$(DELTA_AG9032V1_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)

View File

@ -0,0 +1,12 @@
# Delta AG9032v1 Platform modules
DELTA_AG9032V1_PLATFORM_MODULE_VERSION = 1.1
export DELTA_AG9032V1_PLATFORM_MODULE_VERSION
DELTA_AG9032V1_PLATFORM_MODULE = platform-modules-ag9032v1_$(DELTA_AG9032V1_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELTA_AG9032V1_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-delta
$(DELTA_AG9032V1_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
$(DELTA_AG9032V1_PLATFORM_MODULE)_PLATFORM = x86_64-delta_ag9032v1-r0
SONIC_DPKG_DEBS += $(DELTA_AG9032V1_PLATFORM_MODULE)

View File

@ -7,6 +7,7 @@ include $(PLATFORM_PATH)/platform-modules-ingrasys.mk
include $(PLATFORM_PATH)/platform-modules-accton.mk include $(PLATFORM_PATH)/platform-modules-accton.mk
include $(PLATFORM_PATH)/platform-modules-inventec.mk include $(PLATFORM_PATH)/platform-modules-inventec.mk
include $(PLATFORM_PATH)/platform-modules-cel.mk include $(PLATFORM_PATH)/platform-modules-cel.mk
include $(PLATFORM_PATH)/platform-modules-delta.mk
include $(PLATFORM_PATH)/docker-orchagent-brcm.mk include $(PLATFORM_PATH)/docker-orchagent-brcm.mk
include $(PLATFORM_PATH)/docker-syncd-brcm.mk include $(PLATFORM_PATH)/docker-syncd-brcm.mk
include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk

View File

@ -0,0 +1,16 @@
Copyright (C) 2016 Microsoft, Inc
Copyright (C) 2017 Delta 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 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,13 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-i801
i2c-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-gpio
i2c-mux-pca954x

View File

@ -0,0 +1,2 @@
obj-m := at24.o dni_ag9032v1_psu.o dni_emc2305.o delta_ag9032v1_platform.o

View File

@ -0,0 +1,698 @@
/*
* at24.c - handle most I2C EEPROMs
*
* Copyright (C) 2005-2007 David Brownell
* Copyright (C) 2008 Wolfram Sang, Pengutronix
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/platform_data/at24.h>
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
* Differences between different vendor product lines (like Atmel AT24C or
* MicroChip 24LC, etc) won't much matter for typical read/write access.
* There are also I2C RAM chips, likewise interchangeable. One example
* would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
*
* However, misconfiguration can lose data. "Set 16-bit memory address"
* to a part with 8-bit addressing will overwrite data. Writing with too
* big a page size also loses data. And it's not safe to assume that the
* conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
* uses 0x51, for just one example.
*
* Accordingly, explicit board-specific configuration data should be used
* in almost all cases. (One partial exception is an SMBus used to access
* "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
*
* So this driver uses "new style" I2C driver binding, expecting to be
* told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
* similar kernel-resident tables; or, configuration data coming from
* a bootloader.
*
* Other than binding model, current differences from "eeprom" driver are
* that this one handles write access and isn't restricted to 24c02 devices.
* It also handles larger devices (32 kbit and up) with two-byte addresses,
* which won't work on pure SMBus systems.
*/
struct at24_data {
struct at24_platform_data chip;
struct memory_accessor macc;
int use_smbus;
/*
* Lock protects against activities from other Linux tasks,
* but not from changes by other I2C masters.
*/
struct mutex lock;
struct bin_attribute bin;
u8 *writebuf;
unsigned write_max;
unsigned num_addresses;
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls.
*/
struct i2c_client *client[];
};
/*
* This parameter is to help this driver avoid blocking other drivers out
* of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
* clock, one 256 byte read takes about 1/43 second which is excessive;
* but the 1/170 second it takes at 400 kHz may be quite reasonable; and
* at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
*
* This value is forced to be a power of two so that writes align on pages.
*/
static unsigned io_limit = 32;
module_param(io_limit, uint, 0);
MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 32)");
/*
* Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts.
*/
static unsigned write_timeout = 25;
module_param(write_timeout, uint, 0);
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
#define AT24_SIZE_BYTELEN 5
#define AT24_SIZE_FLAGS 8
#define AT24_BITMASK(x) (BIT(x) - 1)
/* create non-zero magic value for given eeprom parameters */
#define AT24_DEVICE_MAGIC(_len, _flags) \
((1 << AT24_SIZE_FLAGS | (_flags)) \
<< AT24_SIZE_BYTELEN | ilog2(_len))
static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
/* spd is a 24c02 in memory DIMMs */
{ "spd", AT24_DEVICE_MAGIC(2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
/* 24rf08 quirk is handled at i2c-core */
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, at24_ids);
/*-------------------------------------------------------------------------*/
/*
* This routine supports chips which consume multiple I2C addresses. It
* computes the addressing information to be used for a given r/w request.
* Assumes that sanity checks for offset happened at sysfs-layer.
*/
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
unsigned *offset)
{
unsigned i;
if (at24->chip.flags & AT24_FLAG_ADDR16) {
i = *offset >> 16;
*offset &= 0xffff;
} else {
i = *offset >> 8;
*offset &= 0xff;
}
return at24->client[i];
}
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
unsigned offset, size_t count)
{
struct i2c_msg msg[2];
u8 msgbuf[2];
struct i2c_client *client;
unsigned long timeout, read_time;
int status, i;
memset(msg, 0, sizeof(msg));
/*
* REVISIT some multi-address chips don't rollover page reads to
* the next slave address, so we may need to truncate the count.
* Those chips might need another quirk flag.
*
* If the real hardware used four adjacent 24c02 chips and that
* were misconfigured as one 24c08, that would be a similar effect:
* one "eeprom" file not four, but larger reads would fail when
* they crossed certain pages.
*/
/*
* Slave address and byte offset derive from the offset. Always
* set the byte address; on a multi-master board, another master
* may have changed the chip's "current" address pointer.
*/
client = at24_translate_offset(at24, &offset);
if (count > io_limit)
count = io_limit;
switch (at24->use_smbus) {
case I2C_SMBUS_I2C_BLOCK_DATA:
/* Smaller eeproms can work given some SMBus extension calls */
if (count > I2C_SMBUS_BLOCK_MAX)
count = I2C_SMBUS_BLOCK_MAX;
break;
case I2C_SMBUS_WORD_DATA:
/* Check for odd length transaction */
count = (count == 1) ? 1 : 2;
break;
case I2C_SMBUS_BYTE_DATA:
count = 1;
break;
default:
/*
* When we have a better choice than SMBus calls, use a
* combined I2C message. Write address; then read up to
* io_limit data bytes. Note that read page rollover helps us
* here (unlike writes). msgbuf is u8 and will cast to our
* needs.
*/
i = 0;
if (at24->chip.flags & AT24_FLAG_ADDR16)
msgbuf[i++] = offset >> 8;
msgbuf[i++] = offset;
msg[0].addr = client->addr;
msg[0].buf = msgbuf;
msg[0].len = i;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
}
/*
* Reads fail if the previous write didn't complete yet. We may
* loop a few times until this one succeeds, waiting at least
* long enough for one entire page write to work.
*/
timeout = jiffies + msecs_to_jiffies(write_timeout);
do {
read_time = jiffies;
switch (at24->use_smbus) {
case I2C_SMBUS_I2C_BLOCK_DATA:
status = i2c_smbus_read_i2c_block_data(client, offset,
count, buf);
break;
case I2C_SMBUS_WORD_DATA:
status = i2c_smbus_read_word_data(client, offset);
if (status >= 0) {
buf[0] = status & 0xff;
if (count == 2)
buf[1] = status >> 8;
status = count;
}
break;
case I2C_SMBUS_BYTE_DATA:
status = i2c_smbus_read_byte_data(client, offset);
if (status >= 0) {
buf[0] = status;
status = count;
}
break;
default:
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
status = count;
}
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
count, offset, status, jiffies);
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
msleep(1);
} while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
static ssize_t at24_read(struct at24_data *at24,
char *buf, loff_t off, size_t count)
{
ssize_t retval = 0;
if (unlikely(!count))
return count;
/*
* Read data from chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
*/
mutex_lock(&at24->lock);
while (count) {
ssize_t status;
status = at24_eeprom_read(at24, buf, off, count);
if (status <= 0) {
if (retval == 0)
retval = status;
break;
}
buf += status;
off += status;
count -= status;
retval += status;
}
mutex_unlock(&at24->lock);
return retval;
}
static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct at24_data *at24;
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
return at24_read(at24, buf, off, count);
}
/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
* variants here, including OTP fuses and partial chip protect.
*
* We only use page mode writes; the alternative is sloooow. This routine
* writes at most one page.
*/
static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
unsigned offset, size_t count)
{
struct i2c_client *client;
struct i2c_msg msg;
ssize_t status;
unsigned long timeout, write_time;
unsigned next_page;
/* Get corresponding I2C address and adjust offset */
client = at24_translate_offset(at24, &offset);
/* write_max is at most a page */
if (count > at24->write_max)
count = at24->write_max;
/* Never roll over backwards, to the start of this page */
next_page = roundup(offset + 1, at24->chip.page_size);
if (offset + count > next_page)
count = next_page - offset;
/* If we'll use I2C calls for I/O, set up the message */
if (!at24->use_smbus) {
int i = 0;
msg.addr = client->addr;
msg.flags = 0;
/* msg.buf is u8 and casts will mask the values */
msg.buf = at24->writebuf;
if (at24->chip.flags & AT24_FLAG_ADDR16)
msg.buf[i++] = offset >> 8;
msg.buf[i++] = offset;
memcpy(&msg.buf[i], buf, count);
msg.len = i + count;
}
/*
* Writes fail if the previous one didn't complete yet. We may
* loop a few times until this one succeeds, waiting at least
* long enough for one entire page write to work.
*/
timeout = jiffies + msecs_to_jiffies(write_timeout);
do {
write_time = jiffies;
if (at24->use_smbus) {
status = i2c_smbus_write_i2c_block_data(client,
offset, count, buf);
if (status == 0)
status = count;
} else {
status = i2c_transfer(client->adapter, &msg, 1);
if (status == 1)
status = count;
}
dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
count, offset, status, jiffies);
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
msleep(1);
} while (time_before(write_time, timeout));
return -ETIMEDOUT;
}
static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
size_t count)
{
ssize_t retval = 0;
if (unlikely(!count))
return count;
/*
* Write data to chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
*/
mutex_lock(&at24->lock);
while (count) {
ssize_t status;
status = at24_eeprom_write(at24, buf, off, count);
if (status <= 0) {
if (retval == 0)
retval = status;
break;
}
buf += status;
off += status;
count -= status;
retval += status;
}
mutex_unlock(&at24->lock);
return retval;
}
static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct at24_data *at24;
if (unlikely(off >= attr->size))
return -EFBIG;
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
return at24_write(at24, buf, off, count);
}
/*-------------------------------------------------------------------------*/
/*
* This lets other kernel code access the eeprom data. For example, it
* might hold a board's Ethernet address, or board-specific calibration
* data generated on the manufacturing floor.
*/
static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
off_t offset, size_t count)
{
struct at24_data *at24 = container_of(macc, struct at24_data, macc);
return at24_read(at24, buf, offset, count);
}
static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
off_t offset, size_t count)
{
struct at24_data *at24 = container_of(macc, struct at24_data, macc);
return at24_write(at24, buf, offset, count);
}
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_OF
static void at24_get_ofdata(struct i2c_client *client,
struct at24_platform_data *chip)
{
const __be32 *val;
struct device_node *node = client->dev.of_node;
if (node) {
if (of_get_property(node, "read-only", NULL))
chip->flags |= AT24_FLAG_READONLY;
val = of_get_property(node, "pagesize", NULL);
if (val)
chip->page_size = be32_to_cpup(val);
}
}
#else
static void at24_get_ofdata(struct i2c_client *client,
struct at24_platform_data *chip)
{ }
#endif /* CONFIG_OF */
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct at24_platform_data chip;
bool writable;
int use_smbus = 0;
struct at24_data *at24;
int err;
unsigned i, num_addresses;
kernel_ulong_t magic;
if (client->dev.platform_data) {
chip = *(struct at24_platform_data *)client->dev.platform_data;
} else {
if (!id->driver_data)
return -ENODEV;
magic = id->driver_data;
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
magic >>= AT24_SIZE_BYTELEN;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
chip.page_size = 1;
/* update chipdata if OF is present */
at24_get_ofdata(client, &chip);
chip.setup = NULL;
chip.context = NULL;
}
if (!is_power_of_2(chip.byte_len))
dev_warn(&client->dev,
"byte_len looks suspicious (no power of 2)!\n");
if (!chip.page_size) {
dev_err(&client->dev, "page_size must not be 0!\n");
return -EINVAL;
}
if (!is_power_of_2(chip.page_size))
dev_warn(&client->dev,
"page_size looks suspicious (no power of 2)!\n");
/* Use I2C operations unless we're stuck with SMBus extensions. */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
if (chip.flags & AT24_FLAG_ADDR16)
return -EPFNOSUPPORT;
if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
} else if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA)) {
use_smbus = I2C_SMBUS_WORD_DATA;
} else if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
use_smbus = I2C_SMBUS_BYTE_DATA;
} else {
return -EPFNOSUPPORT;
}
}
if (chip.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8;
else
num_addresses = DIV_ROUND_UP(chip.byte_len,
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
if (!at24)
return -ENOMEM;
mutex_init(&at24->lock);
at24->use_smbus = use_smbus;
at24->chip = chip;
at24->num_addresses = num_addresses;
/*
* Export the EEPROM bytes through sysfs, since that's convenient.
* By default, only root should see the data (maybe passwords etc)
*/
sysfs_bin_attr_init(&at24->bin);
at24->bin.attr.name = "eeprom";
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
at24->bin.read = at24_bin_read;
at24->bin.size = chip.byte_len;
at24->macc.read = at24_macc_read;
writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
if (!use_smbus || i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
unsigned write_max = chip.page_size;
at24->macc.write = at24_macc_write;
at24->bin.write = at24_bin_write;
at24->bin.attr.mode |= S_IWUSR;
if (write_max > io_limit)
write_max = io_limit;
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
write_max = I2C_SMBUS_BLOCK_MAX;
at24->write_max = write_max;
/* buffer (data + address at the beginning) */
at24->writebuf = devm_kzalloc(&client->dev,
write_max + 2, GFP_KERNEL);
if (!at24->writebuf)
return -ENOMEM;
} else {
dev_warn(&client->dev,
"cannot write due to controller restrictions.");
}
}
at24->client[0] = client;
/* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) {
at24->client[i] = i2c_new_dummy(client->adapter,
client->addr + i);
if (!at24->client[i]) {
dev_err(&client->dev, "address 0x%02x unavailable\n",
client->addr + i);
err = -EADDRINUSE;
goto err_clients;
}
}
err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
if (err)
goto err_clients;
i2c_set_clientdata(client, at24);
dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
at24->bin.size, client->name,
writable ? "writable" : "read-only", at24->write_max);
if (use_smbus == I2C_SMBUS_WORD_DATA ||
use_smbus == I2C_SMBUS_BYTE_DATA) {
dev_notice(&client->dev, "Falling back to %s reads, "
"performance will suffer\n", use_smbus ==
I2C_SMBUS_WORD_DATA ? "word" : "byte");
}
/* export data to kernel code */
if (chip.setup)
chip.setup(&at24->macc, chip.context);
return 0;
err_clients:
for (i = 1; i < num_addresses; i++)
if (at24->client[i])
i2c_unregister_device(at24->client[i]);
return err;
}
static int at24_remove(struct i2c_client *client)
{
struct at24_data *at24;
int i;
at24 = i2c_get_clientdata(client);
sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
for (i = 1; i < at24->num_addresses; i++)
i2c_unregister_device(at24->client[i]);
return 0;
}
/*-------------------------------------------------------------------------*/
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.owner = THIS_MODULE,
},
.probe = at24_probe,
.remove = at24_remove,
.id_table = at24_ids,
};
static int __init at24_init(void)
{
if (!io_limit) {
pr_err("at24: io_limit must not be 0!\n");
return -EINVAL;
}
io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&at24_driver);
}
module_init(at24_init);
static void __exit at24_exit(void)
{
i2c_del_driver(&at24_driver);
}
module_exit(at24_exit);
MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
MODULE_AUTHOR("David Brownell and Wolfram Sang");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,545 @@
/*
* An hwmon driver for delta AG9032v1 PSU
* dps_800ab_16_d.c - Support for DPS-800AB-16 D Power Supply Module
*
* Copyright (C) 2017 Delta Networks, Inc.
*
* Aries Lin <aries.lin@deltaww.com>
*
* Based on ym2651y.c
* Based on ad7414.c
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#define MAX_FAN_DUTY_CYCLE 100
#define SWPLD_REG 0x31
#define SWPLD_PSU_MUX_REG 0x21
#define SELECT_PSU1_EEPROM 0x00
#define SELECT_PSU2_EEPROM 0x20
u8 psu_member_data = 0x00;
/* Address scanned */
static const unsigned short normal_i2c[] = { 0x58, I2C_CLIENT_END };
/* This is additional data */
struct dps_800ab_16_d_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
/* Registers value */
u8 vout_mode;
u16 in1_input;
u16 in2_input;
u16 curr1_input;
u16 curr2_input;
u16 power1_input;
u16 power2_input;
u16 temp_input[2];
u8 fan_target;
u16 fan_duty_cycle_input[2];
u16 fan_speed_input[2];
u8 mfr_model[16];
u8 mfr_serial[16];
};
static int two_complement_to_int(u16 data, u8 valid_bit, int mask);
static ssize_t set_fan_duty_cycle_input(struct device *dev, struct device_attribute \
*dev_attr, const char *buf, size_t count);
static ssize_t for_linear_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf);
static ssize_t for_fan_target(struct device *dev, struct device_attribute \
*dev_attr, char *buf);
static ssize_t for_vout_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf);
static int dps_800ab_16_d_read_byte(struct i2c_client *client, u8 reg);
static int dps_800ab_16_d_read_word(struct i2c_client *client, u8 reg);
static int dps_800ab_16_d_write_word(struct i2c_client *client, u8 reg, \
u16 value);
static int dps_800ab_16_d_read_block(struct i2c_client *client, u8 command, \
u8 *data, int data_len);
static struct dps_800ab_16_d_data *dps_800ab_16_d_update_device( \
struct device *dev);
static ssize_t for_ascii(struct device *dev, struct device_attribute \
*dev_attr, char *buf);
static ssize_t set_w_member_data(struct device *dev, struct device_attribute \
*dev_att, const char *buf, size_t count);
static ssize_t for_r_member_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf);
enum dps_800ab_16_d_sysfs_attributes {
PSU_V_IN,
PSU_V_OUT,
PSU_I_IN,
PSU_I_OUT,
PSU_P_IN,
PSU_P_OUT,
PSU_TEMP1_INPUT,
PSU_FAN1_FAULT,
PSU_FAN1_DUTY_CYCLE,
PSU_FAN1_SPEED,
PSU_MFR_MODEL,
PSU_MFR_SERIAL,
PSU_SELECT_MEMBER,
};
static ssize_t set_w_member_data(struct device *dev, struct device_attribute \
*dev_attr, const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
long data;
int error;
if (attr->index == PSU_SELECT_MEMBER) {
error = kstrtol(buf, 16, &data);
if (error)
return error;
if (SELECT_PSU1_EEPROM == data) {
psu_member_data = SELECT_PSU1_EEPROM;
} else if (SELECT_PSU2_EEPROM == data) {
psu_member_data = SELECT_PSU2_EEPROM;
} else {
return -EINVAL;
}
}
return count;
}
static ssize_t for_r_member_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf)
{
return sprintf(buf, "0x%02X\n", psu_member_data);
}
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_input(struct device *dev, struct device_attribute \
*dev_attr, const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct i2c_client *client = to_i2c_client(dev);
struct dps_800ab_16_d_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;
/* Select SWPLD PSU offset */
mutex_lock(&data->update_lock);
data->fan_duty_cycle_input[nr] = speed;
dps_800ab_16_d_write_word(client, 0x3B + nr, data->fan_duty_cycle_input[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t for_linear_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct dps_800ab_16_d_data *data = dps_800ab_16_d_update_device(dev);
u16 value = 0;
int exponent, mantissa;
int multiplier = 1000;
switch (attr->index) {
case PSU_V_IN:
value = data->in1_input;
break;
case PSU_I_IN:
value = data->curr1_input;
break;
case PSU_I_OUT:
value = data->curr2_input;
break;
case PSU_P_IN:
value = data->power1_input;
multiplier = 1000*1000;
break;
case PSU_P_OUT:
value = data->power2_input;
multiplier = 1000*1000;
break;
case PSU_TEMP1_INPUT:
value = data->temp_input[0];
break;
case PSU_FAN1_DUTY_CYCLE:
multiplier = 1;
value = data->fan_duty_cycle_input[0];
break;
case PSU_FAN1_SPEED:
multiplier = 1;
value = data->fan_speed_input[0];
break;
default:
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 for_fan_target(struct device *dev, struct device_attribute \
*dev_attr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct dps_800ab_16_d_data *data = dps_800ab_16_d_update_device(dev);
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
return sprintf(buf, "%d\n", data->fan_target >> shift);
}
static ssize_t for_vout_data(struct device *dev, struct device_attribute \
*dev_attr, char *buf)
{
struct dps_800ab_16_d_data *data = dps_800ab_16_d_update_device(dev);
int exponent, mantissa;
int multiplier = 1000;
exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
mantissa = data->in2_input;
return (exponent > 0) ? sprintf(buf, "%d\n", \
(mantissa * multiplier) / (1 << exponent)): \
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
}
static ssize_t for_ascii(struct device *dev, struct device_attribute \
*dev_attr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct dps_800ab_16_d_data *data = dps_800ab_16_d_update_device(dev);
u8 *ptr = NULL;
if (!data->valid)
return 0;
switch (attr->index) {
case PSU_MFR_MODEL:
ptr = data->mfr_model + 1;
break;
case PSU_MFR_SERIAL:
ptr = data->mfr_serial + 1;
break;
default:
return 0;
}
return sprintf(buf, "%s\n", ptr);
}
static int dps_800ab_16_d_read_byte(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static int dps_800ab_16_d_read_word(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_word_data(client, reg);
}
static int dps_800ab_16_d_write_word(struct i2c_client *client, u8 reg, \
u16 value)
{
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_xfer(client->adapter, client->addr,
client->flags |= I2C_CLIENT_PEC,
I2C_SMBUS_WRITE, reg,
I2C_SMBUS_WORD_DATA, &data);
}
static int dps_800ab_16_d_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 dps_800ab_16_d_data *dps_800ab_16_d_update_device( \
struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct dps_800ab_16_d_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
/* Select SWPLD PSU offset */
if (time_after(jiffies, data->last_updated)) {
int i, status;
u8 command;
struct reg_data_byte regs_byte[] = {
{0x20, &data->vout_mode},
{0x81, &data->fan_target}
};
struct reg_data_word regs_word[] = {
{0x88, &data->in1_input},
{0x8b, &data->in2_input},
{0x89, &data->curr1_input},
{0x8c, &data->curr2_input},
{0x96, &data->power2_input},
{0x97, &data->power1_input},
{0x8d, &(data->temp_input[0])},
{0x8e, &(data->temp_input[1])},
{0x3b, &(data->fan_duty_cycle_input[0])},
{0x90, &(data->fan_speed_input[0])},
};
dev_dbg(&client->dev, "start data update\n");
/* one milliseconds from now */
data->last_updated = jiffies + HZ / 1000;
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
status = dps_800ab_16_d_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;
}
}
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
status = dps_800ab_16_d_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;
}
}
command = 0x9a; /* PSU mfr_model */
status = dps_800ab_16_d_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);
}
command = 0x9e; /* PSU mfr_serial */
status = dps_800ab_16_d_read_block(client, command,
data->mfr_serial, ARRAY_SIZE(data->mfr_serial) - 1);
data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command,
status);
}
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
/* sysfs attributes for hwmon */
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, for_linear_data, NULL, PSU_V_IN);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, for_vout_data, NULL, PSU_V_OUT);
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, for_linear_data, NULL, PSU_I_IN);
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, for_linear_data, NULL, PSU_I_OUT);
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, for_linear_data, NULL, PSU_P_IN);
static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, for_linear_data, NULL, PSU_P_OUT);
static SENSOR_DEVICE_ATTR(temp1_input, \
S_IRUGO, for_linear_data, NULL, PSU_TEMP1_INPUT);
static SENSOR_DEVICE_ATTR(fan1_target, \
S_IRUGO, for_fan_target, NULL, PSU_FAN1_FAULT);
static SENSOR_DEVICE_ATTR(fan1_set_percentage, S_IWUGO | S_IRUGO, \
for_linear_data, set_fan_duty_cycle_input, PSU_FAN1_DUTY_CYCLE);
static SENSOR_DEVICE_ATTR(fan1_input, \
S_IRUGO, for_linear_data, NULL, PSU_FAN1_SPEED);
static SENSOR_DEVICE_ATTR(psu_mfr_model, \
S_IRUGO, for_ascii, NULL, PSU_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu_mfr_serial, \
S_IRUGO, for_ascii, NULL, PSU_MFR_SERIAL);
static SENSOR_DEVICE_ATTR(psu_select_member, S_IWUGO | S_IRUGO, \
for_r_member_data, set_w_member_data, PSU_SELECT_MEMBER);
static struct attribute *dps_800ab_16_d_attributes[] = {
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_curr2_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
&sensor_dev_attr_power2_input.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_fan1_target.dev_attr.attr,
&sensor_dev_attr_fan1_set_percentage.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
&sensor_dev_attr_psu_mfr_serial.dev_attr.attr,
&sensor_dev_attr_psu_select_member.dev_attr.attr,
NULL
};
static const struct attribute_group dps_800ab_16_d_group = {
.attrs = dps_800ab_16_d_attributes,
};
static int dps_800ab_16_d_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct dps_800ab_16_d_data *data;
int status;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(*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, "new chip found\n");
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &dps_800ab_16_d_group);
if (status)
goto exit_sysfs_create_group;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_hwmon_device_register;
}
return 0;
exit_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, &dps_800ab_16_d_group);
exit_sysfs_create_group:
kfree(data);
exit:
return status;
}
static int dps_800ab_16_d_remove(struct i2c_client *client)
{
struct dps_800ab_16_d_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &dps_800ab_16_d_group);
kfree(data);
return 0;
}
enum id_name {
dni_ag9032v1_psu,
dps_800ab_16_d
};
static const struct i2c_device_id dps_800ab_16_d_id[] = {
{ "dni_ag9032v1_psu", dni_ag9032v1_psu },
{ "dps_800ab_16_d", dps_800ab_16_d },
{}
};
MODULE_DEVICE_TABLE(i2c, dps_800ab_16_d_id);
/* This is the driver that will be inserted */
static struct i2c_driver dps_800ab_16_d_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "dps_800ab_16_d",
},
.probe = dps_800ab_16_d_probe,
.remove = dps_800ab_16_d_remove,
.id_table = dps_800ab_16_d_id,
.address_list = normal_i2c,
};
static int __init dps_800ab_16_d_init(void)
{
return i2c_add_driver(&dps_800ab_16_d_driver);
}
static void __exit dps_800ab_16_d_exit(void)
{
i2c_del_driver(&dps_800ab_16_d_driver);
}
MODULE_AUTHOR("Aries Lin <aries.lin@deltaww.com>");
MODULE_DESCRIPTION("DPS_800AB_16_D Driver");
MODULE_LICENSE("GPL");
module_init(dps_800ab_16_d_init);
module_exit(dps_800ab_16_d_exit);

View File

@ -0,0 +1,381 @@
/*
* <bsn.cl fy=2013 v=gpl>
*
* Copyright (C) 2017 Delta Networks, Inc.
*
* This program is free software; you can redistribute it
* and/or modify it under the terms ofthe GNU General Public License as
* published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
*
* </bsn.cl>
*
*
* A hwmon driver for the SMSC EMC2305 fan controller
* Complete datasheet is available (6/2013) at:
* http://www.smsc.com/media/Downloads_Public/Data_Sheets/2305.pdf
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count);
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
char *buf);
static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count);
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
char *buf);
static ssize_t set_fan_percentage(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count);
static ssize_t show_fan_percentage(struct device *dev, struct device_attribute * devattr,
char *buf);
static const unsigned short normal_i2c[] = { 0x2C, 0x2D, 0x2E, 0x2F, 0x4C,
0x4D, I2C_CLIENT_END
};
#define EMC2305_REG_DEVICE 0xFD
#define EMC2305_REG_VENDOR 0xFE
//#define FAN_MINIMUN 0x33 /*20%*/
#define FAN_MINIMUN 0x0 /*0%*/
#define FAN_RPM_BASED 0xAB
#define EMC2305_REG_FAN_DRIVE(n) (0x30 + 0x10 * n)
#define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * n)
#define EMC2305_REG_FAN_TACH(n) (0x3E + 0x10 * n)
#define EMC2305_REG_FAN_CONF(n) (0x32 + 0x10 * n)
#define EMC2305_REG_FAN_REAR_H_RPM(n) (0x3D + 0x10 * n)
#define EMC2305_REG_FAN_REAR_L_RPM(n) (0x3C + 0x10 * n)
#define EMC2305_DEVICE 0x34
#define EMC2305_VENDOR 0x5D
#define MAX_FAN_SPEED 23000
struct emc2305_data
{
struct device *hwmon_dev;
struct attribute_group attrs;
struct mutex lock;
};
static int emc2305_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int emc2305_detect(struct i2c_client *client,
struct i2c_board_info *info);
static int emc2305_remove(struct i2c_client *client);
static const struct i2c_device_id emc2305_id[] =
{
{ "emc2305", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc2305_id);
static struct i2c_driver emc2305_driver =
{
.class = I2C_CLASS_HWMON,
.driver = {
.name = "emc2305",
},
.probe = emc2305_probe,
.remove = emc2305_remove,
.id_table = emc2305_id,
.detect = emc2305_detect,
.address_list = normal_i2c,
};
static SENSOR_DEVICE_ATTR(fan1_input, S_IWUSR | S_IRUGO, show_fan, set_fan, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IWUSR | S_IRUGO, show_fan, set_fan, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IWUSR | S_IRUGO, show_fan, set_fan, 2);
static SENSOR_DEVICE_ATTR(fan4_input, S_IWUSR | S_IRUGO, show_fan, set_fan, 3);
static SENSOR_DEVICE_ATTR(fan5_input, S_IWUSR | S_IRUGO, show_fan, set_fan, 4);
static SENSOR_DEVICE_ATTR(fan1_input_percentage, S_IWUSR | S_IRUGO, show_fan_percentage, set_fan_percentage, 0);
static SENSOR_DEVICE_ATTR(fan2_input_percentage, S_IWUSR | S_IRUGO, show_fan_percentage, set_fan_percentage, 1);
static SENSOR_DEVICE_ATTR(fan3_input_percentage, S_IWUSR | S_IRUGO, show_fan_percentage, set_fan_percentage, 2);
static SENSOR_DEVICE_ATTR(fan4_input_percentage, S_IWUSR | S_IRUGO, show_fan_percentage, set_fan_percentage, 3);
static SENSOR_DEVICE_ATTR(fan5_input_percentage, S_IWUSR | S_IRUGO, show_fan_percentage, set_fan_percentage, 4);
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 4);
static struct attribute *emc2305_attr[] =
{
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan1_input_percentage.dev_attr.attr,
&sensor_dev_attr_fan2_input_percentage.dev_attr.attr,
&sensor_dev_attr_fan3_input_percentage.dev_attr.attr,
&sensor_dev_attr_fan4_input_percentage.dev_attr.attr,
&sensor_dev_attr_fan5_input_percentage.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
NULL
};
static ssize_t show_fan_percentage(struct device *dev, struct device_attribute * devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
int val;
mutex_lock(&data->lock);
val = i2c_smbus_read_word_swapped(client,
EMC2305_REG_FAN_TACH(attr->index));
mutex_unlock(&data->lock);
/* Left shift 3 bits for showing correct RPM */
val = val >> 3;
if ((int)(3932160 * 2 / (val > 0 ? val : 1) == 960))return sprintf(buf, "%d\n", 0);
return sprintf(buf, "%d\n", (int)(3932160 * 2 / (val > 0 ? val : 1) * 100 / MAX_FAN_SPEED));
}
static ssize_t set_fan_percentage(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
unsigned long hsb, lsb;
unsigned long tech;
unsigned long val;
int ret;
ret = kstrtoul(buf, 10, &val);
if (ret)
{
return ret;
}
if (val > 100)
{
return -EINVAL;
}
if (val <= 5)
{
hsb = 0xff; /*high bit*/
lsb = 0xe0; /*low bit*/
}
else
{
val = val * 230;
tech = (3932160 * 2) / (val > 0 ? val : 1);
hsb = (uint8_t)(((tech << 3) >> 8) & 0x0ff);
lsb = (uint8_t)((tech << 3) & 0x0f8);
}
mutex_lock(&data->lock);
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_REAR_H_RPM(attr->index), hsb);
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_REAR_L_RPM(attr->index), lsb);
mutex_unlock(&data->lock);
return count;
}
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
int val;
mutex_lock(&data->lock);
val = i2c_smbus_read_word_swapped(client,
EMC2305_REG_FAN_TACH(attr->index));
mutex_unlock(&data->lock);
/* Left shift 3 bits for showing correct RPM */
val = val >> 3;
return sprintf(buf, "%d\n", 3932160 * 2 / (val > 0 ? val : 1));
}
static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
unsigned long hsb, lsb;
unsigned long tech;
unsigned long val;
int ret;
ret = kstrtoul(buf, 10, &val);
if (ret)
{
return ret;
}
if (val > 23000)
{
return -EINVAL;
}
if (val <= 960)
{
hsb = 0xff; /*high bit*/
lsb = 0xe0; /*low bit*/
}
else
{
tech = (3932160 * 2) / (val > 0 ? val : 1);
hsb = (uint8_t)(((tech << 3) >> 8) & 0x0ff);
lsb = (uint8_t)((tech << 3) & 0x0f8);
}
mutex_lock(&data->lock);
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_REAR_H_RPM(attr->index), hsb);
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_REAR_L_RPM(attr->index), lsb);
mutex_unlock(&data->lock);
return count;
}
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
int val;
mutex_lock(&data->lock);
val = i2c_smbus_read_byte_data(client,
EMC2305_REG_FAN_DRIVE(attr->index));
mutex_unlock(&data->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct emc2305_data *data = i2c_get_clientdata(client);
unsigned long val;
int ret;
ret = kstrtoul(buf, 10, &val);
if (ret)
{
return ret;
}
if (val > 255)
{
return -EINVAL;
}
mutex_lock(&data->lock);
i2c_smbus_write_byte_data(client,
EMC2305_REG_FAN_DRIVE(attr->index),
val);
mutex_unlock(&data->lock);
return count;
}
static int emc2305_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int vendor, device;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
{
return -ENODEV;
}
vendor = i2c_smbus_read_byte_data(client, EMC2305_REG_VENDOR);
if (vendor != EMC2305_VENDOR)
{
return -ENODEV;
}
device = i2c_smbus_read_byte_data(client, EMC2305_REG_DEVICE);
if (device != EMC2305_DEVICE)
{
return -ENODEV;
}
strlcpy(info->type, "emc2305", I2C_NAME_SIZE);
return 0;
}
static int emc2305_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct emc2305_data *data;
int err;
int i;
data = devm_kzalloc(&client->dev, sizeof(struct emc2305_data),
GFP_KERNEL);
if (!data)
{
return -ENOMEM;
}
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
dev_info(&client->dev, "%s chip found\n", client->name);
data->attrs.attrs = emc2305_attr;
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
if (err)
{
return err;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev))
{
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
for (i = 0; i < 5; i++)
{
/* set minimum drive to 0% */
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i), FAN_MINIMUN);
i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_CONF(i), FAN_RPM_BASED);
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
return err;
}
static int emc2305_remove(struct i2c_client *client)
{
struct emc2305_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
return 0;
}
module_i2c_driver(emc2305_driver);
MODULE_AUTHOR("Neal Tai<neal.tai@deltaww.com>");
MODULE_DESCRIPTION("SMSC EMC2305 fan controller driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,9 @@
#!/bin/bash
#platform init script for Delta ag9032v1
#fan speed monitol start
/usr/share/sonic/device/x86_64-delta_ag9032v1-r0/fancontrol.service /usr/share/sonic/device/x86_64-delta_ag9032v1-r0/fancontrol &
exit 0

View File

@ -0,0 +1,225 @@
#!/bin/bash
FAN1_EEPROM="-y 31 0x51 0x0a"
FAN2_EEPROM="-y 32 0x52 0x0a"
FAN3_EEPROM="-y 33 0x53 0x0a"
FAN4_EEPROM="-y 34 0x54 0x0a"
FAN5_EEPROM="-y 35 0x55 0x0a"
LED_CONTROL="/sys/devices/platform/delta-ag9032v1-cpld.0/led_control"
FAN1_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-37/37-002c/fan5_input"
FAN1_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-38/38-002d/fan5_input"
FAN2_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-37/37-002c/fan4_input"
FAN2_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-38/38-002d/fan4_input"
FAN3_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-37/37-002c/fan3_input"
FAN3_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-38/38-002d/fan3_input"
FAN4_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-37/37-002c/fan2_input"
FAN4_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-38/38-002d/fan2_input"
FAN5_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-37/37-002c/fan1_input"
FAN5_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/i2c-38/38-002d/fan1_input"
PSU1_EEPROM="-y 40 0x50 0x00"
PSU2_EEPROM="-y 41 0x50 0x00"
PSU1_FAN_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-4/i2c-40/40-0058/fan1_input"
PSU2_FAN_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-4/i2c-41/41-0058/fan1_input"
catfaneeprom(){
fan_eeprom_num=0
i2cget $FAN1_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan_eeprom_num=$((fan_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan_eeprom_num=$((fan_eeprom_num))
fi
i2cget $FAN2_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan_eeprom_num=$((fan_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan_eeprom_num=$((fan_eeprom_num_num))
fi
i2cget $FAN3_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan_eeprom_num=$((fan_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan_eeprom_num=$((fan_eeprom_num))
fi
i2cget $FAN4_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan_eeprom_num=$((fan_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan_eeprom_num=$((fan_eeprom_num))
fi
i2cget $FAN5_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan_eeprom_num=$((fan_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan_eeprom_num=$((fan_eeprom_num))
fi
}
catfanspeed(){
fan_rpm_normal_num=0
fan1_rpm_normal_num=0
fan1_front_rpm=`cat $FAN1_FRONT_RPM`
fan1_rear_rpm=`cat $FAN1_REAR_RPM`
if [ "${fan1_front_rpm}" -ne "960" ] && [ "${fan1_rear_rpm}" -ne "960" ] && [ "${fan1_front_rpm}" -ne "0" ] && [ "${fan1_rear_rpm}" -ne "0" ]; then
fan1_rpm_normal_num=$((fan1_rpm_normal_num+1))
elif [ "${fan1_front_rpm}" -eq "960" ] || [ "${fan1_rear_rpm}" -eq "960" ] || [ "${fan1_front_rpm}" -eq "0" ] || [ "${fan1_rear_rpm}" -eq "0" ]; then
fan1_rpm_normal_num=$((fan1_rpm_normal_num))
fi
fan2_rpm_normal_num=0
fan2_front_rpm=`cat $FAN2_FRONT_RPM`
fan2_rear_rpm=`cat $FAN2_REAR_RPM`
if [ "${fan2_front_rpm}" -ne "960" ] && [ "${fan2_rear_rpm}" -ne "960" ] && [ "${fan2_front_rpm}" -ne "0" ] && [ "${fan2_rear_rpm}" -ne "0" ]; then
fan2_rpm_normal_num=$((fan2_rpm_normal_num+1))
elif [ "${fan2_front_rpm}" -eq "960" ] || [ "${fan2_rear_rpm}" -eq "960" ] || [ "${fan2_front_rpm}" -eq "0" ] || [ "${fan2_rear_rpm}" -eq "0" ]; then
fan2_rpm_normal_num=$((fan2_rpm_normal_num))
fi
fan3_rpm_normal_num=0
fan3_front_rpm=`cat $FAN3_FRONT_RPM`
fan3_rear_rpm=`cat $FAN3_REAR_RPM`
if [ "${fan3_front_rpm}" -ne "960" ] && [ "${fan3_rear_rpm}" -ne "960" ] && [ "${fan3_front_rpm}" -ne "0" ] && [ "${fan3_rear_rpm}" -ne "0" ]; then
fan3_rpm_normal_num=$((fan3_rpm_normal_num+1))
elif [ "${fan3_front_rpm}" -eq "960" ] || [ "${fan3_rear_rpm}" -eq "960" ] || [ "${fan3_front_rpm}" -eq "0" ] || [ "${fan3_rear_rpm}" -eq "0" ]; then
fan3_rpm_normal_num=$((fan3_rpm_normal_num))
fi
fan4_rpm_normal_num=0
fan4_front_rpm=`cat $FAN4_FRONT_RPM`
fan4_rear_rpm=`cat $FAN4_REAR_RPM`
if [ "${fan4_front_rpm}" -ne "960" ] && [ "${fan4_rear_rpm}" -ne "960" ] && [ "${fan4_front_rpm}" -ne "0" ] && [ "${fan4_rear_rpm}" -ne "0" ]; then
fan4_rpm_normal_num=$((fan4_rpm_normal_num+1))
elif [ "${fan4_front_rpm}" -eq "960" ] || [ "${fan4_rear_rpm}" -eq "960" ] || [ "${fan4_front_rpm}" -eq "0" ] || [ "${fan4_rear_rpm}" -eq "0" ]; then
fan4_rpm_normal_num=$((fan4_rpm_normal_num))
fi
fan5_rpm_normal_num=0
fan5_front_rpm=`cat $FAN5_FRONT_RPM`
fan5_rear_rpm=`cat $FAN5_REAR_RPM`
if [ "${fan5_front_rpm}" -ne "960" ] && [ "${fan5_rear_rpm}" -ne "960" ] && [ "${fan5_front_rpm}" -ne "0" ] && [ "${fan5_rear_rpm}" -ne "0" ]; then
fan5_rpm_normal_num=$((fan5_rpm_normal_num+1))
elif [ "${fan5_front_rpm}" -eq "960" ] || [ "${fan5_rear_rpm}" -eq "960" ] || [ "${fan5_front_rpm}" -eq "0" ] || [ "${fan5_rear_rpm}" -eq "0" ]; then
fan5_rpm_normal_num=$((fan5_rpm_normal_num))
fi
fan_rpm_normal_num=$((fan1_rpm_normal_num+fan2_rpm_normal_num+fan3_rpm_normal_num+fan4_rpm_normal_num+fan5_rpm_normal_num))
}
catpsueeprom(){
psu1_eeprom_num=0
i2cget $PSU1_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
psu1_eeprom_num=$((psu1_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
psu1_eeprom_num=$((psu1_eeprom_num))
fi
psu2_eeprom_num=0
i2cget $PSU2_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
psu2_eeprom_num=$((psu2_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
psu2_eeprom_num=$((psu2_eeprom_num))
fi
}
catpsufanspeed(){
psu1_rpm_normal_num=0
psu1_rpm=`cat $PSU1_FAN_RPM`
if [ "${psu1_rpm}" -ne "960" ] && [ "${psu1_rpm}" -ne "0" ]; then
psu1_rpm_normal_num=$((psu1_rpm_normal_num+1))
elif [ "${psu1_rpm}" -eq "960" ] || [ "${psu1_rpm}" -eq "0" ]; then
psu1_rpm_normal_num=$((psu1_rpm_normal_num))
fi
psu2_rpm_normal_num=0
psu2_rpm=`cat $PSU2_FAN_RPM`
if [ "${psu2_rpm}" -ne "960" ] && [ "${psu2_rpm}" -ne "0" ]; then
psu2_rpm_normal_num=$((psu2_rpm_normal_num+1))
elif [ "${psu2_rpm}" -eq "960" ] || [ "${psu2_rpm}" -eq "0" ]; then
psu2_rpm_normal_num=$((psu2_rpm_normal_num))
fi
}
setfanled(){
if [ "${fan_eeprom_num}" -eq "5" ] && [ "${fan_rpm_normal_num}" -eq "5" ]; then
echo "fan_green" > $LED_CONTROL
elif [ "${fan_eeprom_num}" -lt "5" ] || [ "${fan_rpm_normal_num}" -lt "5" ]; then
echo "fan_amber" > $LED_CONTROL
fi
}
setpsuled(){
if [ "${psu1_eeprom_num}" -eq "1" ] && [ "${psu1_rpm_normal_num}" -eq "1" ]; then
echo "pwr1_green" > $LED_CONTROL
elif [ "${psu1_eeprom_num}" -eq "0" ] || [ "${psu1_rpm_normal_num}" -eq "0" ]; then
echo "pwr1_amber" > $LED_CONTROL
fi
if [ "${psu2_eeprom_num}" -eq "1" ] && [ "${psu2_rpm_normal_num}" -eq "1" ]; then
echo "pwr2_green" > $LED_CONTROL
elif [ "${psu2_eeprom_num}" -eq "0" ] || [ "${psu2_rpm_normal_num}" -eq "0" ]; then
echo "pwr2_amber" > $LED_CONTROL
fi
}
setfantrayled(){
if [ "${fan1_rpm_normal_num}" -eq "1" ]; then
echo "fan1_green" > $LED_CONTROL
else
echo "fan1_red" > $LED_CONTROL
fi
if [ "${fan2_rpm_normal_num}" -eq "1" ]; then
echo "fan2_green" > $LED_CONTROL
else
echo "fan2_red" > $LED_CONTROL
fi
if [ "${fan3_rpm_normal_num}" -eq "1" ]; then
echo "fan3_green" > $LED_CONTROL
else
echo "fan3_red" > $LED_CONTROL
fi
if [ "${fan4_rpm_normal_num}" -eq "1" ]; then
echo "fan4_green" > $LED_CONTROL
else
echo "fan4_red" > $LED_CONTROL
fi
if [ "${fan5_rpm_normal_num}" -eq "1" ]; then
echo "fan5_green" > $LED_CONTROL
else
echo "fan5_red" > $LED_CONTROL
fi
}
platformstatus(){
echo "sys_green" > $LED_CONTROL
catfaneeprom
catfanspeed
setfanled
setfantrayled
catpsueeprom
catpsufanspeed
setpsuled
}
while true
do
platformstatus
sleep 1
done

View File

@ -0,0 +1,5 @@
sonic-delta-platform-modules (1.1) unstable; urgency=low
* Initial release
-- Neal Tai <neal.tai@deltaww.com> Fri, 21 APR 2017 11:11:11 -0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,11 @@
Source: sonic-delta-platform-modules
Section: main
Priority: extra
Maintainer: Neal Tai <neal.tai@deltaww.com>
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
Package: platform-modules-ag9032v1
Architecture: amd64
Depends: linux-image-3.16.0-4-amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -0,0 +1 @@
platform-modules-ag9032v1_1.1_amd64.deb main extra

View File

@ -0,0 +1,49 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup ag9032v1 board.
### END INIT INFO
case "$1" in
start)
echo -n "Setting up board... "
depmod -a
rmmod i2c-i801
rmmod i2c-ismt
modprobe i2c-dev
modprobe i2c-i801
modprobe i2c-ismt
modprobe i2c-mux-pca954x
modprobe dni_ag9032v1_psu
modprobe dni_emc2305
modprobe at24
modprobe delta_ag9032v1_platform
/usr/local/bin/ag9032v1_platform_init.sh
echo "done."
;;
stop)
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-ag9032v1.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,3 @@
ag9032v1/scripts/ag9032v1_platform_init.sh usr/local/bin
ag9032v1/scripts/led_status.sh usr/local/bin
ag9032v1/cfg/ag9032v1-modules.conf etc/modules-load.d

View File

@ -0,0 +1,33 @@
#!/usr/bin/make -f
export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= ag9032v1
%:
dh $@
override_dh_auto_build:
(for mod in $(MODULE_DIRS); do \
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
done)
override_dh_auto_install:
(for mod in $(MODULE_DIRS); do \
dh_installdirs -pplatform-modules-$${mod} \
$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \
debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
done)
override_dh_usrlocal:
override_dh_clean:
dh_clean
(for mod in $(MODULE_DIRS); do \
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \
done)