[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:
parent
98fbddf60f
commit
8602360ffd
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
SAI_INIT_CONFIG_FILE=/etc/bcm/th-ag9032v1-32x100G.config.bcm
|
10
device/delta/x86_64-delta_ag9032v1-r0/fancontrol
Normal file
10
device/delta/x86_64-delta_ag9032v1-r0/fancontrol
Normal 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
|
244
device/delta/x86_64-delta_ag9032v1-r0/fancontrol.service
Executable file
244
device/delta/x86_64-delta_ag9032v1-r0/fancontrol.service
Executable 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
|
2
device/delta/x86_64-delta_ag9032v1-r0/installer.conf
Normal file
2
device/delta/x86_64-delta_ag9032v1-r0/installer.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CONSOLE_PORT=0x3f8
|
||||||
|
CONSOLE_SPEED=115200
|
45
device/delta/x86_64-delta_ag9032v1-r0/led_proc_init.soc
Normal file
45
device/delta/x86_64-delta_ag9032v1-r0/led_proc_init.soc
Normal 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
|
||||||
|
|
1079
device/delta/x86_64-delta_ag9032v1-r0/minigraph.xml
Normal file
1079
device/delta/x86_64-delta_ag9032v1-r0/minigraph.xml
Normal file
File diff suppressed because it is too large
Load Diff
32
device/delta/x86_64-delta_ag9032v1-r0/plugins/eeprom.py
Normal file
32
device/delta/x86_64-delta_ag9032v1-r0/plugins/eeprom.py
Normal 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)
|
175
device/delta/x86_64-delta_ag9032v1-r0/plugins/sfputil.py
Normal file
175
device/delta/x86_64-delta_ag9032v1-r0/plugins/sfputil.py
Normal 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
|
61
device/delta/x86_64-delta_ag9032v1-r0/sensors.conf
Normal file
61
device/delta/x86_64-delta_ag9032v1-r0/sensors.conf
Normal 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"
|
||||||
|
|
@ -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)
|
||||||
|
12
platform/broadcom/platform-modules-delta.mk
Normal file
12
platform/broadcom/platform-modules-delta.mk
Normal 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)
|
||||||
|
|
@ -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
|
||||||
|
16
platform/broadcom/sonic-platform-modules-delta/LICENSE
Normal file
16
platform/broadcom/sonic-platform-modules-delta/LICENSE
Normal 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.
|
@ -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
|
@ -0,0 +1,2 @@
|
|||||||
|
obj-m := at24.o dni_ag9032v1_psu.o dni_emc2305.o delta_ag9032v1_platform.o
|
||||||
|
|
@ -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");
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
@ -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");
|
@ -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
|
||||||
|
|
225
platform/broadcom/sonic-platform-modules-delta/ag9032v1/scripts/led_status.sh
Executable file
225
platform/broadcom/sonic-platform-modules-delta/ag9032v1/scripts/led_status.sh
Executable 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
|
||||||
|
|
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
9
|
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
platform-modules-ag9032v1_1.1_amd64.deb main extra
|
@ -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
|
@ -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
|
33
platform/broadcom/sonic-platform-modules-delta/debian/rules
Normal file
33
platform/broadcom/sonic-platform-modules-delta/debian/rules
Normal 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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user