[device]: Add a new supported device, Delta-ag5648 (#1470)

* [platform]: Add a new supported platform, Delta-ag5648

            CPU : Intel Rangeley C2538
            Swich ASIC: Broadcom Tomahawk BCM56967
            Ports : 48x25G + 6x100G
            Switch SKU : Delta-ag5648

Signed-off-by: neal tai <neal.tai@deltaww.com>

* Delete the file

Delete the auto-generated file.

* [device]: ag5648 remove all *.cmd files.
          remove the files under ag5648/modules

Signed-off-by: neal tai <neal.tai@deltaww.com>

* [device]: ag5648 device drivers
          1. Use the common driver dni_emc2305.c

          ag9032v1 device drivers
          1. Move dni_emc2305.c to be the common driver
          2. Remove at24.c

Signed-off-by: neal tai <neal.tai@deltaww.com>
This commit is contained in:
nealtai 2018-03-24 06:17:41 +08:00 committed by lguohan
parent dba35eebb1
commit 830e1dd560
30 changed files with 4850 additions and 1083 deletions

View File

@ -0,0 +1,55 @@
# name lanes alias
Ethernet0 65 twentyfiveGigE1
Ethernet4 66 twentyfiveGigE2
Ethernet8 67 twentyfiveGigE3
Ethernet12 68 twentyfiveGigE4
Ethernet16 69 twentyfiveGigE5
Ethernet20 70 twentyfiveGigE6
Ethernet24 71 twentyfiveGigE7
Ethernet28 72 twentyfiveGigE8
Ethernet32 81 twentyfiveGigE9
Ethernet36 82 twentyfiveGigE10
Ethernet40 83 twentyfiveGigE11
Ethernet44 84 twentyfiveGigE12
Ethernet48 85 twentyfiveGigE13
Ethernet52 86 twentyfiveGigE14
Ethernet56 87 twentyfiveGigE15
Ethernet60 88 twentyfiveGigE16
Ethernet64 33 twentyfiveGigE17
Ethernet68 34 twentyfiveGigE18
Ethernet72 35 twentyfiveGigE19
Ethernet76 36 twentyfiveGigE20
Ethernet80 37 twentyfiveGigE21
Ethernet84 38 twentyfiveGigE22
Ethernet88 39 twentyfiveGigE23
Ethernet92 40 twentyfiveGigE24
Ethernet96 42 twentyfiveGigE25
Ethernet100 41 twentyfiveGigE26
Ethernet104 44 twentyfiveGigE27
Ethernet108 43 twentyfiveGigE28
Ethernet112 49 twentyfiveGigE29
Ethernet116 50 twentyfiveGigE30
Ethernet120 51 twentyfiveGigE31
Ethernet124 52 twentyfiveGigE32
Ethernet128 53 twentyfiveGigE33
Ethernet132 54 twentyfiveGigE34
Ethernet136 55 twentyfiveGigE35
Ethernet140 56 twentyfiveGigE36
Ethernet144 97 twentyfiveGigE37
Ethernet148 98 twentyfiveGigE38
Ethernet152 99 twentyfiveGigE39
Ethernet156 100 twentyfiveGigE40
Ethernet160 101 twentyfiveGigE41
Ethernet164 102 twentyfiveGigE42
Ethernet168 103 twentyfiveGigE43
Ethernet172 104 twentyfiveGigE44
Ethernet176 105 twentyfiveGigE45
Ethernet180 106 twentyfiveGigE46
Ethernet184 107 twentyfiveGigE47
Ethernet188 108 twentyfiveGigE48
Ethernet192 117,118,119,120 hundredGigE51
Ethernet196 109,110,111,112 hundredGigE51
Ethernet200 5,6,7,8 hundredGigE51
Ethernet204 1,2,3,4 hundredGigE52
Ethernet208 21,22,23,24 hundredGigE53
Ethernet212 9,10,11,12 hundredGigE54

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/etc/bcm/th-ag5648-48x25G+6x100G.config.bcm

View File

@ -0,0 +1,10 @@
INTERVAL=10
DEVPATH=hwmon1=/sys/bus/i2c/devices
DEVNAME=hwmon1=emc2305
FCTEMPS=DEVPATH/2-004d/hwmon/hwmon*/temp1_input DEVPATH/3-0049/hwmon/hwmon*/temp1_input DEVPATH/3-004b/hwmon/hwmon*/temp1_input DEVPATH/3-004c/hwmon/hwmon*/temp1_input DEVPATH/3-004e/hwmon/hwmon*/temp1_input DEVPATH/3-004f/hwmon/hwmon*/temp1_input DEVPATH/6-0059/temp1_input DEVPATH/6-0058/temp1_input
FCFANS=DEVPATH/3-004d/fan1_input DEVPATH/3-004d/fan2_input DEVPATH/3-004d/fan3_input DEVPATH/3-004d/fan4_input DEVPATH/5-004d/fan1_input DEVPATH/5-004d/fan2_input DEVPATH/5-004d/fan3_input DEVPATH/5-004d/fan4_input
MINTEMP=20
MAXTEMP=60
MINSTART=75
MINSTOP=22

View File

@ -0,0 +1,262 @@
#!/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.service [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 "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/DEVPATH/\/sys\/bus\/i2c\/devices/g' )
AFCTEMP_PATH[$fcvcount]=$( echo "${AFCTEMP[$fcvcount]}" | sed 's/DEVPATH/\/sys\/bus\/i2c\/devices/g' )
#if [ $fcvcount -eq 5 ];then
#echo "0x00" > '/sys/bus/i2c/devices/6-0058/psu_select_member'
# AFCTEMP[$fcvcount]=$( cat ${AFCTEMP[$fcvcount]} )
#elif [ $fcvcount -eq 6 ];then
#echo "0x20" > '/sys/bus/i2c/devices/6-0058/psu_select_member'
# AFCTEMP[$fcvcount]=$( cat ${AFCTEMP[$fcvcount]} )
#else
# AFCTEMP[$fcvcount]=$( cat ${AFCTEMP[$fcvcount]} )
#fi
AFCTEMP[$fcvcount]=$( cat ${AFCTEMP[$fcvcount]} )
AFCTEMP[$fcvcount]=$(( AFCTEMP[$fcvcount]/1000 ))
echo "AFCTEMP[$fcvcount]=${AFCTEMP[$fcvcount]} (Celsius)"
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/DEVPATH/\/sys\/bus\/i2c\/devices/g' )
AFCFAN_TARGET[$fcvcount]=$( echo "${AFCFAN_PATH[$fcvcount]}" | sed 's/DEVPATH/\/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
echo "AFCFAN[$fcvcount]=${AFCFAN[$fcvcount]} (rpm)"
done
echo "INTERVAL=$INTERVAL"
echo "DEVPATH=$FCDEVPATH"
echo "MINTEMP=$FCMINTEMP"
echo "MAXTEMP=$FCMAXTEMP"
echo "MINSTART=$FCMINSTART"
echo "MINSTOP=$FCMINSTOP"
}
# 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
echo "AFCFAN[$fcvcount]=${AFCFAN[$fcvcount]} (rpm)"
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/6-0059/fan1_set_percentage'
echo "PSU fan1 =$( cat '/sys/bus/i2c/devices/6-0059/fan1_input' ) (rpm)"
#Set speed to PSU_FAN2
#echo "0x20" > '/sys/bus/i2c/devices/6-0058/psu_select_member'
echo "$FAN_ON_PSU_PERCENTAGE" > '/sys/bus/i2c/devices/6-0058/fan1_set_percentage'
echo "PSU fan2 =$( cat '/sys/bus/i2c/devices/6-0058/fan1_input' ) (rpm)"
rm -f "$PIDFILE"
}
# main loop calling the main function at specified intervals
while true
do
UpdateThermalSensors
UpdateFanSpeeds
echo "Sleep $INTERVAL seconds ..."
# Sleep while still handling signals
sleep $INTERVAL &
wait $!
done

View File

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

View File

@ -0,0 +1,67 @@
#AG5648 LED
led 0 stop
led 0 prog \
02 00 60 E0 02 A0 60 E2 86 ED 02 00 60 E1 67 EF \
71 1F 2E E0 32 08 97 02 00 0E 02 60 E3 77 2A 2E \
E0 32 08 97 02 00 0E 03 60 E3 2E E0 32 00 32 01 \
B7 97 02 00 0E 00 12 E7 FE E1 50 67 EF 71 49 86 \
E0 86 E1 06 E1 D2 04 74 2A 02 00 60 E1 12 E7 FE \
E1 05 60 EC 12 E3 FE E1 05 0A 03 71 61 67 EB 77 \
63 67 CB 67 EF 71 76 12 E3 FE E1 05 0A 02 71 74 \
67 EB 77 76 67 CB 12 E3 FE E1 05 0A 01 71 87 67 \
EB 67 EF 71 97 77 8D 67 CB 67 EF 71 97 86 E1 06 \
E1 D2 04 74 4D 77 A5 06 E0 28 32 08 97 71 A3 67 \
EB 77 A5 67 D7 06 E2 67 EF 71 B1 F2 04 60 E2 77 \
B7 F2 01 60 E2 86 E0 06 E0 D2 24 74 0A 67 EB 67 \
EB 67 EB 67 EB 67 EB 67 EB 3A 72 67 EF 71 E7 06 \
EC D2 00 70 E7 77 DD 06 EC D2 00 70 EB 16 ED 99 \
99 1A 00 71 E7 77 EB 32 0F 87 57 32 0E 87 57 16 \
E0 DA 0C 57 00 00 00 00 00 00 00 00 00 00 00 00
led 0 auto on
led 0 start
led 1 stop
led 1 prog \
02 00 60 E0 02 A0 60 E2 86 E6 02 00 60 E1 2E E0 \
32 08 97 02 00 0E 03 60 E3 2E E0 32 00 32 01 B7 \
97 02 00 0E 00 12 E4 FE E1 50 12 E4 05 60 E5 12 \
E3 05 0A 03 71 3A 67 83 77 3C 67 7F 12 E3 05 0A \
01 71 47 67 83 77 49 67 7F 06 E0 28 32 08 97 71 \
55 67 83 77 57 67 6F 06 E2 F2 01 60 E2 86 E0 06 \
E0 D2 24 74 0A 67 83 67 83 67 83 67 83 3A 70 06 \
E5 D2 00 70 83 16 E6 99 99 1A 00 71 7F 77 83 32 \
0F 87 57 32 0E 87 57 00 00 00 00 00 00 00 00 00
led 1 auto on
led 1 start
# LED0 port order remap
m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=47 REMAP_PORT_1=47 REMAP_PORT_2=47 REMAP_PORT_3=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=47 REMAP_PORT_5=47 REMAP_PORT_6=47 REMAP_PORT_7=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=31 REMAP_PORT_9=30 REMAP_PORT_10=29 REMAP_PORT_11=28
m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=47 REMAP_PORT_13=47 REMAP_PORT_14=47 REMAP_PORT_15=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 REMAP_PORT_17=47 REMAP_PORT_18=47 REMAP_PORT_19=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=35 REMAP_PORT_21=34 REMAP_PORT_22=33 REMAP_PORT_23=32
m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=23 REMAP_PORT_25=22 REMAP_PORT_26=21 REMAP_PORT_27=20
m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=27 REMAP_PORT_29=26 REMAP_PORT_30=25 REMAP_PORT_31=24
m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=47 REMAP_PORT_33=47 REMAP_PORT_34=47 REMAP_PORT_35=47
m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=15 REMAP_PORT_41=14 REMAP_PORT_42=13 REMAP_PORT_43=12
m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=19 REMAP_PORT_49=18 REMAP_PORT_50=17 REMAP_PORT_51=16
m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 REMAP_PORT_53=10 REMAP_PORT_54=9 REMAP_PORT_55=8
m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 REMAP_PORT_57=6 REMAP_PORT_58=5 REMAP_PORT_59=4
m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 REMAP_PORT_61=2 REMAP_PORT_62=1 REMAP_PORT_63=0
# LED1 port order remap
m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=19 REMAP_PORT_1=18 REMAP_PORT_2=17 REMAP_PORT_3=16
m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=23 REMAP_PORT_5=22 REMAP_PORT_6=21 REMAP_PORT_7=20
m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=26 REMAP_PORT_9=27 REMAP_PORT_10=24 REMAP_PORT_11=25
m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 REMAP_PORT_13=63 REMAP_PORT_14=63 REMAP_PORT_15=63
m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=31 REMAP_PORT_17=30 REMAP_PORT_18=29 REMAP_PORT_19=28
m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=35 REMAP_PORT_21=34 REMAP_PORT_22=33 REMAP_PORT_23=32
m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=63 REMAP_PORT_25=63 REMAP_PORT_26=63 REMAP_PORT_27=63
m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=63 REMAP_PORT_29=63 REMAP_PORT_30=63 REMAP_PORT_31=63
m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=3 REMAP_PORT_33=2 REMAP_PORT_34=1 REMAP_PORT_35=0
m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=7 REMAP_PORT_37=6 REMAP_PORT_38=5 REMAP_PORT_39=4
m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=11 REMAP_PORT_49=10 REMAP_PORT_50=9 REMAP_PORT_51=8
m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=15 REMAP_PORT_53=14 REMAP_PORT_54=13 REMAP_PORT_55=12

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#############################################################################
# Mellanox
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
import exceptions
import binascii
import time
import optparse
import warnings
import os
import sys
from sonic_eeprom import eeprom_base
from sonic_eeprom import eeprom_tlvinfo
import subprocess
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
_TLV_INFO_MAX_LEN = 256
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-2/2-0053/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,56 @@
import os.path
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.psu_path = "/sys/bus/i2c/devices/6-00{}/"
self.psu_oper_status = "in1_input"
self.psu_presence = "i2cget -y 6 0x{} 0x00"
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
return 2
def get_psu_status(self, index):
if index is None:
return False
Base_bus_number = 57
status = 0
try:
with open(self.psu_path.format(index + Base_bus_number) + self.psu_oper_status, 'r') as power_status:
if int(power_status.read()) == 0 :
return False
else:
status = 1
except IOError:
return False
return status == 1
def get_psu_presence(self, index):
if index is None:
return False
Base_bus_number = 49
status = 0
try:
p = os.popen(self.psu_presence.format(index + Base_bus_number)+ "> /dev/null 2>&1")
if p.readline() != None:
status = 1
p.close()
except IOError:
return False
return status == 1

View File

@ -0,0 +1,203 @@
# 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_START_QSFP = 48
PORT_END = 53
PORTS_IN_BLOCK = 54
EEPROM_OFFSET = 10
_port_to_eeprom_mapping = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_start_qsfp(self):
return self.PORT_START_QSFP
@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):
if x > self.port_start_qsfp -1 and x < self.port_end + 1:
self.get_response(x)
self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET)
SfpUtilBase.__init__(self)
def get_response(self, port_num):
# Check for invalid port_num
if port_num < self.port_start_qsfp or port_num > self.port_end:
return False
try:
reg_file = open("/sys/devices/platform/delta-ag5648-cpld.0/sfp_response", "r+")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
# set the bit corresponding to our port
mask = (port_num + 1) % 8 - 1
mask = 1 << mask
# Convert our register value back to a hex string and write back
content = hex(mask)
reg_file.seek(0)
reg_file.write(content)
reg_file.close()
return True
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-ag5648-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-ag5648-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_qsfp or port_num > self.port_end:
return False
try:
reg_file = open("/sys/devices/platform/delta-ag5648-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-ag5648-cpld.0/sfp_reset"
# Check for invalid port_num
if port_num < self.port_start_qsfp or port_num > self.port_end:
return False
try:
reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = reg_file.readline().rstrip()
# File content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# ResetL is active low
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
reg_file.seek(0)
reg_file.write(hex(reg_value))
reg_file.close()
# Sleep 1 second to allow it to settle
time.sleep(1)
# Flip the bit back high and write back to the register to take port out of reset
try:
reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "w")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
reg_value = reg_value | mask
reg_file.seek(0)
reg_file.write(hex(reg_value))
reg_file.close()
return True

View File

@ -0,0 +1,91 @@
# libsensors configuration file for AG5648
# ------------------------------------------------
#
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-5" "i2c-1-mux (chan_id 3)"
bus "i2c-6" "i2c-1-mux (chan_id 4)"
bus "i2c-7" "i2c-1-mux (chan_id 5)"
# tmp75-i2c-2-4d board sensor near Left of front vents.
# tmp75-i2c-3-49 board sensor near MAC.
# tmp75-i2c-3-4b board sensor near Middle of front vents.
# tmp75-i2c-3-4c board sensor near Right of front vents.
# tmp75-i2c-3-4e board sensor near DC fan.
# tmp75-i2c-3-4f board sensor near CPU.
chip "tmp75-i2c-2-4d"
label temp1 "board sensor near Left of front vents"
set temp1_max 60
set temp1_max_hyst 55
chip "tmp75-i2c-3-49"
label temp1 "board sensor near MAC"
set temp1_max 85
set temp1_max_hyst 80
chip "tmp75-i2c-3-4b"
label temp1 "board sensor near Middle of front vents"
set temp1_max 70
set temp1_max_hyst 65
chip "tmp75-i2c-3-4c"
label temp1 "board sensor near Right of front vents"
set temp1_max 65
set temp1_max_hyst 60
chip "tmp75-i2c-3-4e"
label temp1 "board sensor near DC fan"
set temp1_max 60
set temp1_max_hyst 55
chip "tmp75-i2c-3-4f"
label temp1 "board sensor near CPU"
set temp1_max 80
set temp1_max_hyst 75
chip "emc2305-i2c-3-4d"
label fan1 "FANTRAY 1 REAR"
label fan2 "FANTRAY 2 REAR"
label fan3 "FANTRAY 3 REAR"
label fan4 "FANTRAY 4 REAR"
chip "emc2305-i2c-5-4d"
label fan1 "FANTRAY 1 FRONT"
label fan2 "FANTRAY 2 FRONT"
label fan3 "FANTRAY 3 FRONT"
label fan4 "FANTRAY 4 FRONT"
chip "ltc4215-i2c-3-40"
label in1 "PSU Hot-Swap voltage 1"
label in2 "PSU Hot-Swap voltage 2"
label power1 "PSU Hot-Swap power"
label curr1 "PSU Hot-Swap current"
chip "ltc4215-i2c-3-42"
label in1 "PSU Hot-Swap voltage 1"
label in2 "PSU Hot-Swap voltage 2"
label power1 "PSU Hot-Swap power"
label curr1 "PSU Hot-Swap current"
chip "dni_ag5648_psu-i2c-6-59"
label in1 "PSU voltage 1"
label in2 "PSU voltage 2"
label fan1 "PSU fan"
label temp1 "PSU temperature"
label power1 "PSU power1"
label power2 "PSU power2"
label curr1 "PSU current1"
label curr2 "PSU current2"
chip "dni_ag5648_psu-i2c-6-58"
label in1 "PSU voltage 1"
label in2 "PSU voltage 2"
label fan1 "PSU fan"
label temp1 "PSU temperature"
label power1 "PSU power1"
label power2 "PSU power2"
label curr1 "PSU current1"
label curr2 "PSU current2"

View File

@ -24,6 +24,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(CEL_DX010_PLATFORM_MODULE) \
$(DELTA_AG9032V1_PLATFORM_MODULE) \
$(DELTA_AG9064_PLATFORM_MODULE) \
$(DELTA_AG5648_PLATFORM_MODULE) \
$(QUANTA_IX1B_32X_PLATFORM_MODULE) \
$(MITAC_LY1200_32X_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)

View File

@ -2,9 +2,11 @@
DELTA_AG9032V1_PLATFORM_MODULE_VERSION = 1.1
DELTA_AG9064_PLATFORM_MODULE_VERSION = 1.1
DELTA_AG5648_PLATFORM_MODULE_VERSION = 1.1
export DELTA_AG9032V1_PLATFORM_MODULE_VERSION
export DELTA_AG9064_PLATFORM_MODULE_VERSION
export DELTA_AG5648_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
@ -16,3 +18,8 @@ SONIC_DPKG_DEBS += $(DELTA_AG9032V1_PLATFORM_MODULE)
DELTA_AG9064_PLATFORM_MODULE = platform-modules-ag9064_$(DELTA_AG9064_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELTA_AG9064_PLATFORM_MODULE)_PLATFORM = x86_64-delta_ag9064-r0
$(eval $(call add_extra_package,$(DELTA_AG9032V1_PLATFORM_MODULE),$(DELTA_AG9064_PLATFORM_MODULE)))
DELTA_AG5648_PLATFORM_MODULE = platform-modules-ag5648_$(DELTA_AG5648_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELTA_AG5648_PLATFORM_MODULE)_PLATFORM = x86_64-delta_ag5648-r0
$(eval $(call add_extra_package,$(DELTA_AG9032V1_PLATFORM_MODULE),$(DELTA_AG5648_PLATFORM_MODULE)))

View File

@ -0,0 +1,13 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-i801
i2c-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-gpio
i2c-mux-pca954x

View File

@ -0,0 +1,2 @@
obj-m := dni_ag5648_psu.o dni_emc2305.o delta_ag5648_platform.o

View File

@ -0,0 +1,552 @@
/*
* An hwmon driver for delta AG5648 PSU
* dps_800ab_16_d.c - Support for DPS-800AB-16 D Power Supply Module
*
* Copyright (C) 2016 Delta Network Technology Corporation
*
* DNI <DNIsales@delta.com.tw>
*
* 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[] = { 0x59, 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[14];
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 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},
{0x97, &data->power1_input},
{0x96, &data->power2_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;
data->in1_input = 0;
data->in2_input = 0;
data->curr1_input = 0;
data->curr2_input = 0;
data->power1_input = 0;
data->power2_input = 0;
data->temp_input[0] = 0;
data->temp_input[1] = 0;
data->fan_duty_cycle_input[0] = 0;
data->fan_speed_input[0] = 0;
data->mfr_model[0] = '\0';
data->mfr_serial[0] = '\0';
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);
}
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_ag5648_psu,
dps_800ab_16_d
};
static const struct i2c_device_id dps_800ab_16_d_id[] = {
{ "dni_ag5648_psu", dni_ag5648_psu },
{ "dps_800ab_16_d", dps_800ab_16_d },
{}
};
MODULE_DEVICE_TABLE(i2c, dps_800ab_16_d_id);
/* This is the driver that will be inserted */
static struct i2c_driver dps_800ab_16_d_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "dps_800ab_16_d",
},
.probe = dps_800ab_16_d_probe,
.remove = dps_800ab_16_d_remove,
.id_table = dps_800ab_16_d_id,
.address_list = normal_i2c,
};
static int __init dps_800ab_16_d_init(void)
{
return i2c_add_driver(&dps_800ab_16_d_driver);
}
static void __exit dps_800ab_16_d_exit(void)
{
i2c_del_driver(&dps_800ab_16_d_driver);
}
MODULE_AUTHOR("Aries Lin <aries.lin@deltaww.com>");
MODULE_DESCRIPTION("DPS_800AB_16_D Driver");
MODULE_LICENSE("GPL");
module_init(dps_800ab_16_d_init);
module_exit(dps_800ab_16_d_exit);

View File

@ -0,0 +1 @@
../../common/modules/dni_emc2305.c

View File

@ -0,0 +1,13 @@
#!/bin/bash
#platform init script for Delta ag5648
#fan speed monitor start
/usr/share/sonic/device/x86_64-delta_ag5648-r0/fancontrol.service /usr/share/sonic/device/x86_64-delta_ag5648-r0/fancontrol &
#led control
/usr/local/bin/led_control &
exit 0

View File

@ -0,0 +1,221 @@
#!/bin/bash
FAN1_EEPROM="-y 3 0x51 0x0a"
FAN2_EEPROM="-y 3 0x52 0x0a"
FAN3_EEPROM="-y 3 0x53 0x0a"
FAN4_EEPROM="-y 3 0x54 0x0a"
LED_CONTROL="/sys/devices/platform/delta-ag5648-cpld.0/led_control"
FAN1_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/3-004d/fan1_input"
FAN2_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/3-004d/fan2_input"
FAN3_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/3-004d/fan3_input"
FAN4_REAR_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-3/3-004d/fan4_input"
FAN1_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-004d/fan1_input"
FAN2_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-004d/fan2_input"
FAN3_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-004d/fan3_input"
FAN4_FRONT_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-5/5-004d/fan4_input"
PSU1_EEPROM="-y 6 0x51 0x00"
PSU2_EEPROM="-y 6 0x50 0x00"
PSU1_FAN_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-6/6-0059/fan1_input"
PSU2_FAN_RPM="/sys/devices/pci0000:00/0000:00:13.0/i2c-1/i2c-6/6-0058/fan1_input"
catfaneeprom(){
fan_eeprom_num=0
fan1_eeprom_num=0
i2cget $FAN1_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan1_eeprom_num=$((fan1_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan1_eeprom_num=$((fan1_eeprom_num))
fi
fan2_eeprom_num=0
i2cget $FAN2_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan2_eeprom_num=$((fan2_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan2_eeprom_num=$((fan2_eeprom_num))
fi
fan3_eeprom_num=0
i2cget $FAN3_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan3_eeprom_num=$((fan3_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan3_eeprom_num=$((fan3_eeprom_num))
fi
fan4_eeprom_num=0
i2cget $FAN4_EEPROM > /dev/null 2>&1
if [ "`echo $?`" -eq "0" ]; then
fan4_eeprom_num=$((fan4_eeprom_num+1))
elif [ "`echo $?`" -eq "2" ]; then
fan4_eeprom_num=$((fan4_eeprom_num))
fi
fan_eeprom_num=$((fan1_eeprom_num+fan2_eeprom_num+fan3_eeprom_num+fan4_eeprom_num))
}
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
fan_rpm_normal_num=$((fan1_rpm_normal_num+fan2_rpm_normal_num+fan3_rpm_normal_num+fan4_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 "4" ] && [ "${fan_rpm_normal_num}" -eq "4" ]; then
echo "fan_green" > $LED_CONTROL
elif [ "${fan_eeprom_num}" -lt "4" ] && [ "${fan_rpm_normal_num}" -eq "4" ]; then
echo "fan_Amber" > $LED_CONTROL
elif [ "${psu1_eeprom_num}" -eq "0" ] && [ "${psu2_eeprom_num}" -eq "0" ]; then
echo "fan_off" > $LED_CONTROL
else
echo "fan_Blinking_yellow" > $LED_CONTROL
fi
}
setpsuled(){
if [ "${psu1_rpm_normal_num}" -eq "1" ] && [ "${psu2_rpm_normal_num}" -eq "1" ]; then
echo "pwr_green" > $LED_CONTROL
elif [ "${psu1_eeprom_num}" -eq "1" ] && [ "${psu2_eeprom_num}" -eq "1" ]; then
echo "pwr_Blinking_Amber" > $LED_CONTROL
elif [ "${psu1_eeprom_num}" -eq "0" ] || [ "${psu2_eeprom_num}" -eq "0" ]; then
echo "pwr_Amber" > $LED_CONTROL
else
echo "pwr_off" > $LED_CONTROL
fi
}
setfantrayled(){
if [ "${fan1_rpm_normal_num}" -eq "1" ]; then
echo "fan1_green" > $LED_CONTROL
elif [ "${fan1_eeprom_num}" -eq "1" ]; then
echo "fan1_Amber" > $LED_CONTROL
else
echo "fan1_off" > $LED_CONTROL
fi
if [ "${fan2_rpm_normal_num}" -eq "1" ]; then
echo "fan2_green" > $LED_CONTROL
elif [ "${fan2_eeprom_num}" -eq "1" ]; then
echo "fan2_Amber" > $LED_CONTROL
else
echo "fan2_off" > $LED_CONTROL
fi
if [ "${fan3_rpm_normal_num}" -eq "1" ]; then
echo "fan3_green" > $LED_CONTROL
elif [ "${fan3_eeprom_num}" -eq "1" ]; then
echo "fan3_Amber" > $LED_CONTROL
else
echo "fan3_off" > $LED_CONTROL
fi
if [ "${fan4_rpm_normal_num}" -eq "1" ]; then
echo "fan4_green" > $LED_CONTROL
elif [ "${fan4_eeprom_num}" -eq "1" ]; then
echo "fan4_Amber" > $LED_CONTROL
else
echo "fan4_off" > $LED_CONTROL
fi
}
platformstatus(){
echo "sys_green" > $LED_CONTROL
catfaneeprom
catfanspeed
setfanled
setfantrayled
catpsueeprom
catpsufanspeed
setpsuled
}
while true
do
platformstatus
sleep 5
done

View File

@ -0,0 +1,94 @@
# libsensors configuration file for AG5648
# ------------------------------------------------
#
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-5" "i2c-1-mux (chan_id 3)"
bus "i2c-6" "i2c-1-mux (chan_id 4)"
bus "i2c-7" "i2c-1-mux (chan_id 5)"
# tmp75-i2c-2-4d board sensor near Left of front vents.
# tmp75-i2c-3-49 board sensor near MAC.
# tmp75-i2c-3-4b board sensor near Middle of front vents.
# tmp75-i2c-3-4c board sensor near Right of front vents.
# tmp75-i2c-3-4e board sensor near DC fan.
# tmp75-i2c-3-4f board sensor near CPU.
chip "tmp75-i2c-*-4d"
label temp1 "board sensor near Left of front vents"
set temp1_max 60
set temp1_max_hyst 55
chip "tmp75-i2c-*-49"
label temp1 "board sensor near MAC"
set temp1_max 85
set temp1_max_hyst 80
chip "tmp75-i2c-*-4b"
label temp1 "board sensor near Middle of front vents"
set temp1_max 70
set temp1_max_hyst 65
chip "tmp75-i2c-*-4c"
label temp1 "board sensor near Right of front vents"
set temp1_max 65
set temp1_max_hyst 60
chip "tmp75-i2c-*-4e"
label temp1 "board sensor near DC fan"
set temp1_max 60
set temp1_max_hyst 55
chip "tmp75-i2c-*-4f"
label temp1 "board sensor near CPU"
set temp1_max 80
set temp1_max_hyst 75
chip "emc2305-i2c-3-4d"
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-5-4d"
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 "ltc4215-i2c-*-40"
label in1 "PSU Hot-Swap voltage 1"
label in2 "PSU Hot-Swap voltage 2"
label power1 "PSU Hot-Swap power"
label curr1 "PSU Hot-Swap current"
chip "ltc4215-i2c-*-42"
label in1 "PSU Hot-Swap voltage 1"
label in2 "PSU Hot-Swap voltage 2"
label power1 "PSU Hot-Swap power"
label curr1 "PSU Hot-Swap current"
chip "dni_ag5648_psu-i2c-*-59"
label in1 "PSU voltage 1"
label in2 "PSU voltage 2"
label fan1 "PSU fan"
label temp1 "PSU temperature"
label power1 "PSU power1"
label power2 "PSU power2"
label curr1 "PSU current1"
label curr2 "PSU current2"
chip "dni_ag5648_psu-i2c-*-58"
label in1 "PSU voltage 1"
label in2 "PSU voltage 2"
label fan1 "PSU fan"
label temp1 "PSU temperature"
label power1 "PSU power1"
label power2 "PSU power2"
label curr1 "PSU current1"
label curr2 "PSU current2"

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
../../common/modules/dni_emc2305.c

View File

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

View File

@ -14,3 +14,8 @@ Package: platform-modules-ag9064
Architecture: amd64
Depends: linux-image-3.16.0-5-amd64
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-ag5648
Architecture: amd64
Depends: linux-image-3.16.0-5-amd64
Description: kernel modules for platform devices such as fan, led, sfp

View File

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

View File

@ -0,0 +1,49 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup ag5648 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_ag5648_psu
modprobe dni_emc2305
modprobe at24
modprobe delta_ag5648_platform
/usr/local/bin/ag5648_platform_init.sh
echo "done."
;;
stop)
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-ag5648.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,3 @@
ag5648/scripts/ag5648_platform_init.sh usr/local/bin
ag5648/cfg/ag5648-modules.conf etc/modules-load.d
ag5648/scripts/led_control usr/local/bin

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= ag9032v1 ag9064
MODULE_DIRS:= ag9032v1 ag9064 ag5648
%:
dh $@