Platform Driver Developement Framework (PDDF) (#4756)

This change introduces PDDF which is described here: https://github.com/Azure/SONiC/pull/536

Most of the platform bring up effort goes in developing the platform device drivers, SONiC platform APIs and validating them. Typically each platform vendor writes their own drivers and platform APIs which is very tailor made to that platform. This involves writing code, building, installing it on the target platform devices and testing. Many of the details of the platform are hard coded into these drivers, from the HW spec. They go through this cycle repetitively till everything works fine, and is validated before upstreaming the code.
PDDF aims to make this platform driver and platform APIs development process much simpler by providing a data driven development framework. This is enabled by:

JSON descriptor files for platform data
Generic data-driven drivers for various devices
Generic SONiC platform APIs
Vendor specific extensions for customisation and extensibility

Signed-off-by: Fuzail Khan <fuzail.khan@broadcom.com>
This commit is contained in:
fk410167 2020-11-12 23:52:38 +05:30 committed by GitHub
parent 8d8ed89778
commit a3dd3f55f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 18064 additions and 1 deletions

View File

@ -277,6 +277,7 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in
python \
python-setuptools \
python3-setuptools \
python-jsonschema \
python-apt \
traceroute \
iputils-ping \

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python
try:
import os
import sys
import json
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
#from sonic_eeprom import eeprom_base
from sonic_eeprom import eeprom_tlvinfo
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):
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
# system EEPROM always has device name EEPROM1
self.eeprom_path = pddf_obj.get_path("EEPROM1", "eeprom")
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,202 @@
#!/usr/bin/env python
# Sample pddf_fanutil file
# All the supported FAN SysFS aattributes are
#- fan<idx>_present
#- fan<idx>_direction
#- fan<idx>_input
#- fan<idx>_pwm
#- fan<idx>_fault
# where idx is in the range [1-12]
#
import os.path
import sys
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
import json
try:
from sonic_fan.fan_base import FanBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class FanUtil(FanBase):
"""PDDF generic FAN util class"""
def __init__(self):
FanBase.__init__(self)
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
self.platform = pddf_obj.get_platform()
self.num_fans = (self.platform['num_fantrays'] * self.platform['num_fans_pertray'] )
def get_num_fans(self):
return self.num_fans
def get_presence(self, idx):
# 1 based fan index
if idx<1 or idx>self.num_fans:
print "Invalid fan index %d\n"%idx
return False
attr_name = "fan"+ str(idx) +"_present"
output = pddf_obj.get_attr_name_output("FAN-CTRL", attr_name)
if not output:
return False
mode = output['mode']
presence = output['status'].rstrip()
vmap = plugin_data['FAN']['present'][mode]['valmap']
if presence in vmap:
status = vmap[presence]
else:
status = False
return status
def get_status(self, idx):
# 1 based fan index
if idx<1 or idx>self.num_fans:
print "Invalid fan index %d\n"%idx
return False
speed = self.get_speed(idx)
status = True if (speed != 0) else False
return status
def get_direction(self, idx):
# 1 based fan index
if idx<1 or idx>self.num_fans:
print "Invalid fan index %d\n"%idx
return None
attr = "fan" + str(idx) + "_direction"
output = pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return None
mode = output['mode']
val = output['status']
val = val.rstrip()
vmap = plugin_data['FAN']['direction'][mode]['valmap']
if val in vmap:
direction = vmap[val]
else:
direction = val
return direction
def get_directions(self):
num_fan = self.get_num_fan();
for i in range(1, num_fan+1):
attr = "fan" + str(i) + "_direction"
output = pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return None
mode = output['mode']
val = output['status']
val = val.rstrip()
vmap = plugin_data['FAN']['direction'][mode]['valmap']
direction = vmap[str(val)]
print "FAN-%d direction is %s"%(i, direction)
return 0
def get_speed(self, idx):
# 1 based fan index
if idx<1 or idx>self.num_fans:
print "Invalid fan index %d\n"%idx
return 0
attr = "fan" + str(idx) + "_input"
output = pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return 0
#mode = output['mode']
val = output['status'].rstrip()
if val.isalpha():
return 0
else:
rpm_speed = int(float(val))
return rpm_speed
def get_speeds(self):
num_fan = self.get_num_fan();
ret = "FAN_INDEX\t\tRPM\n"
for i in range(1, num_fan+1):
attr1 = "fan" + str(i) + "_input"
output = pddf_obj.get_attr_name_output("FAN-CTRL", attr1)
if not output:
return ""
#mode = output['mode']
val = output['status'].rstrip()
if val.isalpha():
frpm = 0
else:
frpm = int(val)
ret += "FAN-%d\t\t\t%d\n"%(i, frpm)
return ret
def set_speed(self, val):
if val<0 or val>100:
print "Error: Invalid speed %d. Please provide a valid speed percentage"%val
return False
num_fan = self.num_fans
if 'duty_cycle_to_pwm' not in plugin_data['FAN']:
print "Setting fan speed is not allowed !"
return False
else:
duty_cycle_to_pwm = eval(plugin_data['FAN']['duty_cycle_to_pwm'])
pwm = duty_cycle_to_pwm(val)
print "New Speed: %d%% - PWM value to be set is %d\n"%(val,pwm)
for i in range(1, num_fan+1):
attr = "fan" + str(i) + "_pwm"
node = pddf_obj.get_path("FAN-CTRL", attr)
if node is None:
return False
try:
with open(node, 'w') as f:
f.write(str(pwm))
except IOError:
return False
return True
def dump_sysfs(self):
return pddf_obj.cli_dump_dsysfs('fan')
def get_change_event(self):
"""
TODO: This function need to be implemented
when decide to support monitoring FAN(fand)
on this platform.
"""
raise NotImplementedError

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python
import sys
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
class LedUtil:
color_map = {
"STATUS_LED_COLOR_GREEN" : "on",
"STATUS_LED_COLOR_RED" : "faulty",
"STATUS_LED_COLOR_OFF" : "off"
}
def __init__(self):
global pddf_obj
pddf_obj = pddfparse.PddfParse()
self.path="pddf/devices/led"
self.cur_state_path="pddf/devices/led/cur_state"
def set_status_led(self, led_device_name, color, color_state="SOLID"):
if (not led_device_name in pddf_obj.data.keys()):
status="ERROR: " + led_device_name + " is not configured"
return (status)
if (not color in self.color_map.keys()):
status="ERROR: Invalid color"
return (status)
index=pddf_obj.data[led_device_name]['dev_attr']['index']
pddf_obj.create_attr('device_name', led_device_name, self.path)
pddf_obj.create_attr('index', index, self.path)
pddf_obj.create_attr('color', self.color_map[color], self.cur_state_path)
pddf_obj.create_attr('color_state', color_state, self.cur_state_path)
pddf_obj.create_attr('dev_ops', 'set_status', self.path)
return ("Executed")
def get_status_led(self, led_device_name):
if (not led_device_name in pddf_obj.data.keys()):
status="ERROR: " + led_device_name + " is not configured"
return (status)
index=pddf_obj.data[led_device_name]['dev_attr']['index']
pddf_obj.create_attr('device_name', led_device_name, self.path)
pddf_obj.create_attr('index', index, self.path)
pddf_obj.create_attr('dev_ops', 'get_status', self.path)
color_f="/sys/kernel/" + self.cur_state_path +"/color"
color_state_f="/sys/kernel/" + self.cur_state_path +"/color_state"
try:
with open(color_f, 'r') as f:
color = f.read().strip("\r\n")
with open(color_state_f, 'r') as f:
color_state = f.read().strip("\r\n")
except IOError:
status="ERROR :" + color_f + " open failed"
return (status)
status = "%s-%s:\t%s %s\n"%(led_device_name, index, color, color_state)
return (status)

View File

@ -0,0 +1,272 @@
#!/usr/bin/env python
#
# Sample pddf_psuutil file
#
# All the supported PSU SysFS aattributes are
#- psu_present
#- psu_model_name
#- psu_power_good
#- psu_mfr_id
#- psu_serial_num
#- psu_fan_dir
#- psu_v_out
#- psu_i_out
#- psu_p_out
#- psu_fan1_speed_rpm
#
import os.path
import sys
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
import json
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""PDDF generic PSU util class"""
def __init__(self):
PsuBase.__init__(self)
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
self.platform = pddf_obj.get_platform()
def get_num_psus(self):
return int(self.platform['num_psus'])
def get_psu_status(self, index):
if index is None:
return False
device = "PSU" + "%d"%index
output = pddf_obj.get_attr_name_output(device, "psu_power_good")
if not output:
return False
mode = output['mode']
val = output['status']
val = val.rstrip()
vmap = plugin_data['PSU']['psu_power_good'][mode]['valmap']
if val in vmap:
return vmap[val]
else:
return False
def get_psu_presence(self, index):
if index is None:
return False
status = 0
device = "PSU" + "%d"%index
output = pddf_obj.get_attr_name_output(device, "psu_present")
if not output:
return False
mode = output['mode']
status = output['status']
vmap = plugin_data['PSU']['psu_present'][mode]['valmap']
if status.rstrip('\n') in vmap:
return vmap[status.rstrip('\n')]
else:
return False
def get_powergood_status(self, idx):
if idx is None:
return False
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return False
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_power_good")
if not output:
return False
mode = output['mode']
status = output ['status']
vmap = plugin_data['PSU']['psu_power_good'][mode]['valmap']
if status.rstrip('\n') in vmap:
return vmap[status.rstrip('\n')]
else:
return False
def get_model(self, idx):
if idx is None:
return None
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return None
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_model_name")
if not output:
return None
model = output['status']
# strip_non_ascii
stripped = (c for c in model if 0 < ord(c) < 127)
model = ''.join(stripped)
return model.rstrip('\n')
def get_mfr_id(self, idx):
if idx is None:
return None
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return None
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_mfr_id")
if not output:
return None
mfr = output['status']
return mfr.rstrip('\n')
def get_serial(self, idx):
if idx is None:
return None
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return None
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_serial_num")
if not output:
return None
serial = output['status']
return serial.rstrip('\n')
def get_direction(self, idx):
if idx is None:
return None
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return None
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_fan_dir")
if not output:
return None
mode = output['mode']
direction = output['status'].rstrip('\n')
vmap = plugin_data['PSU']['psu_fan_dir'][mode]['valmap']
if direction in vmap:
airflow_dir_real = vmap[direction]
else:
airflow_dir_real = direction
return airflow_dir_real
def get_output_voltage(self, idx):
if idx is None:
return 0.0
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return 0.0
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_v_out")
if not output:
return 0.0
v_out = output['status']
# value returned by the psu driver is in mV
return float(v_out)/1000
def get_output_current(self, idx):
if idx is None:
return 0.0
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return 0.0
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_i_out")
if not output:
return 0.0
i_out = output['status']
# current in mA
return float(i_out)/1000
def get_output_power(self, idx):
if idx is None:
return 0.0
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return 0.0
device = "PSU"+"%d"%(idx)
output = pddf_obj.get_attr_name_output(device, "psu_p_out")
if not output:
return 0.0
p_out = output['status']
# power is returned in micro watts
return float(p_out)/1000000
def get_fan_rpm(self, idx, fan_idx):
if idx is None or fan_idx is None:
return 0
if idx<1 or idx>self.platform['num_psus']:
print "Invalid index %d\n"%idx
return 0
device = "PSU"+"%d"%(idx)
num_fans = pddf_obj.get_num_psu_fans(device)
if fan_idx<1 or fan_idx>num_fans:
print "Invalid PSU-fan index %d\n"%fan_idx
return 0
output = pddf_obj.get_attr_name_output(device, "psu_fan"+str(fan_idx)+"_speed_rpm")
if not output:
return 0
#mode = output['mode']
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
speed = int(output['status'])
return speed
def dump_sysfs(self):
return pddf_obj.cli_dump_dsysfs('psu')

View File

@ -0,0 +1,237 @@
#!/usr/bin/env python
import os.path
import sys
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
import json
try:
import time
from ctypes import create_string_buffer
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class SfpUtil(SfpUtilBase):
"""Platform generic PDDF SfpUtil class"""
_port_to_eeprom_mapping = {}
_port_start = 0
_port_end = 0
_port_to_type_mapping = {}
_qsfp_ports = []
_sfp_ports = []
def __init__(self):
SfpUtilBase.__init__(self)
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
self.platform = pddf_obj.get_platform()
self._port_start = 0
self._port_end = self.get_num_ports()
for port_num in range(self._port_start, self._port_end):
device = "PORT" + "%d"%(port_num+1)
port_eeprom_path = pddf_obj.get_path(device,"eeprom")
self._port_to_eeprom_mapping[port_num] = port_eeprom_path
port_type = pddf_obj.get_device_type(device)
self._port_to_type_mapping[port_num] = port_type
self.populate_port_type(port_num)
def get_num_ports(self):
return int(self.platform['num_ports'])
def is_valid_port(self, port_num):
if port_num < self._port_start or port_num > self._port_end:
return False
else:
return True
def get_presence(self, port_num):
if port_num < self._port_start or port_num > self._port_end:
return False
device = "PORT" + "%d"%(port_num+1)
output = pddf_obj.get_attr_name_output(device, 'xcvr_present')
if not output:
return False
#mode = output['mode']
modpres = output['status'].rstrip()
if 'XCVR' in plugin_data:
if 'xcvr_present' in plugin_data['XCVR']:
ptype = self._port_to_type_mapping[port_num]
vtype = 'valmap-'+ptype
if vtype in plugin_data['XCVR']['xcvr_present']:
vmap = plugin_data['XCVR']['xcvr_present'][vtype]
if modpres in vmap:
return vmap[modpres]
else:
return False
# if plugin_data doesn't specify anything regarding Transceivers
if modpres == '1':
return True
return False
def populate_port_type(self, port):
if self._port_to_type_mapping[port] == 'QSFP' or self._port_to_type_mapping[port] == 'QSFP28':
self._qsfp_ports.append(port)
elif self._port_to_type_mapping[port] == 'SFP' or self._port_to_type_mapping[port] == 'SFP28':
self._sfp_ports.append(port)
@property
def port_start(self):
return self._port_start
@property
def port_end(self):
return (self._port_end - 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
@property
def qsfp_ports(self):
return self._qsfp_ports
def reset(self, port_num):
if port_num < self._port_start or port_num > self._port_end:
return False
device = "PORT" + "%d"%(port_num+1)
port_ps = pddf_obj.get_path(device,"xcvr_reset")
if port_ps is None:
return False
try:
reg_file = open(port_ps, 'w')
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
try:
reg_file.seek(0)
reg_file.write('1')
time.sleep(1)
reg_file.seek(0)
reg_file.write('0')
reg_file.close()
return True
except IOError as e:
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
if not self.get_presence(port_num):
return False
device = "PORT" + "%d"%(port_num+1)
output = pddf_obj.get_attr_name_output(device, 'xcvr_lpmode')
if not output:
if port_num not in self.qsfp_ports:
return False # Read from eeprom only for QSFP ports
try:
eeprom = None
eeprom = open(self.port_to_eeprom_mapping[port_num], "rb")
# check for valid connector type
eeprom.seek(2)
ctype = eeprom.read(1)
if ctype in ['21','23']:
return False
eeprom.seek(93)
lpmode = ord(eeprom.read(1))
if ((lpmode & 0x3) == 0x3):
return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1
else:
return False # High Power Mode if one of the following conditions is matched:
# 1. "Power override" bit is 0
# 2. "Power override" bit is 1 and "Power set" bit is 0
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
else:
#mode = output['mode']
status = int(output['status'].rstrip())
if status == 1:
return True
else:
return False
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
if not self.get_presence(port_num):
return False # Port is not present, unable to set the eeprom
device = "PORT" + "%d"%(port_num+1)
port_ps = pddf_obj.get_path(device,"xcvr_lpmode")
if port_ps is None:
if port_num not in self.qsfp_ports:
return False # Write to eeprom only for QSFP ports
try:
eeprom = None
eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b")
# check for valid connector type
eeprom.seek(2)
ctype = eeprom.read(1)
if ctype in ['21','23']:
return False
# Fill in write buffer
regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode
buffer = create_string_buffer(1)
buffer[0] = chr(regval)
# Write to eeprom
eeprom.seek(93)
eeprom.write(buffer[0])
return True
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
else:
try:
f = open(port_ps, 'w')
if lpmode:
f.write('1')
else:
f.write('0')
f.close()
return True
except IOError as e:
return False
def get_transceiver_change_event(self):
"""
TODO: This function need to be implemented
when decide to support monitoring SFP(Xcvrd)
on this platform.
"""
raise NotImplementedError
def dump_sysfs(self):
return pddf_obj.cli_dump_dsysfs('xcvr')

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python
import os.path
import sys
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
import json
class SYSStatusUtil():
"""Platform-specific SYSStatus class"""
def __init__(self):
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
def get_board_info(self):
device = "SYSSTATUS"
node = pddf_obj.get_path(device,"board_info")
if node is None:
return False
try:
with open(node, 'r') as f:
status = f.read()
print "board_info : %s" %status
except IOError:
return False
def get_cpld_versio(self):
device = "SYSSTATUS"
node = pddf_obj.get_path(device,"cpld1_version")
if node is None:
return False
try:
with open(node, 'r') as f:
status = f.read()
print "cpld1_version : %s" %status
except IOError:
return False
def get_power_module_status(self):
device = "SYSSTATUS"
node = pddf_obj.get_path(device,"power_module_status")
if node is None:
return False
try:
with open(node, 'r') as f:
status = f.read()
print "power_module_status : %s" %status
except IOError:
return False
def get_system_reset_status(self):
device = "SYSSTATUS"
for i in range(1,8):
node = pddf_obj.get_path(device,"system_reset"+str(i))
if node is None:
return False
try:
with open(node, 'r') as f:
status = f.read()
print "system_reset%s : %s" %(i, status)
except IOError:
print "system_reset%s not supported" %i
def get_misc_status(self):
device = "SYSSTATUS"
for i in range(1,3):
node = pddf_obj.get_path(device,"misc"+str(i))
if node is None:
return False
try:
with open(node, 'r') as f:
status = f.read()
print "misc%s : %s" %(i, status)
except IOError:
print "system_reset%s not supported" %i
def dump_sysfs(self):
return pddf_obj.cli_dump_dsysfs('sys-status')

View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
import os.path
import sys
import json
sys.path.append('/usr/share/sonic/platform/plugins')
import pddfparse
class ThermalUtil:
def __init__(self):
global pddf_obj
global plugin_data
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)) + '/../pddf/pd-plugin.json')) as pd:
plugin_data = json.load(pd)
pddf_obj = pddfparse.PddfParse()
self.platform = pddf_obj.get_platform()
self.num_thermals = self.platform['num_temps']
self.info=[]
def get_num_thermals(self):
return (self.num_thermals)
def get_thermal_info(self):
list=[]
pddf_obj.get_device_list(list, "TEMP_SENSOR")
list.sort()
for dev in list:
data={}
device_name = dev['dev_info']['device_name']
topo_info = dev['i2c']['topo_info']
label="%s-i2c-%d-%x" % (topo_info['dev_type'], int(topo_info['parent_bus'], 0), int(topo_info['dev_addr'], 0))
attr_list = dev['i2c']['attr_list']
data['device_name']=device_name
data['label']=label
for attr in attr_list:
attr_name = attr['attr_name']
node = pddf_obj.get_path(device_name, attr_name)
if node is None:
return False
try:
with open(node, 'r') as f:
attr_value = int(f.read())
except IOError:
return False
data[attr_name] = attr_value/float(1000)
self.info.append(data)
def show_thermal_temp_values(self, idx):
if idx<1 or idx>self.num_thermals:
print "Invalid temperature sensor idx %d"%idx
return None
self.get_thermal_info()
thermal_name = "TEMP"+"%d"%idx
label=""
value=""
for temp in self.info:
if thermal_name==temp['device_name']:
label = temp['label']
value = "temp1\t %+.1f C (high = %+.1f C, hyst = %+.1f C)" % (temp['temp1_input'], temp['temp1_max'], temp['temp1_max_hyst'])
else:
continue
return (label, value)
def show_temp_values(self):
self.get_thermal_info()
for temp in self.info:
print temp['label']
print "temp1\t %+.1f C (high = %+.1f C, hyst = %+.1f C)" % (temp['temp1_input'], temp['temp1_max'], temp['temp1_max_hyst'])
def dump_sysfs(self):
return pddf_obj.cli_dump_dsysfs('temp-sensors')

View File

@ -19,7 +19,8 @@ RUN apt-get update && \
python-smbus \
ethtool \
dmidecode \
i2c-tools
i2c-tools \
python-jsonschema
# On Arista devices, the sonic_platform wheel is not installed in the container.
# Instead, the installation directory is mounted from the host OS. However, this method

View File

@ -178,6 +178,14 @@ sudo cp {{platform_common_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2
sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip2 install $PLATFORM_COMMON_PY2_WHEEL_NAME
sudo rm -rf $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2_WHEEL_NAME
{% if pddf_support == "y" %}
# Install pddf-platform-api-base Python 2 package
PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME=$(basename {{pddf_platform_api_base_py2_wheel_path}})
sudo cp {{pddf_platform_api_base_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME
sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME
sudo rm -rf $FILESYSTEM_ROOT/$PLATFORM_PDDF_COMMON_PY2_WHEEL_NAME
{% endif %}
# Install system-health Python 2 package
SYSTEM_HEALTH_PY2_WHEEL_NAME=$(basename {{system_health_py2_wheel_path}})
sudo cp {{system_health_py2_wheel_path}} $FILESYSTEM_ROOT/$SYSTEM_HEALTH_PY2_WHEEL_NAME

View File

@ -4,6 +4,7 @@ SONIC_ONE_IMAGE = sonic-broadcom.bin
$(SONIC_ONE_IMAGE)_MACHINE = broadcom
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(BRCM_OPENNSL_KERNEL)
$(SONIC_ONE_IMAGE)_INSTALLS += $(PDDF_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(DELL_Z9264F_PLATFORM_MODULE) \

19
platform/pddf/README.md Normal file
View File

@ -0,0 +1,19 @@
Platform Driver Development Framework (PDDF) is part of SONiC Platform Development Kit (PDK) which optimizes the platform developement.
SONiC PDDF (Platform driver development framework) supports the following HW devices on a given platform:
- Fan
- PSU
- System EEPROM
- CPLD
- CPLDMUX
- GPIO
- Optic Transceivers
- System LED control via CPLD
- System Status Registers in CPLD
- Temp Sensors
This folder for the PDDF consists of the following:
- PDDF python utility scripts
- Generic PDDF HW device drivers in kernel space

View File

@ -0,0 +1 @@
subdir-m := modules

View File

@ -0,0 +1,12 @@
sonic-pddf-platform-modules (1.1) unstable; urgency=low
* Enhancing PDDF: Added support for cpldmux, gpio and some extra attributes
-- Broadcom <fuzail.khan@broadcom.com> Wed, 10 Jun 2020 10:10:10 -0800
sonic-pddf-platform-modules (1.0) unstable; urgency=low
* Basic tempelate for PDDF
* Initial release
-- Broadcom <satish-k.kumar@broadcom.com> Wed, 26 Jun 2019 10:10:10 -0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,12 @@
Source: sonic-pddf-platform-modules
Section: main
Priority: extra
Maintainer: Broadcom <sk@broadcom.com>
Build-Depends: debhelper (>= 9), bzip2
Standards-Version: 3.9.3
Package: sonic-platform-pddf
Architecture: amd64
Description: kernel modules for platform devices such as psu, fan, sfp, led

75
platform/pddf/i2c/debian/rules Executable file
View File

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

View File

@ -0,0 +1 @@
subdir-m := client cpld cpldmux xcvr mux gpio psu fan led sysstatus

View File

@ -0,0 +1,3 @@
obj-m:= pddf_client_module.o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,330 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* A pddf kernel module to create access-data attributes for client creation
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include <linux/hashtable.h>
#include "pddf_client_defs.h"
NEW_DEV_ATTR pddf_data={0};
EXPORT_SYMBOL(pddf_data);
int showall = 0;
/* CLIENT CREATION DATA ATTR LIST */
PDDF_DATA_ATTR(i2c_type, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.i2c_type, NULL);
PDDF_DATA_ATTR(i2c_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.i2c_name, NULL);
PDDF_DATA_ATTR(parent_bus, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_data.parent_bus, NULL);
PDDF_DATA_ATTR(dev_type, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_data.dev_type, NULL);
PDDF_DATA_ATTR(dev_id, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_data.dev_id, NULL);
PDDF_DATA_ATTR(dev_addr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_data.dev_addr, NULL);
PDDF_DATA_ATTR(error, S_IRUGO, show_error_code, NULL, PDDF_INT_DEC, sizeof(int), (void*)&pddf_data.error, (void*)&pddf_data.errstr);
static struct attribute *pddf_clients_data_attributes[] = {
&attr_i2c_type.dev_attr.attr,
&attr_i2c_name.dev_attr.attr,
&attr_parent_bus.dev_attr.attr,
&attr_dev_type.dev_attr.attr,
&attr_dev_id.dev_attr.attr,
&attr_dev_addr.dev_attr.attr,
&attr_error.dev_attr.attr,
NULL
};
struct attribute_group pddf_clients_data_group = {
.attrs = pddf_clients_data_attributes,
};
EXPORT_SYMBOL(pddf_clients_data_group);
PDDF_DATA_ATTR(showall, S_IRUGO, show_all_devices, NULL, PDDF_INT_DEC, sizeof(int), (void *)&showall, NULL);
static struct attribute *pddf_allclients_data_attributes[] = {
&attr_showall.dev_attr.attr,
NULL
};
struct attribute_group pddf_allclients_data_group = {
.attrs = pddf_allclients_data_attributes,
};
void set_attr_data(void * ptr)
{
pddf_data.data=ptr;
}
ssize_t show_all_devices(struct device *dev, struct device_attribute *da, char *buf)
{
int ret = 0;
PDDF_ATTR *pptr = (PDDF_ATTR *)da;
int *ptr = (int *)pptr->addr;
traverse_device_table();
ret = sprintf(buf, "Total Devices: %d\n", *ptr);
return ret;
}
ssize_t show_error_code(struct device *dev, struct device_attribute *da, char *buf)
{
int ret = 0;
PDDF_ATTR *pptr = (PDDF_ATTR *)da;
NEW_DEV_ATTR *ptr = ( NEW_DEV_ATTR *)pptr->addr;
ret = sprintf(buf, "0x%x:%s\n", (ptr->error), ptr->errstr);
return ret;
}
void set_error_code(int ecode, char *estr)
{
pddf_data.error = ecode;
strcpy(pddf_data.errstr, estr);
return;
}
EXPORT_SYMBOL(set_error_code);
ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf)
{
int ret = 0;
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
/*pddf_dbg(KERN_ERR "[ READ ] DATA ATTR PTR TYPE:%d, ADDR=%p\n", ptr->type, ptr->addr);*/
switch(ptr->type)
{
case PDDF_CHAR:
ret = sprintf(buf, "%s\n", ptr->addr);
break;
case PDDF_UCHAR:
ret = sprintf(buf, "%d\n", *(unsigned char*)(ptr->addr));
break;
case PDDF_INT_DEC:
ret = sprintf(buf, "%d\n", *(int*)(ptr->addr));
break;
case PDDF_INT_HEX:
ret = sprintf(buf, "0x%x\n", *(int*)(ptr->addr));
break;
case PDDF_USHORT:
ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr));
break;
case PDDF_UINT32:
ret = sprintf(buf, "0x%x\n", *(uint32_t *)(ptr->addr));
break;
default:
break;
}
return ret;
}
EXPORT_SYMBOL(show_pddf_data);
ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int ret = 0, num = 0;
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
switch(ptr->type)
{
case PDDF_CHAR:
strncpy(ptr->addr, buf, strlen(buf)-1); // to discard newline char form buf
ptr->addr[strlen(buf)-1] = '\0';
break;
case PDDF_UCHAR:
ret = kstrtoint(buf,10,&num);
if (ret==0)
*(unsigned char *)(ptr->addr) = (unsigned char)num;
break;
case PDDF_INT_DEC:
ret = kstrtoint(buf,10,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
break;
case PDDF_INT_HEX:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
break;
case PDDF_USHORT:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(unsigned short *)(ptr->addr) = (unsigned short)num;
break;
case PDDF_UINT32:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(uint32_t *)(ptr->addr) = (uint32_t)num;
break;
default:
break;
}
return count;
}
EXPORT_SYMBOL(store_pddf_data);
DEFINE_HASHTABLE(htable, 8);
int get_hash(char *name)
{
int i=0;
int hash=0;
for(i=0; i<strlen(name); i++)
{
hash+=name[i];
}
return hash;
}
void init_device_table(void)
{
hash_init(htable);
}
void add_device_table(char *name, void *ptr)
{
PDEVICE *hdev=kmalloc(sizeof(PDEVICE), GFP_KERNEL );
if(!hdev)return;
strcpy(hdev->name, name);
hdev->data = ptr;
pddf_dbg(CLIENT, KERN_ERR "%s: Adding ptr 0x%p to the hash table\n", __FUNCTION__, ptr);
hash_add(htable, &hdev->node, get_hash(hdev->name));
}
EXPORT_SYMBOL(add_device_table);
void* get_device_table(char *name)
{
PDEVICE *dev=NULL;
int i=0;
hash_for_each(htable, i, dev, node) {
if(strcmp(dev->name, name)==0) {
return (void *)dev->data;
}
}
return NULL;
}
EXPORT_SYMBOL(get_device_table);
void delete_device_table(char *name)
{
PDEVICE *dev=NULL;
int i=0;
hash_for_each(htable, i, dev, node) {
if(strcmp(dev->name, name)==0) {
pddf_dbg(CLIENT, KERN_ERR "found entry to delete: %s 0x%p\n", dev->name, dev->data);
hash_del(&(dev->node));
}
}
return;
}
EXPORT_SYMBOL(delete_device_table);
void traverse_device_table(void )
{
PDEVICE *dev=NULL;
int i=0;
hash_for_each(htable, i, dev, node) {
pddf_dbg(CLIENT, KERN_ERR "Entry[%d]: %s : 0x%p\n", i, dev->name, dev->data);
}
showall = i;
}
EXPORT_SYMBOL(traverse_device_table);
struct kobject *device_kobj;
static struct kobject *pddf_kobj;
struct kobject *get_device_i2c_kobj(void)
{
return device_kobj;
}
EXPORT_SYMBOL(get_device_i2c_kobj);
int __init pddf_data_init(void)
{
int ret = 0;
pddf_dbg(CLIENT, "PDDF_DATA MODULE.. init\n");
pddf_kobj = kobject_create_and_add("pddf", kernel_kobj);
if(!pddf_kobj) {
return -ENOMEM;
}
device_kobj = kobject_create_and_add("devices", pddf_kobj);
if(!device_kobj) {
return -ENOMEM;
}
init_device_table();
ret = sysfs_create_group(device_kobj, &pddf_allclients_data_group);
if (ret)
{
kobject_put(device_kobj);
return ret;
}
pddf_dbg(CLIENT, "CREATED PDDF ALLCLIENTS CREATION SYSFS GROUP\n");
return ret;
}
void __exit pddf_data_exit(void)
{
pddf_dbg(CLIENT, "PDDF_DATA MODULE.. exit\n");
sysfs_remove_group(device_kobj, &pddf_allclients_data_group);
kobject_put(device_kobj);
kobject_put(pddf_kobj);
pddf_dbg(CLIENT, KERN_ERR "%s: Removed the kernle object for 'pddf' and 'device' \n", __FUNCTION__);
return;
}
module_init(pddf_data_init);
module_exit(pddf_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("pddf data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
subdir-m := driver
obj-m := pddf_cpld_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,5 @@
TARGET = pddf_cpld_driver
obj-m := $(TARGET).o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,230 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* A pddf kernel driver module for CPLD
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/dmi.h>
#include "pddf_cpld_defs.h"
extern PDDF_CPLD_DATA pddf_cpld_data;
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
//hw_preaccess_func_cpld_mux_default((uint32_t)cpld_addr, NULL);
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(board_i2c_cpld_read);
int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(board_i2c_cpld_write);
ssize_t regval_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
struct i2c_client *client = to_i2c_client(dev);
mutex_lock(&pddf_cpld_data.cpld_lock);
// Put code here to read the register value and print it
if (pddf_cpld_data.reg_addr!=0)
len = sprintf(buf, "0x%2.2x\n", board_i2c_cpld_read(client->addr, pddf_cpld_data.reg_addr));
else
len = sprintf(buf, "xx\n");
mutex_unlock(&pddf_cpld_data.cpld_lock);
return len;
}
static DEVICE_ATTR_RO(regval);
static struct attribute *cpld_attrs[] = {
&dev_attr_regval.attr,
NULL,
};
static struct attribute_group cpld_attribute_group = {
.attrs = cpld_attrs,
};
/* Addresses scanned for board_i2c_cpld
*/
static const unsigned short normal_i2c[] = { 0x31, 0x32, 0x33, 0x35, 0x60, 0x61, 0x62, 0x64, I2C_CLIENT_END };
static void board_i2c_cpld_add_client(struct i2c_client *client)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
if (!node) {
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
return;
}
node->client = client;
mutex_lock(&list_lock);
list_add(&node->list, &cpld_client_list);
mutex_unlock(&list_lock);
}
static void board_i2c_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int found = 0;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client == client) {
found = 1;
break;
}
}
if (found) {
list_del(list_node);
kfree(cpld_node);
}
mutex_unlock(&list_lock);
}
static int board_i2c_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr);
status = -EIO;
goto exit;
}
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &cpld_attribute_group);
if (status) {
goto exit;
}
dev_dbg(&client->dev, "chip found\n");
board_i2c_cpld_add_client(client);
return 0;
exit:
return status;
}
static int board_i2c_cpld_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &cpld_attribute_group);
board_i2c_cpld_remove_client(client);
return 0;
}
static const struct i2c_device_id board_i2c_cpld_id[] = {
{ "i2c_cpld", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, board_i2c_cpld_id);
static struct i2c_driver board_i2c_cpld_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "i2c_cpld",
},
.probe = board_i2c_cpld_probe,
.remove = board_i2c_cpld_remove,
.id_table = board_i2c_cpld_id,
.address_list = normal_i2c,
};
static int __init board_i2c_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&board_i2c_cpld_driver);
}
static void __exit board_i2c_cpld_exit(void)
{
i2c_del_driver(&board_i2c_cpld_driver);
}
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("board_i2c_cpld driver");
MODULE_LICENSE("GPL");
module_init(board_i2c_cpld_init);
module_exit(board_i2c_cpld_exit);

View File

@ -0,0 +1,219 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to create I2C client for a CPLD
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_cpld_defs.h"
PDDF_CPLD_DATA pddf_cpld_data={0};
EXPORT_SYMBOL(pddf_cpld_data);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static ssize_t store_pddf_cpld_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
ssize_t show_pddf_cpld_data(struct device *dev, struct device_attribute *da, char *buf);
extern void *get_device_table(char *name);
extern void delete_device_table(char *name);
/* MUX CLIENT DATA */
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, NULL, (void*)&pddf_data);
PDDF_DATA_ATTR(reg_addr, S_IWUSR|S_IRUGO, show_pddf_cpld_data, store_pddf_cpld_data, PDDF_USHORT, sizeof(unsigned short), (void*)&pddf_cpld_data.reg_addr, NULL);
static struct attribute *cpld_attributes[] = {
&attr_dev_ops.dev_attr.attr,
&attr_reg_addr.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_cpld_client_data_group = {
.attrs = cpld_attributes,
};
static ssize_t store_pddf_cpld_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int ret = 0;
int num = 0;
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
ret = kstrtoint(buf,16,&num);
if (ret==0)
{
mutex_lock(&pddf_cpld_data.cpld_lock);
*(unsigned short *)(ptr->addr) = (unsigned short)num;
mutex_unlock(&pddf_cpld_data.cpld_lock);
pddf_dbg(CPLD, KERN_ERR "Stored value: 0x%x, num: 0x%x\n", *(int*)(ptr->addr), num);
}
return count;
}
EXPORT_SYMBOL(store_pddf_cpld_data);
ssize_t show_pddf_cpld_data(struct device *dev, struct device_attribute *da, char *buf)
{
int ret = 0;
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
pddf_dbg(CPLD, KERN_ERR "[ READ ] DATA ATTR PTR TYPE:%d, ADDR=%p\n", ptr->type, ptr->addr);
mutex_lock(&pddf_cpld_data.cpld_lock);
ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr));
mutex_unlock(&pddf_cpld_data.cpld_lock);
return ret;
}
EXPORT_SYMBOL(show_pddf_cpld_data);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
static struct i2c_board_info board_info;
struct i2c_client *client_ptr;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
adapter = i2c_get_adapter(device_ptr->parent_bus);
if (strncmp(device_ptr->dev_type, "i2c_cpld", strlen("i2c_cpld"))==0)
{
board_info = (struct i2c_board_info) {
.platform_data = (void *)NULL,
};
board_info.addr = device_ptr->dev_addr;
strcpy(board_info.type, device_ptr->dev_type);
/*pddf_dbg(KERN_ERR "Creating a client %s on 0x%x, platform_data 0x%x\n", board_info.type, board_info.addr, board_info.platform_data);*/
client_ptr = i2c_new_device(adapter, &board_info);
if (client_ptr != NULL) {
i2c_put_adapter(adapter);
pddf_dbg(CPLD, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
add_device_table(device_ptr->i2c_name, (void*)client_ptr);
}
else {
i2c_put_adapter(adapter);
goto free_data;
}
}
else
{
printk(KERN_ERR "%s: Unsupported type of cpld - unable to add i2c client\n", __FUNCTION__);
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name);
if (client_ptr)
{
pddf_dbg(CPLD, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
delete_device_table(device_ptr->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
free_data:
/*TODO: free the device_ptr->data is dynamically allocated*/
memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *cpld_kobj;
int __init cpld_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(CPLD, "CPLD_DATA MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
cpld_kobj = kobject_create_and_add("cpld", device_kobj);
if(!cpld_kobj)
return -ENOMEM;
ret = sysfs_create_group(cpld_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(cpld_kobj);
return ret;
}
pddf_dbg(CPLD, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
mutex_init(&pddf_cpld_data.cpld_lock);
ret = sysfs_create_group(cpld_kobj, &pddf_cpld_client_data_group);
if (ret)
{
sysfs_remove_group(cpld_kobj, &pddf_clients_data_group);
kobject_put(cpld_kobj);
return ret;
}
pddf_dbg(CPLD, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
return ret;
}
void __exit cpld_data_exit(void)
{
pddf_dbg(CPLD, "CPLD_DATA MODULE.. exit\n");
sysfs_remove_group(cpld_kobj, &pddf_cpld_client_data_group);
sysfs_remove_group(cpld_kobj, &pddf_clients_data_group);
kobject_put(cpld_kobj);
pddf_dbg(CPLD, KERN_ERR "%s: Removed the kobjects for 'cpld'\n",__FUNCTION__);
return;
}
module_init(cpld_data_init);
module_exit(cpld_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("cpld platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
subdir-m := driver
obj-m := pddf_cpldmux_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,4 @@
TARGET = pddf_cpldmux_driver
obj-m := $(TARGET).o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,209 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
* A pddf kernel driver module for CPLDMUX
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/dmi.h>
#include <linux/platform_data/pca954x.h>
#include <linux/i2c-mux.h>
#include <linux/platform_device.h>
#include "pddf_client_defs.h"
#include "pddf_cpldmux_defs.h"
extern PDDF_CPLDMUX_DATA pddf_cpldmux_data;
/* Users may overwrite these select and delsect functions as per their requirements
* by overwriting them in custom driver
*/
PDDF_CPLDMUX_OPS pddf_cpldmux_ops = {
.select = pddf_cpldmux_select_default,
.deselect = NULL, /* pddf_cpldmux_deselct_default */
};
EXPORT_SYMBOL(pddf_cpldmux_ops);
/* NOTE: Never use i2c_smbus_write_byte_data() or i2c_smbus_xfer() since these operations
* locks the parent bus which might lead to mutex deadlock.
*/
static int cpldmux_byte_write(struct i2c_client *client, u8 regaddr, u8 val)
{
union i2c_smbus_data data;
data.byte = val;
return client->adapter->algo->smbus_xfer(client->adapter, client->addr,
client->flags,
I2C_SMBUS_WRITE,
regaddr, I2C_SMBUS_BYTE_DATA, &data);
}
int pddf_cpldmux_select_default(struct i2c_mux_core *muxc, uint32_t chan)
{
PDDF_CPLDMUX_PRIV_DATA *private = i2c_mux_priv(muxc);
PDDF_CPLDMUX_PDATA *pdata = NULL;
PDDF_CPLDMUX_CHAN_DATA *sdata = NULL;
int ret = 0;
/* Select the chan_data based upon the chan */
pdata = &private->data;
if (chan>=pdata->num_chan)
{
printk(KERN_ERR "%s: wrong channel number %d, supported channels %d\n",__FUNCTION__, chan, pdata->num_chan);
return 0;
}
if ( (pdata->chan_cache!=1) || (private->last_chan!=chan) )
{
sdata = &pdata->chan_data[chan];
pddf_dbg(CPLDMUX, KERN_ERR "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to enable chan %d\n", __FUNCTION__, sdata->cpld_sel, sdata->cpld_offset, sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_sel & 0xff));
private->last_chan = chan;
}
return ret;
}
int pddf_cpldmux_deselect_default(struct i2c_mux_core *muxc, uint32_t chan)
{
PDDF_CPLDMUX_PRIV_DATA *private = i2c_mux_priv(muxc);
PDDF_CPLDMUX_PDATA *pdata = NULL;
PDDF_CPLDMUX_CHAN_DATA *sdata = NULL;
int ret = 0;
/* Select the chan_data based upon the chan */
pdata = &private->data;
if (chan>=pdata->num_chan)
{
printk(KERN_ERR "%s: wrong channel number %d, supported channels %d\n",__FUNCTION__, chan, pdata->num_chan);
return 0;
}
sdata = &pdata->chan_data[chan];
pddf_dbg(CPLDMUX, KERN_ERR "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to disable chan %d", __FUNCTION__, sdata->cpld_desel, sdata->cpld_offset, sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_desel));
return ret;
}
static int cpld_mux_probe(struct platform_device *pdev)
{
struct i2c_mux_core *muxc;
PDDF_CPLDMUX_PRIV_DATA *private;
PDDF_CPLDMUX_PDATA *pdata;
struct i2c_adapter *adap;
int i, ret, ndev;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "CPLDMUX platform data not found\n");
return -ENODEV;
}
private = (PDDF_CPLDMUX_PRIV_DATA *)kzalloc(sizeof(PDDF_CPLDMUX_PRIV_DATA) , GFP_KERNEL);
if (!private) {
printk(KERN_ERR "Failed to allocate memory for priv data\n");
return -ENOMEM;
}
private->last_chan = 0xff; /*Giving imaginary high value so that proper channel is selected at first iteration*/
memcpy(&private->data, pdata, sizeof(PDDF_CPLDMUX_PDATA));
adap = i2c_get_adapter(pdata->parent_bus);
if (!adap) {
kfree(private);
dev_err(&pdev->dev, "Parent adapter (%d) not found\n", pdata->parent_bus);
return -ENODEV;
}
ndev = pdata->num_chan;
muxc = i2c_mux_alloc(adap, &pdev->dev, ndev, 0, 0, pddf_cpldmux_ops.select, pddf_cpldmux_ops.deselect);
if (!muxc) {
ret = -ENOMEM;
goto alloc_failed;
}
muxc->priv = private;
platform_set_drvdata(pdev, muxc);
for (i = 0; i < ndev; i++)
{
int nr = pdata->base_chan + i;
unsigned int class = 0;
ret = i2c_mux_add_adapter(muxc, nr, i, class);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
}
dev_info(&pdev->dev, "%d port mux on %s adapter\n", ndev, adap->name);
return 0;
add_adapter_failed:
i2c_mux_del_adapters(muxc);
alloc_failed:
kfree(private);
i2c_put_adapter(adap);
return ret;
}
static int cpld_mux_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
struct i2c_adapter *adap = muxc->parent;
PDDF_CPLDMUX_PDATA *cpldmux_pdata = pdev->dev.platform_data;
i2c_mux_del_adapters(muxc);
if (muxc->priv)
kfree(muxc->priv);
i2c_put_adapter(adap);
if (cpldmux_pdata) {
pddf_dbg(CPLDMUX, KERN_DEBUG "%s: Freeing cpldmux platform data\n", __FUNCTION__);
kfree(cpldmux_pdata);
}
return 0;
}
static struct platform_driver cpld_mux_driver = {
.probe = cpld_mux_probe,
.remove = cpld_mux_remove, /* TODO */
.driver = {
.owner = THIS_MODULE,
.name = "cpld_mux",
},
};
static int __init board_i2c_cpldmux_init(void)
{
int ret;
ret = platform_driver_register(&cpld_mux_driver);
if (ret) {
printk(KERN_WARNING "Fail to register swpld mux driver\n");
}
return (ret);
}
static void __exit board_i2c_cpldmux_exit(void)
{
platform_driver_unregister(&cpld_mux_driver);
}
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("board_i2c_cpldmux driver");
MODULE_LICENSE("GPL");
module_init(board_i2c_cpldmux_init);
module_exit(board_i2c_cpldmux_exit);

View File

@ -0,0 +1,254 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* PDDF generic module for cpldmux device
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_cpldmux_defs.h"
PDDF_CPLDMUX_DATA pddf_cpldmux_data={0};
PDDF_CPLDMUX_CHAN_DATA pddf_cpldmux_chan_data={0};
EXPORT_SYMBOL(pddf_cpldmux_data);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static ssize_t do_chan_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void *get_device_table(char *name);
extern void delete_device_table(char *name);
/* CPLDMUX CLIENT DATA */
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&pddf_cpldmux_data, (void*)&pddf_data);
PDDF_DATA_ATTR(chan_ops, S_IWUSR, NULL, do_chan_operation, PDDF_CHAR, 8, (void*)&pddf_cpldmux_data, NULL);
PDDF_DATA_ATTR(base_chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_data.base_chan, NULL);
PDDF_DATA_ATTR(num_chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_data.num_chan, NULL);
PDDF_DATA_ATTR(chan_cache, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_data.chan_cache, NULL);
PDDF_DATA_ATTR(cpld_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&pddf_cpldmux_data.cpld_name, NULL);
PDDF_DATA_ATTR(chan, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&pddf_cpldmux_chan_data.chan_num, NULL);
PDDF_DATA_ATTR(dev, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 128, (void*)&pddf_cpldmux_chan_data.chan_device, NULL);
PDDF_DATA_ATTR(cpld_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_devaddr, NULL);
PDDF_DATA_ATTR(cpld_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_offset, NULL);
PDDF_DATA_ATTR(cpld_sel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_sel, NULL);
PDDF_DATA_ATTR(cpld_desel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_desel, NULL);
static struct attribute *cpldmux_attributes[] = {
&attr_dev_ops.dev_attr.attr,
&attr_chan_ops.dev_attr.attr,
&attr_base_chan.dev_attr.attr,
&attr_num_chan.dev_attr.attr,
&attr_chan_cache.dev_attr.attr,
&attr_cpld_name.dev_attr.attr,
&attr_chan.dev_attr.attr,
&attr_dev.dev_attr.attr,
&attr_cpld_devaddr.dev_attr.attr,
&attr_cpld_offset.dev_attr.attr,
&attr_cpld_sel.dev_attr.attr,
&attr_cpld_desel.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_cpldmux_client_data_group = {
.attrs = cpldmux_attributes,
};
static ssize_t do_chan_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
PDDF_CPLDMUX_DATA *cpldmux_data = (PDDF_CPLDMUX_DATA *)(ptr->addr);
int index;
pddf_dbg(CPLDMUX, KERN_ERR "%s: Adding channel %d\n", __FUNCTION__, pddf_cpldmux_chan_data.chan_num);
index = pddf_cpldmux_chan_data.chan_num;
cpldmux_data->chan_data[index] = pddf_cpldmux_chan_data;
memset(&pddf_cpldmux_chan_data, 0, sizeof(pddf_cpldmux_chan_data));
return count;
}
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data);
PDDF_CPLDMUX_DATA *cpldmux_data = (PDDF_CPLDMUX_DATA *)(ptr->addr);
PDDF_CPLDMUX_PDATA *cpldmux_platform_data = NULL;
struct platform_device *plat_dev = NULL;
struct i2c_client *client_ptr = NULL;
int ret=0, i=0;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
if (strncmp(device_ptr->dev_type, "cpld_mux", strlen("cpld_mux"))==0)
{
/*Get the i2c_client handle for the CPLD which drives this cpldmux*/
client_ptr = (struct i2c_client *)get_device_table(cpldmux_data->cpld_name);
if (client_ptr==NULL)
{
pddf_dbg(CPLDMUX, KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name);
printk(KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name);
goto clear_data;
}
/* Allocate the cpldmux_platform_data */
cpldmux_platform_data = (PDDF_CPLDMUX_PDATA *)kzalloc( sizeof(PDDF_CPLDMUX_PDATA) + cpldmux_data->num_chan*sizeof(PDDF_CPLDMUX_CHAN_DATA), GFP_KERNEL );
cpldmux_platform_data->chan_data = (PDDF_CPLDMUX_CHAN_DATA *)(cpldmux_platform_data+1);
cpldmux_platform_data->parent_bus = device_ptr->parent_bus;
cpldmux_platform_data->base_chan = cpldmux_data->base_chan;
cpldmux_platform_data->num_chan = cpldmux_data->num_chan;
cpldmux_platform_data->chan_cache = cpldmux_data->chan_cache;
cpldmux_platform_data->cpld = client_ptr;
for (i=0; i<cpldmux_data->num_chan; i++)
{
cpldmux_platform_data->chan_data[i] = cpldmux_data->chan_data[i];
}
plat_dev = platform_device_alloc(device_ptr->dev_type, device_ptr->dev_id);
plat_dev->dev.platform_data = cpldmux_platform_data;
pddf_dbg(CPLDMUX, KERN_ERR "Creating a %s platform_device 0x%p, platform_data 0x%p\n", plat_dev->name, (void *)plat_dev, (void *)cpldmux_platform_data);
ret = platform_device_add(plat_dev);
if (ret)
{
pddf_dbg(CPLDMUX, KERN_ERR "Unable to create cpld_mux (%s) device: Error %d\n", device_ptr->i2c_name, ret);
goto free_data;
}
else
{
add_device_table(device_ptr->i2c_name, (void *)plat_dev);
}
}
else
{
printk(KERN_ERR "%s: Unsupported type of cpldmux - unable to add i2c client\n", __FUNCTION__);
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
plat_dev = (struct platform_device *)get_device_table(device_ptr->i2c_name);
if (plat_dev)
{
pddf_dbg(CPLDMUX, KERN_ERR "Removing %s device: 0x%p\n", device_ptr->i2c_name, (void *)plat_dev);
pddf_dbg(CPLDMUX, KERN_ERR "Freeing the memory held by device: 0x%p\n", (void *)plat_dev);
platform_device_del(plat_dev);
delete_device_table(device_ptr->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
goto clear_data;
free_data:
/* Free the allocated memory for platform and channel data */
cpldmux_platform_data = plat_dev->dev.platform_data;
if (cpldmux_platform_data)
{
printk(KERN_ERR "%s: Unable to register a cpldmux device. Freeing the platform data\n", __FUNCTION__);
kfree(cpldmux_platform_data);
}
/* Put the platform device structure */
platform_device_put(plat_dev);
clear_data:
memset(cpldmux_data, 0, sizeof(PDDF_CPLDMUX_DATA));
/*TODO: free the data device_ptr->data if data is dynamically allocated*/
memset(device_ptr, 0, sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *cpldmux_kobj;
int __init cpldmux_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(CPLDMUX, "CPLDMUX_DATA MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
cpldmux_kobj = kobject_create_and_add("cpldmux", device_kobj);
if(!cpldmux_kobj)
return -ENOMEM;
ret = sysfs_create_group(cpldmux_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(cpldmux_kobj);
return ret;
}
pddf_dbg(CPLDMUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(cpldmux_kobj, &pddf_cpldmux_client_data_group);
if (ret)
{
sysfs_remove_group(cpldmux_kobj, &pddf_clients_data_group);
kobject_put(cpldmux_kobj);
return ret;
}
pddf_dbg(CPLDMUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
return ret;
}
void __exit cpldmux_data_exit(void)
{
pddf_dbg(CPLDMUX, "CPLDMUX_DATA MODULE.. exit\n");
sysfs_remove_group(cpldmux_kobj, &pddf_cpldmux_client_data_group);
sysfs_remove_group(cpldmux_kobj, &pddf_clients_data_group);
kobject_put(cpldmux_kobj);
pddf_dbg(CPLDMUX, KERN_ERR "%s: Removed the kobjects for 'cpldmux'\n",__FUNCTION__);
return;
}
module_init(cpldmux_data_init);
module_exit(cpldmux_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("cpldmux platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
subdir-m := driver
obj-m := pddf_fan_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,6 @@
TARGET := pddf_fan_driver_module
obj-m := $(TARGET).o
$(TARGET)-objs := pddf_fan_api.o pddf_fan_driver.o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,526 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description of various APIs related to FAN component
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include "pddf_fan_defs.h"
#include "pddf_fan_driver.h"
/*#define FAN_DEBUG*/
#ifdef FAN_DEBUG
#define fan_dbg(...) printk(__VA_ARGS__)
#else
#define fan_dbg(...)
#endif
extern void *get_device_table(char *name);
void get_fan_duplicate_sysfs(int idx, char *str)
{
switch (idx)
{
default:
break;
}
return;
}
int fan_update_hw(struct device *dev, struct fan_attr_info *info, FAN_DATA_ATTR *udata)
{
int status = 0;
struct i2c_client *client = to_i2c_client(dev);
FAN_SYSFS_ATTR_DATA *sysfs_attr_data = NULL;
mutex_lock(&info->update_lock);
sysfs_attr_data = udata->access_data;
if (sysfs_attr_data->pre_set != NULL)
{
status = (sysfs_attr_data->pre_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->do_set != NULL)
{
status = (sysfs_attr_data->do_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->post_set != NULL)
{
status = (sysfs_attr_data->post_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
mutex_unlock(&info->update_lock);
return 0;
}
int fan_update_attr(struct device *dev, struct fan_attr_info *info, FAN_DATA_ATTR *udata)
{
int status = 0;
struct i2c_client *client = to_i2c_client(dev);
FAN_SYSFS_ATTR_DATA *sysfs_attr_data = NULL;
mutex_lock(&info->update_lock);
if (time_after(jiffies, info->last_updated + HZ + HZ / 2) || !info->valid)
{
dev_dbg(&client->dev, "Starting pddf_fan update\n");
info->valid = 0;
sysfs_attr_data = udata->access_data;
if (sysfs_attr_data->pre_get != NULL)
{
status = (sysfs_attr_data->pre_get)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->do_get != NULL)
{
status = (sysfs_attr_data->do_get)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->post_get != NULL)
{
status = (sysfs_attr_data->post_get)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
info->last_updated = jiffies;
info->valid = 1;
}
mutex_unlock(&info->update_lock);
return 0;
}
ssize_t fan_show_default(struct device *dev, struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct fan_data *data = i2c_get_clientdata(client);
FAN_PDATA *pdata = (FAN_PDATA *)(client->dev.platform_data);
FAN_DATA_ATTR *usr_data = NULL;
struct fan_attr_info *attr_info = NULL;
int i, status=0;
char new_str[ATTR_NAME_LEN] = "";
FAN_SYSFS_ATTR_DATA *ptr = NULL;
for (i=0;i<data->num_attr;i++)
{
ptr = (FAN_SYSFS_ATTR_DATA *)pdata->fan_attrs[i].access_data;
get_fan_duplicate_sysfs(ptr->index , new_str);
if (strcmp(attr->dev_attr.attr.name, pdata->fan_attrs[i].aname) == 0 || strcmp(attr->dev_attr.attr.name, new_str) == 0)
{
attr_info = &data->attr_info[i];
usr_data = &pdata->fan_attrs[i];
strcpy(new_str, "");
}
}
if (attr_info==NULL || usr_data==NULL)
{
printk(KERN_ERR "%s is not supported attribute for this client\n", usr_data->aname);
goto exit;
}
fan_update_attr(dev, attr_info, usr_data);
/*Decide the o/p based on attribute type */
switch(attr->index)
{
case FAN1_PRESENT:
case FAN2_PRESENT:
case FAN3_PRESENT:
case FAN4_PRESENT:
case FAN5_PRESENT:
case FAN6_PRESENT:
case FAN7_PRESENT:
case FAN8_PRESENT:
case FAN9_PRESENT:
case FAN10_PRESENT:
case FAN11_PRESENT:
case FAN12_PRESENT:
case FAN1_DIRECTION:
case FAN2_DIRECTION:
case FAN3_DIRECTION:
case FAN4_DIRECTION:
case FAN5_DIRECTION:
case FAN6_DIRECTION:
case FAN7_DIRECTION:
case FAN8_DIRECTION:
case FAN9_DIRECTION:
case FAN10_DIRECTION:
case FAN11_DIRECTION:
case FAN12_DIRECTION:
case FAN1_INPUT:
case FAN2_INPUT:
case FAN3_INPUT:
case FAN4_INPUT:
case FAN5_INPUT:
case FAN6_INPUT:
case FAN7_INPUT:
case FAN8_INPUT:
case FAN9_INPUT:
case FAN10_INPUT:
case FAN11_INPUT:
case FAN12_INPUT:
case FAN1_PWM:
case FAN2_PWM:
case FAN3_PWM:
case FAN4_PWM:
case FAN5_PWM:
case FAN6_PWM:
case FAN7_PWM:
case FAN8_PWM:
case FAN9_PWM:
case FAN10_PWM:
case FAN11_PWM:
case FAN12_PWM:
case FAN1_FAULT:
case FAN2_FAULT:
case FAN3_FAULT:
case FAN4_FAULT:
case FAN5_FAULT:
case FAN6_FAULT:
case FAN7_FAULT:
case FAN8_FAULT:
case FAN9_FAULT:
case FAN10_FAULT:
case FAN11_FAULT:
case FAN12_FAULT:
status = attr_info->val.intval;
break;
default:
fan_dbg(KERN_ERR "%s: Unable to find the attribute index for %s\n", __FUNCTION__, usr_data->aname);
status = 0;
}
exit:
return sprintf(buf, "%d\n", status);
}
ssize_t fan_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct fan_data *data = i2c_get_clientdata(client);
FAN_PDATA *pdata = (FAN_PDATA *)(client->dev.platform_data);
FAN_DATA_ATTR *usr_data = NULL;
struct fan_attr_info *attr_info = NULL;
int i, ret ;
uint32_t val;
for (i=0;i<data->num_attr;i++)
{
if (strcmp(data->attr_info[i].name, attr->dev_attr.attr.name) == 0 && strcmp(pdata->fan_attrs[i].aname, attr->dev_attr.attr.name) == 0)
{
attr_info = &data->attr_info[i];
usr_data = &pdata->fan_attrs[i];
}
}
if (attr_info==NULL || usr_data==NULL) {
printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name);
goto exit;
}
switch(attr->index)
{
case FAN1_PWM:
case FAN2_PWM:
case FAN3_PWM:
case FAN4_PWM:
case FAN5_PWM:
case FAN6_PWM:
case FAN7_PWM:
case FAN8_PWM:
case FAN9_PWM:
case FAN10_PWM:
case FAN11_PWM:
case FAN12_PWM:
ret = kstrtoint(buf, 10, &val);
if (ret)
{
printk(KERN_ERR "%s: Unable to convert string into value for %s\n", __FUNCTION__, usr_data->aname);
return ret;
}
/*Update the value of attr_info here, and use it to update the HW values*/
attr_info->val.intval = val;
break;
default:
printk(KERN_ERR "%s: Unable to find the attr index for %s\n", __FUNCTION__, usr_data->aname);
goto exit;
}
fan_dbg(KERN_ERR "%s: pwm to be set is %d\n", __FUNCTION__, val);
fan_update_hw(dev, attr_info, usr_data);
exit:
return count;
}
int fan_cpld_client_read(FAN_DATA_ATTR *udata)
{
int status = -1;
if (udata!=NULL)
{
if (udata->len==1)
{
status = board_i2c_cpld_read(udata->devaddr , udata->offset);
}
else
{
/* Get the I2C client for the CPLD */
struct i2c_client *client_ptr=NULL;
client_ptr = (struct i2c_client *)get_device_table(udata->devname);
if (client_ptr)
{
if (udata->len==2)
{
status = i2c_smbus_read_word_swapped(client_ptr, udata->offset);
}
else
printk(KERN_ERR "PDDF_FAN: Doesn't support block CPLD read yet");
}
else
printk(KERN_ERR "Unable to get the client handle for %s\n", udata->devname);
}
}
return status;
}
int sonic_i2c_get_fan_present_default(void *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
int val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
if (strcmp(udata->devtype, "cpld") == 0)
{
val = fan_cpld_client_read(udata);
}
else
{
val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset);
}
painfo->val.intval = ((val & udata->mask) == udata->cmpval);
return status;
}
int sonic_i2c_get_fan_rpm_default(void *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
uint32_t val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
if (strcmp(udata->devtype, "cpld") == 0)
{
val = fan_cpld_client_read(udata);
}
else
{
if (udata->len == 1)
{
val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset);
}
else if (udata->len ==2)
{
val = i2c_smbus_read_word_swapped((struct i2c_client *)client, udata->offset);
}
}
if (udata->is_divisor)
painfo->val.intval = udata->mult / (val >> 3);
else
painfo->val.intval = udata->mult * val;
return status;
}
int sonic_i2c_get_fan_direction_default(void *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
uint32_t val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
if (strcmp(udata->devtype, "cpld") == 0)
{
val = fan_cpld_client_read(udata);
}
else
{
val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset);
}
painfo->val.intval = ((val & udata->mask) == udata->cmpval);
return status;
}
int sonic_i2c_set_fan_pwm_default(struct i2c_client *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
uint32_t val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
val = painfo->val.intval & udata->mask;
if (val > 255)
{
return -EINVAL;
}
if (strcmp(udata->devtype, "cpld") == 0)
{
if (udata->len==1)
{
status = board_i2c_cpld_write(udata->devaddr , udata->offset, val);
}
else
{
/* Get the I2C client for the CPLD */
struct i2c_client *client_ptr=NULL;
client_ptr = (struct i2c_client *)get_device_table(udata->devname);
if (client_ptr)
{
if (udata->len==2)
{
uint8_t val_lsb = val & 0xFF;
uint8_t val_hsb = (val >> 8) & 0xFF;
/* TODO: Check this logic for LE and BE */
i2c_smbus_write_byte_data(client, udata->offset, val_lsb);
i2c_smbus_write_byte_data(client, udata->offset+1, val_hsb);
}
else
printk(KERN_ERR "PDDF_FAN: Doesn't support block CPLD write yet");
}
else
printk(KERN_ERR "Unable to get the client handle for %s\n", udata->devname);
}
}
else
{
if (udata->len == 1)
i2c_smbus_write_byte_data(client, udata->offset, val);
else if (udata->len == 2)
{
uint8_t val_lsb = val & 0xFF;
uint8_t val_hsb = (val >> 8) & 0xFF;
/* TODO: Check this logic for LE and BE */
i2c_smbus_write_byte_data(client, udata->offset, val_lsb);
i2c_smbus_write_byte_data(client, udata->offset+1, val_hsb);
}
else
{
printk(KERN_DEBUG "%s: pwm should be of len 1/2 bytes. Not setting the pwm as the length is %d\n", __FUNCTION__, udata->len);
}
}
return status;
}
int sonic_i2c_get_fan_pwm_default(void *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
uint32_t val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
if (strcmp(udata->devtype, "cpld") == 0)
{
val = fan_cpld_client_read(udata);
}
else
{
if (udata->len == 1)
{
val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset);
}
else if (udata->len ==2)
{
val = i2c_smbus_read_word_swapped((struct i2c_client *)client, udata->offset);
}
}
val = val & udata->mask;
painfo->val.intval = val;
return status;
}
int sonic_i2c_get_fan_fault_default(void *client, FAN_DATA_ATTR *udata, void *info)
{
int status = 0;
uint32_t val = 0;
struct fan_attr_info *painfo = (struct fan_attr_info *)info;
/*Assuming fan fault to be denoted by 1 byte only*/
if (strcmp(udata->devtype, "cpld") == 0)
{
val = fan_cpld_client_read(udata);
}
else
{
val = i2c_smbus_read_byte_data((struct i2c_client *)client, udata->offset);
}
val = val & udata->mask;
painfo->val.intval = val;
return status;
}
int pddf_fan_post_probe_default(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
/*Dummy func for now - check the respective platform modules*/
return 0;
}

View File

@ -0,0 +1,496 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel driver module for a FAN controller
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_fan_defs.h"
#include "pddf_fan_driver.h"
#include "pddf_fan_api.h"
#define DRVNAME "pddf_fan"
struct pddf_ops_t pddf_fan_ops = {
.pre_init = NULL,
.post_init = NULL,
.pre_probe = NULL,
.post_probe = pddf_fan_post_probe_default,
.pre_remove = NULL,
.post_remove = NULL,
.pre_exit = NULL,
.post_exit = NULL,
};
EXPORT_SYMBOL(pddf_fan_ops);
FAN_SYSFS_ATTR_DATA data_fan1_present = {FAN1_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan1_present);
FAN_SYSFS_ATTR_DATA data_fan2_present = {FAN2_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan2_present);
FAN_SYSFS_ATTR_DATA data_fan3_present = {FAN3_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan3_present);
FAN_SYSFS_ATTR_DATA data_fan4_present = {FAN4_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan4_present);
FAN_SYSFS_ATTR_DATA data_fan5_present = {FAN5_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan5_present);
FAN_SYSFS_ATTR_DATA data_fan6_present = {FAN6_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan6_present);
FAN_SYSFS_ATTR_DATA data_fan7_present = {FAN7_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan7_present);
FAN_SYSFS_ATTR_DATA data_fan8_present = {FAN8_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan8_present);
FAN_SYSFS_ATTR_DATA data_fan9_present = {FAN9_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan9_present);
FAN_SYSFS_ATTR_DATA data_fan10_present = {FAN10_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan10_present);
FAN_SYSFS_ATTR_DATA data_fan11_present = {FAN11_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan11_present);
FAN_SYSFS_ATTR_DATA data_fan12_present = {FAN12_PRESENT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_present_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan12_present);
FAN_SYSFS_ATTR_DATA data_fan1_direction = {FAN1_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan1_direction);
FAN_SYSFS_ATTR_DATA data_fan2_direction = {FAN2_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan2_direction);
FAN_SYSFS_ATTR_DATA data_fan3_direction = {FAN3_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan3_direction);
FAN_SYSFS_ATTR_DATA data_fan4_direction = {FAN4_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan4_direction);
FAN_SYSFS_ATTR_DATA data_fan5_direction = {FAN5_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan5_direction);
FAN_SYSFS_ATTR_DATA data_fan6_direction = {FAN6_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan6_direction);
FAN_SYSFS_ATTR_DATA data_fan7_direction = {FAN7_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan7_direction);
FAN_SYSFS_ATTR_DATA data_fan8_direction = {FAN8_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan8_direction);
FAN_SYSFS_ATTR_DATA data_fan9_direction = {FAN9_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan9_direction);
FAN_SYSFS_ATTR_DATA data_fan10_direction = {FAN10_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan10_direction);
FAN_SYSFS_ATTR_DATA data_fan11_direction = {FAN11_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan11_direction);
FAN_SYSFS_ATTR_DATA data_fan12_direction = {FAN12_DIRECTION, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_direction_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan12_direction);
FAN_SYSFS_ATTR_DATA data_fan1_input = {FAN1_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan1_input);
FAN_SYSFS_ATTR_DATA data_fan2_input = {FAN2_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan2_input);
FAN_SYSFS_ATTR_DATA data_fan3_input = {FAN3_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan3_input);
FAN_SYSFS_ATTR_DATA data_fan4_input = {FAN4_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan4_input);
FAN_SYSFS_ATTR_DATA data_fan5_input = {FAN5_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan5_input);
FAN_SYSFS_ATTR_DATA data_fan6_input = {FAN6_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan6_input);
FAN_SYSFS_ATTR_DATA data_fan7_input = {FAN7_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan7_input);
FAN_SYSFS_ATTR_DATA data_fan8_input = {FAN8_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan8_input);
FAN_SYSFS_ATTR_DATA data_fan9_input = {FAN9_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan9_input);
FAN_SYSFS_ATTR_DATA data_fan10_input = {FAN10_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan10_input);
FAN_SYSFS_ATTR_DATA data_fan11_input = {FAN11_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan11_input);
FAN_SYSFS_ATTR_DATA data_fan12_input = {FAN12_INPUT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_rpm_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan12_input);
FAN_SYSFS_ATTR_DATA data_fan1_pwm = {FAN1_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan1_pwm);
FAN_SYSFS_ATTR_DATA data_fan2_pwm = {FAN2_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan2_pwm);
FAN_SYSFS_ATTR_DATA data_fan3_pwm = {FAN3_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan3_pwm);
FAN_SYSFS_ATTR_DATA data_fan4_pwm = {FAN4_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan4_pwm);
FAN_SYSFS_ATTR_DATA data_fan5_pwm = {FAN5_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan5_pwm);
FAN_SYSFS_ATTR_DATA data_fan6_pwm = {FAN6_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan6_pwm);
FAN_SYSFS_ATTR_DATA data_fan7_pwm = {FAN7_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan7_pwm);
FAN_SYSFS_ATTR_DATA data_fan8_pwm = {FAN8_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan8_pwm);
FAN_SYSFS_ATTR_DATA data_fan9_pwm = {FAN9_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan9_pwm);
FAN_SYSFS_ATTR_DATA data_fan10_pwm = {FAN10_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan10_pwm);
FAN_SYSFS_ATTR_DATA data_fan11_pwm = {FAN11_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan11_pwm);
FAN_SYSFS_ATTR_DATA data_fan12_pwm = {FAN12_PWM, S_IRUGO | S_IWUSR, fan_show_default, NULL, sonic_i2c_get_fan_pwm_default, NULL, fan_store_default, NULL, sonic_i2c_set_fan_pwm_default, NULL, NULL};
EXPORT_SYMBOL(data_fan12_pwm);
FAN_SYSFS_ATTR_DATA data_fan1_fault = {FAN1_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan1_fault);
FAN_SYSFS_ATTR_DATA data_fan2_fault = {FAN2_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan2_fault);
FAN_SYSFS_ATTR_DATA data_fan3_fault = {FAN3_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan3_fault);
FAN_SYSFS_ATTR_DATA data_fan4_fault = {FAN4_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan4_fault);
FAN_SYSFS_ATTR_DATA data_fan5_fault = {FAN5_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan5_fault);
FAN_SYSFS_ATTR_DATA data_fan6_fault = {FAN6_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan6_fault);
FAN_SYSFS_ATTR_DATA data_fan7_fault = {FAN7_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan7_fault);
FAN_SYSFS_ATTR_DATA data_fan8_fault = {FAN8_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan8_fault);
FAN_SYSFS_ATTR_DATA data_fan9_fault = {FAN9_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan9_fault);
FAN_SYSFS_ATTR_DATA data_fan10_fault = {FAN10_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan10_fault);
FAN_SYSFS_ATTR_DATA data_fan11_fault = {FAN11_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan11_fault);
FAN_SYSFS_ATTR_DATA data_fan12_fault = {FAN12_FAULT, S_IRUGO, fan_show_default, NULL, sonic_i2c_get_fan_fault_default, NULL, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(data_fan12_fault);
FAN_SYSFS_ATTR_DATA_ENTRY fan_sysfs_attr_data_tbl[]=
{
{ "fan1_present", &data_fan1_present},
{ "fan2_present", &data_fan2_present},
{ "fan3_present", &data_fan3_present},
{ "fan4_present", &data_fan4_present},
{ "fan5_present", &data_fan5_present},
{ "fan6_present", &data_fan6_present},
{ "fan7_present", &data_fan7_present},
{ "fan8_present", &data_fan8_present},
{ "fan9_present", &data_fan9_present},
{ "fan10_present", &data_fan10_present},
{ "fan11_present", &data_fan11_present},
{ "fan12_present", &data_fan12_present},
{ "fan1_direction", &data_fan1_direction},
{ "fan2_direction", &data_fan2_direction},
{ "fan3_direction", &data_fan3_direction},
{ "fan4_direction", &data_fan4_direction},
{ "fan5_direction", &data_fan5_direction},
{ "fan6_direction", &data_fan6_direction},
{ "fan7_direction", &data_fan7_direction},
{ "fan8_direction", &data_fan8_direction},
{ "fan9_direction", &data_fan9_direction},
{ "fan10_direction", &data_fan10_direction},
{ "fan11_direction", &data_fan11_direction},
{ "fan12_direction", &data_fan12_direction},
{ "fan1_input", &data_fan1_input},
{ "fan2_input", &data_fan2_input},
{ "fan3_input", &data_fan3_input},
{ "fan4_input", &data_fan4_input},
{ "fan5_input", &data_fan5_input},
{ "fan6_input", &data_fan6_input},
{ "fan7_input", &data_fan7_input},
{ "fan8_input", &data_fan8_input},
{ "fan9_input", &data_fan9_input},
{ "fan10_input", &data_fan10_input},
{ "fan11_input", &data_fan11_input},
{ "fan12_input", &data_fan12_input},
{ "fan1_pwm", &data_fan1_pwm},
{ "fan2_pwm", &data_fan2_pwm},
{ "fan3_pwm", &data_fan3_pwm},
{ "fan4_pwm", &data_fan4_pwm},
{ "fan5_pwm", &data_fan5_pwm},
{ "fan6_pwm", &data_fan6_pwm},
{ "fan7_pwm", &data_fan7_pwm},
{ "fan8_pwm", &data_fan8_pwm},
{ "fan9_pwm", &data_fan9_pwm},
{ "fan10_pwm", &data_fan10_pwm},
{ "fan11_pwm", &data_fan11_pwm},
{ "fan12_pwm", &data_fan12_pwm},
{ "fan1_fault", &data_fan1_fault},
{ "fan2_fault", &data_fan2_fault},
{ "fan3_fault", &data_fan3_fault},
{ "fan4_fault", &data_fan4_fault},
{ "fan5_fault", &data_fan5_fault},
{ "fan6_fault", &data_fan6_fault},
{ "fan7_fault", &data_fan7_fault},
{ "fan8_fault", &data_fan8_fault},
{ "fan9_fault", &data_fan9_fault},
{ "fan10_fault", &data_fan10_fault},
{ "fan11_fault", &data_fan11_fault},
{ "fan12_fault", &data_fan12_fault},
};
void *get_fan_access_data(char *name)
{
int i=0;
for(i=0; i<(sizeof(fan_sysfs_attr_data_tbl)/sizeof(fan_sysfs_attr_data_tbl[0])); i++)
{
if(strcmp(name, fan_sysfs_attr_data_tbl[i].name) ==0)
{
return &fan_sysfs_attr_data_tbl[i];
}
}
return NULL;
}
EXPORT_SYMBOL(get_fan_access_data);
static int pddf_fan_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct fan_data *data;
int status=0,i,num, j=0;
FAN_PDATA *fan_platform_data;
FAN_DATA_ATTR *data_attr;
FAN_SYSFS_ATTR_DATA_ENTRY *sysfs_data_entry;
char new_str[ATTR_NAME_LEN] = "";
if (client == NULL) {
printk("NULL Client.. \n");
goto exit;
}
if (pddf_fan_ops.pre_probe)
{
status = (pddf_fan_ops.pre_probe)(client, dev_id);
if (status != 0)
goto exit;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
status = -EIO;
goto exit;
}
/* Add support for a pre probe function */
data = kzalloc(sizeof(struct fan_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
dev_info(&client->dev, "chip found\n");
/*Take control of the platform data*/
fan_platform_data = (FAN_PDATA *)(client->dev.platform_data);
num = fan_platform_data->len;
data->num_attr = num;
for (i=0;i<num;i++)
{
/*struct attribute *aptr = NULL;*/
struct sensor_device_attribute *dy_ptr = NULL;
data_attr = fan_platform_data->fan_attrs + i;
sysfs_data_entry = get_fan_access_data(data_attr->aname);
if (sysfs_data_entry == NULL)
{
printk(KERN_ERR "%s: Wrong attribute name provided by user '%s'\n", __FUNCTION__, data_attr->aname);
continue;
}
dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL);
dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1];
strcpy((char *)dy_ptr->dev_attr.attr.name, data_attr->aname);
dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode;
dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show;
dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store;
dy_ptr->index = sysfs_data_entry->a_ptr->index;
data->fan_attribute_list[i] = &dy_ptr->dev_attr.attr;
strcpy(data->attr_info[i].name, data_attr->aname);
data->attr_info[i].valid = 0;
mutex_init(&data->attr_info[i].update_lock);
/*Create a duplicate entry*/
get_fan_duplicate_sysfs(dy_ptr->index, new_str);
if (strcmp(new_str,""))
{
dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL);
dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1];
strcpy((char *)dy_ptr->dev_attr.attr.name, new_str);
dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode;
dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show;
dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store;
dy_ptr->index = sysfs_data_entry->a_ptr->index;
data->fan_attribute_list[num+j] = &dy_ptr->dev_attr.attr;
j++;
strcpy(new_str, "");
}
}
data->fan_attribute_list[i+j] = NULL;
data->fan_attribute_group.attrs = data->fan_attribute_list;
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &data->fan_attribute_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: fan '%s'\n",
dev_name(data->hwmon_dev), client->name);
/* Add a support for post probe function */
if (pddf_fan_ops.post_probe)
{
status = (pddf_fan_ops.post_probe)(client, dev_id);
if (status != 0)
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->fan_attribute_group);
exit_free:
/* Free all the allocated attributes */
for (i=0; data->fan_attribute_list[i]!=NULL; i++)
{
struct sensor_device_attribute *ptr = (struct sensor_device_attribute *)data->fan_attribute_list[i];
kfree(ptr);
}
pddf_dbg(FAN, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__);
kfree(data);
exit:
return status;
}
static int pddf_fan_remove(struct i2c_client *client)
{
int i = 0, ret = 0;
struct sensor_device_attribute *ptr = NULL;
struct fan_data *data = i2c_get_clientdata(client);
FAN_PDATA *platdata = (FAN_PDATA *)client->dev.platform_data;
FAN_DATA_ATTR *platdata_sub = platdata->fan_attrs;
if (pddf_fan_ops.pre_remove)
{
ret = (pddf_fan_ops.pre_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN pre_remove function failed\n");
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->fan_attribute_group);
for (i=0; data->fan_attribute_list[i]!=NULL; i++)
{
ptr = (struct sensor_device_attribute *)data->fan_attribute_list[i];
kfree(ptr);
}
pddf_dbg(FAN, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__);
kfree(data);
if (platdata_sub) {
printk(KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__);
kfree(platdata_sub);
}
if (platdata) {
printk(KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__);
kfree(platdata);
}
if (pddf_fan_ops.post_remove)
{
ret = (pddf_fan_ops.post_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN post_remove function failed\n");
}
return 0;
}
/* Addresses to scan */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
static const struct i2c_device_id pddf_fan_id[] = {
{ "fan_ctrl", 0 },
{ "fan_cpld", 1 },
{}
};
MODULE_DEVICE_TABLE(i2c, pddf_fan_id);
static struct i2c_driver pddf_fan_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DRVNAME,
},
.probe = pddf_fan_probe,
.remove = pddf_fan_remove,
.id_table = pddf_fan_id,
.address_list = normal_i2c,
};
static int __init pddf_fan_init(void)
{
int status = 0;
if (pddf_fan_ops.pre_init)
{
status = (pddf_fan_ops.pre_init)();
if (status!=0)
return status;
}
status = i2c_add_driver(&pddf_fan_driver);
if (status!=0)
return status;
if (pddf_fan_ops.post_init)
{
status = (pddf_fan_ops.post_init)();
if (status!=0)
return status;
}
return status;
}
static void __exit pddf_fan_exit(void)
{
if (pddf_fan_ops.pre_exit) (pddf_fan_ops.pre_exit)();
i2c_del_driver(&pddf_fan_driver);
if (pddf_fan_ops.post_exit) (pddf_fan_ops.post_exit)();
}
module_init(pddf_fan_init);
module_exit(pddf_fan_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("pddf_fan driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,280 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to create I2C client for FAN controller
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_fan_defs.h"
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void *get_fan_access_data(char *);
extern void* get_device_table(char *name);
extern void delete_device_table(char *name);
FAN_DATA fan_data = {0};
/* FAN CLIENT DATA */
PDDF_DATA_ATTR(num_fantrays, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.num_fantrays, NULL);
PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&fan_data.fan_attr.aname, NULL);
PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&fan_data.fan_attr.devtype, NULL);
PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&fan_data.fan_attr.devname, NULL);
PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.devaddr, NULL);
PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.offset, NULL);
PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.mask, NULL);
PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&fan_data.fan_attr.cmpval, NULL);
PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.fan_attr.len, NULL);
PDDF_DATA_ATTR(attr_mult, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&fan_data.fan_attr.mult, NULL);
PDDF_DATA_ATTR(attr_is_divisor, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UCHAR, sizeof(unsigned char), (void*)&fan_data.fan_attr.is_divisor, NULL);
PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&fan_data, NULL);
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&fan_data, (void*)&pddf_data);
static struct attribute *fan_attributes[] = {
&attr_num_fantrays.dev_attr.attr,
&attr_attr_name.dev_attr.attr,
&attr_attr_devtype.dev_attr.attr,
&attr_attr_devname.dev_attr.attr,
&attr_attr_devaddr.dev_attr.attr,
&attr_attr_offset.dev_attr.attr,
&attr_attr_mask.dev_attr.attr,
&attr_attr_cmpval.dev_attr.attr,
&attr_attr_len.dev_attr.attr,
&attr_attr_mult.dev_attr.attr,
&attr_attr_is_divisor.dev_attr.attr,
&attr_attr_ops.dev_attr.attr,
&attr_dev_ops.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_fan_client_data_group = {
.attrs = fan_attributes,
};
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
FAN_DATA *fdata = (FAN_DATA *)(ptr->addr);
FAN_SYSFS_ATTR_DATA_ENTRY *entry_ptr;
fdata->fan_attrs[fdata->len] = fdata->fan_attr;
entry_ptr = get_fan_access_data(fdata->fan_attrs[fdata->len].aname);
if (entry_ptr != NULL && entry_ptr->a_ptr != NULL)
{
fdata->fan_attrs[fdata->len].access_data = entry_ptr->a_ptr ;
}
fdata->len++;
memset(&fdata->fan_attr, 0, sizeof(fdata->fan_attr));
return count;
}
struct i2c_board_info *i2c_get_fan_board_info(FAN_DATA *fdata, NEW_DEV_ATTR *cdata)
{
int num = fdata->len;
int i = 0;
static struct i2c_board_info board_info;
FAN_PDATA *fan_platform_data;
if (strcmp(cdata->dev_type, "fan_ctrl")==0 ||
strcmp(cdata->dev_type, "fan_eeprom")==0 ||
strcmp(cdata->dev_type, "fan_cpld")==0 )
{
/* Allocate the fan_platform_data */
fan_platform_data = (FAN_PDATA *)kzalloc(sizeof(FAN_PDATA), GFP_KERNEL);
fan_platform_data->fan_attrs = (FAN_DATA_ATTR *)kzalloc(num*sizeof(FAN_DATA_ATTR), GFP_KERNEL);
fan_platform_data->num_fantrays = fdata->num_fantrays;
fan_platform_data->len = fdata->len;
for (i=0;i<num;i++)
{
fan_platform_data->fan_attrs[i] = fdata->fan_attrs[i];
}
board_info = (struct i2c_board_info) {
.platform_data = fan_platform_data,
};
board_info.addr = cdata->dev_addr;
strcpy(board_info.type, cdata->dev_type);
}
else
{
printk(KERN_ERR "%s:Unknown type of device %s. Unable to create I2C client for it\n",__FUNCTION__, cdata->dev_type);
}
return &board_info;
}
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
FAN_DATA *fdata = (FAN_DATA *)(ptr->addr);
NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
struct i2c_board_info *board_info;
struct i2c_client *client_ptr;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
adapter = i2c_get_adapter(cdata->parent_bus);
board_info = i2c_get_fan_board_info(fdata, cdata);
/* Populate the platform data for fan */
client_ptr = i2c_new_device(adapter, board_info);
if(client_ptr != NULL)
{
i2c_put_adapter(adapter);
pddf_dbg(FAN, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr);
add_device_table(cdata->i2c_name, (void*)client_ptr);
}
else
{
i2c_put_adapter(adapter);
goto free_data;
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name);
if (client_ptr)
{
pddf_dbg(FAN, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
delete_device_table(cdata->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
goto clear_data;
free_data:
if (board_info->platform_data)
{
FAN_PDATA *fan_platform_data = board_info->platform_data;
if (fan_platform_data->fan_attrs)
{
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__);
kfree(fan_platform_data->fan_attrs);
}
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__);
kfree(fan_platform_data);
}
clear_data:
memset(fdata, 0, sizeof(FAN_DATA));
/*TODO: free the data cdata->data if data is dynal=mically allocated*/
memset(cdata, 0, sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *fan_kobj;
static struct kobject *i2c_kobj;
int __init pddf_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(FAN, "PDDF FAN MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
fan_kobj = kobject_create_and_add("fan", device_kobj);
if(!fan_kobj)
return -ENOMEM;
i2c_kobj = kobject_create_and_add("i2c", fan_kobj);
if(!i2c_kobj)
return -ENOMEM;
ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(i2c_kobj);
kobject_put(fan_kobj);
return ret;
}
pddf_dbg(FAN, "CREATED FAN I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(i2c_kobj, &pddf_fan_client_data_group);
if (ret)
{
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(fan_kobj);
return ret;
}
pddf_dbg(FAN, "CREATED PDDF FAN DATA SYSFS GROUP\n");
return ret;
}
void __exit pddf_data_exit(void)
{
pddf_dbg(FAN, "PDDF FAN MODULE.. exit\n");
sysfs_remove_group(i2c_kobj, &pddf_fan_client_data_group);
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(fan_kobj);
pddf_dbg(FAN, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'fan'\n",__FUNCTION__);
return;
}
module_init(pddf_data_init);
module_exit(pddf_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("fan platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
obj-m := pddf_gpio_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,223 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* PDDF generic kernle module to create the I2C client for pca955x type of GPIO module
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_gpio_defs.h"
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void* get_device_table(char *name);
extern void delete_device_table(char *name);
static int base_gpio_num = 0xf0;
GPIO_DATA gpio_data = {0};
/* GPIO CLIENT DATA */
PDDF_DATA_ATTR(gpio_base, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&gpio_data.gpio_base, NULL);
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&gpio_data, (void*)&pddf_data);
static struct attribute *gpio_attributes[] = {
&attr_gpio_base.dev_attr.attr,
&attr_dev_ops.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_gpio_client_data_group = {
.attrs = gpio_attributes,
};
struct i2c_board_info *i2c_get_gpio_board_info(GPIO_DATA* mdata, NEW_DEV_ATTR *device_data)
{
static struct i2c_board_info board_info;
struct pca953x_platform_data *gpio_platform_data=NULL;
int def_num_gpios, base;
gpio_platform_data = (struct pca953x_platform_data *)kzalloc(sizeof (struct pca953x_platform_data), GFP_KERNEL);
if (strncmp(device_data->dev_type, "pca9554", strlen("pca9554")) == 0 ||
strncmp(device_data->dev_type, "pca9534", strlen("pca9534")) == 0 ||
strncmp(device_data->dev_type, "pca9538", strlen("pca9538")) == 0)
def_num_gpios = 0x8;
else if (strncmp(device_data->dev_type, "pca9555", strlen("pca9555")) == 0 ||
strncmp(device_data->dev_type, "pca9535", strlen("pca9535")) == 0 ||
strncmp(device_data->dev_type, "pca9539", strlen("pca9539")) == 0 ||
strncmp(device_data->dev_type, "pca9575", strlen("pca9575")) == 0)
def_num_gpios = 0x10;
else if (strncmp(device_data->dev_type, "pca9698", strlen("pca9698")) == 0 ||
strncmp(device_data->dev_type, "pca9505", strlen("pca9505")) == 0)
def_num_gpios = 0x28;
else
{
printk(KERN_ERR "%s: Unknown type of gpio device\n", __FUNCTION__);
return NULL;
}
if(mdata->gpio_base == 0) {
base = base_gpio_num;
base_gpio_num += def_num_gpios;
}
else {
base = mdata->gpio_base;
}
gpio_platform_data->gpio_base = base;
board_info = (struct i2c_board_info) {
.platform_data = gpio_platform_data,
};
board_info.addr = device_data->dev_addr;
strcpy(board_info.type, device_data->dev_type);
return &board_info;
}
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
GPIO_DATA *gpio_ptr = (GPIO_DATA *)(ptr->addr);
NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
struct i2c_board_info *board_info;
struct i2c_client *client_ptr;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
adapter = i2c_get_adapter(device_ptr->parent_bus);
board_info = i2c_get_gpio_board_info(gpio_ptr, device_ptr);
/*pddf_dbg(KERN_ERR "Creating a client %s on 0x%x, platform_data 0x%x\n", board_info->type, board_info->addr, board_info->platform_data);*/
client_ptr = i2c_new_device(adapter, board_info);
i2c_put_adapter(adapter);
if (client_ptr != NULL)
{
pddf_dbg(GPIO, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
add_device_table(device_ptr->i2c_name, (void*)client_ptr);
}
else
{
kfree(board_info);
goto free_data;
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name);
if (client_ptr)
{
struct pca953x_platform_data *gpio_platform_data = (struct pca953x_platform_data *)client_ptr->dev.platform_data;
pddf_dbg(GPIO, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
/*TODO: Nullyfy the platform data*/
if (gpio_platform_data)
kfree(gpio_platform_data);
delete_device_table(device_ptr->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
free_data:
memset(gpio_ptr, 0, sizeof(GPIO_DATA));
/*TODO: free the device_ptr->data is dynamically allocated*/
memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *gpio_kobj;
int __init gpio_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(GPIO, "GPIO_DATA MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
gpio_kobj = kobject_create_and_add("gpio", device_kobj);
if(!gpio_kobj)
return -ENOMEM;
ret = sysfs_create_group(gpio_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(gpio_kobj);
return ret;
}
pddf_dbg(GPIO, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(gpio_kobj, &pddf_gpio_client_data_group);
if (ret)
{
sysfs_remove_group(gpio_kobj, &pddf_clients_data_group);
kobject_put(gpio_kobj);
return ret;
}
pddf_dbg(GPIO, "CREATED GPIO DATA SYSFS GROUP\n");
return ret;
}
void __exit gpio_data_exit(void)
{
pddf_dbg(GPIO, "GPIO_DATA MODULE.. exit\n");
sysfs_remove_group(gpio_kobj, &pddf_gpio_client_data_group);
sysfs_remove_group(gpio_kobj, &pddf_clients_data_group);
kobject_put(gpio_kobj);
pddf_dbg(GPIO, KERN_ERR "%s: Removed the kobjects for 'gpio'\n",__FUNCTION__);
return;
}
module_init(gpio_data_init);
module_exit(gpio_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("gpio platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,135 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform I2C client defines/structures header file
*/
#ifndef __PDDF_CLIENT_DEFS_H__
#define __PDDF_CLIENT_DEFS_H__
#include <linux/i2c.h>
#define PSU "PDDF_PSU"
#define LED "PDDF_LED"
#define FAN "PDDF_FAN"
#define CLIENT "PDDF_CLIENT"
#define CPLD "PDDF_CPLD"
#define CPLDMUX "PDDF_CPLDMUX"
#define MUX "PDDF_MUX"
#define GPIO "PDDF_GPIO"
#define SYSSTATUS "PDDF_SYSSTATUS"
#define XCVR "PDDF_XCVR"
#define PDDF_DEBUG
#ifdef PDDF_DEBUG
#define pddf_dbg(filter,...) printk("%s\t", filter); printk(KERN_CONT __VA_ARGS__)
#else
#define pddf_dbg(...)
#endif
#define GEN_NAME_SIZE 32
#define ERR_STR_SIZE 128
typedef struct pddf_data_attribute{
struct device_attribute dev_attr;
int type;
int len;
char *addr;
char *data;
}PDDF_ATTR;
#define PDDF_DATA_ATTR(_name, _mode, _show, _store, _type, _len, _addr, _data) \
struct pddf_data_attribute attr_##_name = { .dev_attr = __ATTR(_name, _mode, _show, _store), \
.type = _type , \
.len = _len , \
.addr = _addr, \
.data = _data }
enum attribute_data_type {
PDDF_CHAR,
PDDF_UCHAR,
PDDF_INT_HEX, // integer represented in HEX
PDDF_INT_DEC, // integer represented in DECIMAL
PDDF_USHORT, // HEX
PDDF_UINT32 // HEX
};
// PSU Specific details
typedef struct NEW_DEV_ATTR
{
char i2c_type[GEN_NAME_SIZE];
char i2c_name[GEN_NAME_SIZE];
int parent_bus;
char dev_type[GEN_NAME_SIZE];
int dev_id;
int dev_addr;
char *data;
int error;
char errstr[ERR_STR_SIZE];
}NEW_DEV_ATTR;
extern NEW_DEV_ATTR pddf_data;
extern struct attribute_group pddf_clients_data_group;
extern ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf);
struct kobject* get_device_i2c_kobj(void);
void set_attr_data(void * ptr);
void set_error_code(int, char *);
ssize_t show_error_code(struct device *dev, struct device_attribute *da, char *buf);
ssize_t show_all_devices(struct device *dev, struct device_attribute *da, char *buf);
void traverse_device_table(void );
/*Various Ops hook which can be used by vendors to provide some deviation from usual pddf functionality*/
struct pddf_ops_t
{
/*Module init ops*/
int (*pre_init)(void);
int (*post_init)(void);
/*probe ops*/
int (*pre_probe)(struct i2c_client *, const struct i2c_device_id *);
int (*post_probe)(struct i2c_client *, const struct i2c_device_id *);
/*remove ops*/
int (*pre_remove)(struct i2c_client *);
int (*post_remove)(struct i2c_client *);
/*Module exit ops*/
void (*pre_exit)(void);
void (*post_exit)(void);
};
typedef struct PDEVICE
{
struct hlist_node node;
char name[GEN_NAME_SIZE];
void *data;
}PDEVICE;
void add_device_table(char *name, void *ptr);
#endif

View File

@ -0,0 +1,31 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform CPLD defines/structures header file
*/
#ifndef __PDDF_CPLD_DEFS_H__
#define __PDDF_CPLD_DEFS_H__
/* CPLD DATA - DATA FOR CPLD CLIENT READ/WRITE*/
typedef struct CPLD_DATA
{
struct mutex cpld_lock;
uint16_t reg_addr;
}PDDF_CPLD_DATA;
#endif

View File

@ -0,0 +1,76 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform CPLDMUX defines/structures header file
*/
#ifndef __PDDF_CPLDMUX_DEFS_H__
#define __PDDF_CPLDMUX_DEFS_H__
#include <linux/i2c-mux.h>
#define MAX_CPLDMUX_CHAN 64
typedef struct CPLDMUX_CHAN_DATA
{
int chan_num;
char chan_device[128]; /* Could be multiple devices, mentioned as " " seperated array */
int cpld_devaddr;
int cpld_offset;
int cpld_sel;
int cpld_desel;
}PDDF_CPLDMUX_CHAN_DATA;
/* CPLDMUX DATA - DATA FOR CPLDMUX CLIENT*/
typedef struct CPLDMUX_DATA
{
int base_chan;
int num_chan;
int chan_cache;
uint32_t cpld_addr;
char cpld_name[32];
PDDF_CPLDMUX_CHAN_DATA chan_data[MAX_CPLDMUX_CHAN];
}PDDF_CPLDMUX_DATA;
typedef struct CPLDMUX_PDATA
{
int parent_bus;
int base_chan;
int num_chan;
int chan_cache;
struct i2c_client *cpld;
PDDF_CPLDMUX_CHAN_DATA *chan_data;
}PDDF_CPLDMUX_PDATA;
typedef struct CPLDMUX_PRIV_DATA{
struct i2c_adapter *parent;
uint32_t last_chan; /* Will be used in case channel caching is enabled */
PDDF_CPLDMUX_PDATA data;
}PDDF_CPLDMUX_PRIV_DATA;
typedef struct pldmux_ops_t
{
int (*select)(struct i2c_mux_core *muxc, uint32_t chan);
int (*deselect)(struct i2c_mux_core *muxc, uint32_t chan);
}PDDF_CPLDMUX_OPS;
int pddf_cpldmux_select_default(struct i2c_mux_core *muxc, uint32_t chan);
int pddf_cpldmux_deselect_default(struct i2c_mux_core *muxc, uint32_t chan);
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#endif

View File

@ -0,0 +1,37 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
*
* 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.
*
* Description
* FAN driver api declarations
*/
#ifndef __PDDF_FAN_API_H__
#define __PDDF_FAN_API_H__
extern int pddf_fan_post_probe_default(struct i2c_client *client, const struct i2c_device_id *dev_id);
extern void get_fan_duplicate_sysfs(int idx, char *str);
extern ssize_t fan_show_default(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t fan_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern int sonic_i2c_get_fan_present_default(void *client, FAN_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_fan_rpm_default(void *client, FAN_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_fan_direction_default(void *client, FAN_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_fan_pwm_default(void *client, FAN_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_fan_fault_default(void *client, FAN_DATA_ATTR *adata, void *data);
extern int sonic_i2c_set_fan_pwm_default(void *client, FAN_DATA_ATTR *adata, void *data);
#endif

View File

@ -0,0 +1,91 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform FAN defines/structures header file
*/
#ifndef __PDDF_FAN_DEFS_H__
#define __PDDF_FAN_DEFS_H__
#define MAX_NUM_FAN 6
#define MAX_FAN_ATTRS 128
#define ATTR_NAME_LEN 32
#define STR_ATTR_SIZE 32
#define DEV_TYPE_LEN 32
/* Each client has this additional data
*/
typedef struct FAN_DATA_ATTR
{
char aname[ATTR_NAME_LEN]; // attr name, taken from enum fan_sysfs_attributes
char devtype[DEV_TYPE_LEN]; // Type of FAN controller, i.e EMC2305, EMC2302, or FAN-CPLD etc
char devname[DEV_TYPE_LEN]; // Name of the device from where this informatin is to be read
uint32_t devaddr;
uint32_t offset;
uint32_t mask;
uint32_t cmpval;
uint32_t len;
int mult; // Multiplication factor to get the actual data
uint8_t is_divisor; // Check if the value is a divisor and mult is dividend
void *access_data;
}FAN_DATA_ATTR;
typedef struct FAN_SYSFS_ATTR_DATA
{
int index;
unsigned short mode;
ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf);
int (*pre_get)(void *client, FAN_DATA_ATTR *adata, void *data);
int (*do_get)(void *client, FAN_DATA_ATTR *adata, void *data);
int (*post_get)(void *client, FAN_DATA_ATTR *adata, void *data);
ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
int (*pre_set)(void *client, FAN_DATA_ATTR *adata, void *data);
int (*do_set)(void *client, FAN_DATA_ATTR *adata, void *data);
int (*post_set)(void *client, FAN_DATA_ATTR *adata, void *data);
void *data;
} FAN_SYSFS_ATTR_DATA;
typedef struct FAN_SYSFS_ATTR_DATA_ENTRY
{
char name[ATTR_NAME_LEN];
FAN_SYSFS_ATTR_DATA *a_ptr;
} FAN_SYSFS_ATTR_DATA_ENTRY;
/* FAN CLIENT DATA - PLATFORM DATA FOR FAN CLIENT */
typedef struct FAN_DATA
{
int num_fantrays; // num of fans controlled by this fan client
FAN_DATA_ATTR fan_attr;
int len; // no of valid attributes for this fan client
FAN_DATA_ATTR fan_attrs[MAX_FAN_ATTRS];
}FAN_DATA;
typedef struct FAN_PDATA
{
int num_fantrays; // num of fans controlled by this fan client
int len; // no of valid attributes for this fan client
FAN_DATA_ATTR *fan_attrs;
}FAN_PDATA;
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#endif

View File

@ -0,0 +1,107 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* FAN driver related data structures
*/
#ifndef __PDDF_FAN_DRIVER_H__
#define __PDDF_FAN_DRIVER_H__
enum fan_sysfs_attributes {
FAN1_PRESENT,
FAN2_PRESENT,
FAN3_PRESENT,
FAN4_PRESENT,
FAN5_PRESENT,
FAN6_PRESENT,
FAN7_PRESENT,
FAN8_PRESENT,
FAN9_PRESENT,
FAN10_PRESENT,
FAN11_PRESENT,
FAN12_PRESENT,
FAN1_DIRECTION,
FAN2_DIRECTION,
FAN3_DIRECTION,
FAN4_DIRECTION,
FAN5_DIRECTION,
FAN6_DIRECTION,
FAN7_DIRECTION,
FAN8_DIRECTION,
FAN9_DIRECTION,
FAN10_DIRECTION,
FAN11_DIRECTION,
FAN12_DIRECTION,
FAN1_INPUT,
FAN2_INPUT,
FAN3_INPUT,
FAN4_INPUT,
FAN5_INPUT,
FAN6_INPUT,
FAN7_INPUT,
FAN8_INPUT,
FAN9_INPUT,
FAN10_INPUT,
FAN11_INPUT,
FAN12_INPUT,
FAN1_PWM,
FAN2_PWM,
FAN3_PWM,
FAN4_PWM,
FAN5_PWM,
FAN6_PWM,
FAN7_PWM,
FAN8_PWM,
FAN9_PWM,
FAN10_PWM,
FAN11_PWM,
FAN12_PWM,
FAN1_FAULT,
FAN2_FAULT,
FAN3_FAULT,
FAN4_FAULT,
FAN5_FAULT,
FAN6_FAULT,
FAN7_FAULT,
FAN8_FAULT,
FAN9_FAULT,
FAN10_FAULT,
FAN11_FAULT,
FAN12_FAULT,
FAN_MAX_ATTR
};
/* Each client has this additional data */
struct fan_attr_info {
char name[ATTR_NAME_LEN];
struct mutex update_lock;
char valid; /* != 0 if registers are valid */
unsigned long last_updated; /* In jiffies */
union {
char strval[STR_ATTR_SIZE];
int intval;
u16 shortval;
u8 charval;
}val;
};
struct fan_data {
struct device *hwmon_dev;
int num_attr;
struct attribute *fan_attribute_list[MAX_FAN_ATTRS];
struct attribute_group fan_attribute_group;
struct fan_attr_info attr_info[MAX_FAN_ATTRS];
};
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform GPIO defines/structures header file
*/
#ifndef __PAL_GPIO_DEFS_H__
#define __PAL_GPIO_DEFS_H__
#include <linux/platform_data/pca953x.h>
/* GPIO CLIENT DATA*/
typedef struct GPIO_DATA
{
int gpio_base; // base bus number of the gpio pins
}GPIO_DATA;
#endif

View File

@ -0,0 +1,120 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* Platform LED related defines and structures
*/
/*****************************************
* kobj list
*****************************************/
struct kobject *platform_kobj=NULL;
struct kobject *led_kobj=NULL;
struct kobject *state_attr_kobj=NULL;
struct kobject *cur_state_kobj=NULL;
/*****************************************
* Static Data provided from user
* space JSON data file
*****************************************/
#define NAME_SIZE 32
typedef enum {
STATUS_LED_COLOR_GREEN,
STATUS_LED_COLOR_GREEN_BLINK,
STATUS_LED_COLOR_RED,
STATUS_LED_COLOR_RED_BLINK,
STATUS_LED_COLOR_AMBER,
STATUS_LED_COLOR_AMBER_BLINK,
STATUS_LED_COLOR_BLUE,
STATUS_LED_COLOR_BLUE_BLINK,
STATUS_LED_COLOR_OFF,
MAX_LED_STATUS
}LED_STATUS;
char* LED_STATUS_STR[] = {
"STATUS_LED_COLOR_GREEN",
"STATUS_LED_COLOR_GREEN_BLINK",
"STATUS_LED_COLOR_RED",
"STATUS_LED_COLOR_RED_BLINK",
"STATUS_LED_COLOR_AMBER",
"STATUS_LED_COLOR_AMBER_BLINK",
"STATUS_LED_COLOR_BLUE",
"STATUS_LED_COLOR_BLUE_BLINK",
"STATUS_LED_COLOR_OFF"
};
typedef struct
{
char bits[NAME_SIZE];
int pos;
int mask_bits;
}MASK_BITS;
typedef struct
{
int swpld_addr;
int swpld_addr_offset;
MASK_BITS bits;
unsigned short value;
} LED_DATA;
typedef struct
{
int state;
char color[NAME_SIZE];
} CUR_STATE_DATA;
typedef struct
{
CUR_STATE_DATA cur_state;
char device_name[NAME_SIZE];
int index;
LED_DATA data[MAX_LED_STATUS];
int swpld_addr;
int swpld_addr_offset;
} LED_OPS_DATA;
typedef enum{
LED_SYS,
LED_PSU,
LED_FAN,
LED_FANTRAY,
LED_DIAG,
LED_LOC,
LED_TYPE_MAX
} LED_TYPE;
char* LED_TYPE_STR[LED_TYPE_MAX] =
{
"LED_SYS",
"LED_PSU",
"LED_FAN",
"LED_FANTRAY",
"LED_DIAG",
"LED_LOC",
};
/*****************************************
* Data exported from kernel for
* user space plugin to get/set
*****************************************/
#define PDDF_LED_DATA_ATTR( _prefix, _name, _mode, _show, _store, _type, _len, _addr) \
struct pddf_data_attribute pddf_dev_##_prefix##_attr_##_name = { .dev_attr = __ATTR(_name, _mode, _show, _store), \
.type = _type , \
.len = _len , \
.addr = _addr }

View File

@ -0,0 +1,31 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform MUX defines/structures header file
*/
#ifndef __PAL_MUX_DEFS_H__
#define __PAL_MUX_DEFS_H__
#include <linux/platform_data/pca954x.h>
/* MUX CLIENT DATA - PLATFORM DATA FOR PSU CLIENT */
typedef struct MUX_DATA
{
int virt_bus; // Virtual base bus number of the mux channels
}MUX_DATA;
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* PSU driver related api declarations
*/
#ifndef __PDDF_PSU_API_H__
#define __PDDF_PSU_API_H__
extern void get_psu_duplicate_sysfs(int idx, char *str);
extern ssize_t psu_show_default(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t psu_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern int sonic_i2c_get_psu_present_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_power_good_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_model_name_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_mfr_id_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_serial_num_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_fan_dir_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_v_out_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_i_out_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_p_out_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_fan1_speed_rpm_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_temp1_input_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_v_in_default(void *client, PSU_DATA_ATTR *adata, void *data);
extern int sonic_i2c_get_psu_i_in_default(void *client, PSU_DATA_ATTR *adata, void *data);
#endif

View File

@ -0,0 +1,90 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform PSU defines/structures header file
*/
#ifndef __PDDF_PSU_DEFS_H__
#define __PDDF_PSU_DEFS_H__
#define MAX_NUM_PSU 5
#define MAX_PSU_ATTRS 32
#define ATTR_NAME_LEN 32
#define STR_ATTR_SIZE 32
#define DEV_TYPE_LEN 32
/* Each client has this additional data
*/
typedef struct PSU_DATA_ATTR
{
char aname[ATTR_NAME_LEN]; // attr name, taken from enum psu_sysfs_attributes
char devtype[DEV_TYPE_LEN]; // either a 'eeprom' or 'cpld', or 'pmbus' attribute
char devname[DEV_TYPE_LEN]; // Name of the device from where this sysfs attr is read
uint32_t devaddr;
uint32_t offset;
uint32_t mask;
uint32_t cmpval;
uint32_t len;
void *access_data;
}PSU_DATA_ATTR;
typedef struct PSU_SYSFS_ATTR_DATA
{
int index;
unsigned short mode;
ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf);
int (*pre_get)(void *client, PSU_DATA_ATTR *adata, void *data);
int (*do_get)(void *client, PSU_DATA_ATTR *adata, void *data);
int (*post_get)(void *client, PSU_DATA_ATTR *adata, void *data);
ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
int (*pre_set)(void *client, PSU_DATA_ATTR *adata, void *data);
int (*do_set)(void *client, PSU_DATA_ATTR *adata, void *data);
int (*post_set)(void *client, PSU_DATA_ATTR *adata, void *data);
void *data;
} PSU_SYSFS_ATTR_DATA;
typedef struct PSU_SYSFS_ATTR_DATA_ENTRY
{
char name[ATTR_NAME_LEN];
PSU_SYSFS_ATTR_DATA *a_ptr;
} PSU_SYSFS_ATTR_DATA_ENTRY;
/* PSU CLIENT DATA - PLATFORM DATA FOR PSU CLIENT */
typedef struct PSU_DATA
{
int idx; // psu index
int num_psu_fans;
PSU_DATA_ATTR psu_attr;
int len; // no of valid attributes for this psu client
PSU_DATA_ATTR psu_attrs[MAX_PSU_ATTRS];
}PSU_DATA;
typedef struct PSU_PDATA
{
int idx; // psu index
int num_psu_fans; // num of fans supported by the PSU
int len; // no of valid attributes for this psu client
PSU_DATA_ATTR *psu_attrs;
}PSU_PDATA;
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#endif

View File

@ -0,0 +1,65 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* PSU driver data structures
*/
#ifndef __PDDF_PSU_DRIVER_H__
#define __PDDF_PSU_DRIVER_H__
enum psu_sysfs_attributes {
PSU_PRESENT,
PSU_MODEL_NAME,
PSU_POWER_GOOD,
PSU_MFR_ID,
PSU_SERIAL_NUM,
PSU_FAN_DIR,
PSU_V_OUT,
PSU_I_OUT,
PSU_P_OUT, /* This is in micro watts to comply with lm-sensors */
PSU_FAN1_SPEED,
PSU_TEMP1_INPUT,
PSU_V_IN,
PSU_I_IN,
PSU_ATTR_MAX
};
/* Every client has psu_data which is divided into per attribute data */
struct psu_attr_info {
char name[ATTR_NAME_LEN];
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u8 status;
union {
char strval[STR_ATTR_SIZE];
int intval;
u16 shortval;
u8 charval;
}val;
};
struct psu_data {
struct device *hwmon_dev;
u8 index;
int num_psu_fans;
int num_attr;
struct attribute *psu_attribute_list[MAX_PSU_ATTRS];
struct attribute_group psu_attribute_group;
struct psu_attr_info attr_info[MAX_PSU_ATTRS];
};
#endif

View File

@ -0,0 +1,51 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* Platform system status module structures
*/
#ifndef __PDDF_SYSSTATUS_DEFS_H__
#define __PDDF_SYSSTATUS_DEFS_H__
#define ATTR_NAME_LEN 32
#define MAX_ATTRS 32
/* SYSSTATUS CLIENT DATA - PLATFORM DATA FOR SYSSTATUS CLIENT */
typedef struct SYSSTATUS_ADDR_ATTR
{
char aname[ATTR_NAME_LEN]; // attr name
uint32_t devaddr;
uint32_t offset;
uint32_t mask;
uint32_t len;
}SYSSTATUS_ADDR_ATTR;
typedef struct SYSSTATUS_DATA
{
int len;
SYSSTATUS_ADDR_ATTR sysstatus_addr_attr;
SYSSTATUS_ADDR_ATTR sysstatus_addr_attrs[MAX_ATTRS];
}SYSSTATUS_DATA;
#endif

View File

@ -0,0 +1,44 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description
* Optics driver related api declarations
*/
#ifndef __PDDF_XCVR_API_H__
#define __PDDF_XCVR_API_H__
extern int sonic_i2c_get_mod_pres(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_intr_status(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_rxlos(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_get_mod_txfault(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_set_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_set_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern int sonic_i2c_set_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data);
extern ssize_t get_module_presence(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t get_module_reset(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t set_module_reset(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern ssize_t get_module_intr_status(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t get_module_lpmode(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t set_module_lpmode(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern ssize_t get_module_rxlos(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t get_module_txdisable(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t set_module_txdisable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern ssize_t get_module_txfault(struct device *dev, struct device_attribute *da, char *buf);
#endif

View File

@ -0,0 +1,121 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description:
* Platform SFP defines/structures header file
*/
#ifndef __PDDF_XCVR_DEFS_H__
#define __PDDF_XCVR_DEFS_H__
#define MAX_NUM_XCVR 5
#define MAX_XCVR_ATTRS 20
typedef struct XCVR_ATTR
{
char aname[32]; // attr name, taken from enum xcvr_sysfs_attributes
char devtype[32]; // either a 'eeprom' or 'cpld', or 'pmbus' attribute
char devname[32]; // name of the device from where this sysfs is to be read
uint32_t devaddr;
uint32_t offset;
uint32_t mask;
uint32_t cmpval;
uint32_t len;
int (*pre_access)(void *client, void *data);
int (*do_access)(void *client, void *data);
int (*post_access)(void *client, void *data);
}XCVR_ATTR;
/* XCVR CLIENT DATA - PLATFORM DATA FOR XCVR CLIENT */
typedef struct XCVR_DATA
{
int idx; // xcvr index
XCVR_ATTR xcvr_attr;
int len; // no of valid attributes for this xcvr client
XCVR_ATTR xcvr_attrs[MAX_XCVR_ATTRS];
}XCVR_DATA;
typedef struct XCVR_PDATA
{
int idx; // xcvr index
unsigned short addr; // i2c address of the device
int len; // no of valid attributes for this xcvr client
XCVR_ATTR *xcvr_attrs;
}XCVR_PDATA;
#define BIT_INDEX(i) (1ULL << (i))
/* List of valid port types */
typedef enum xcvr_port_type_e {
PDDF_PORT_TYPE_INVALID,
PDDF_PORT_TYPE_NOT_PRESENT,
PDDF_PORT_TYPE_SFP,
PDDF_PORT_TYPE_SFP_PLUS,
PDDF_PORT_TYPE_QSFP,
PDDF_PORT_TYPE_QSFP_PLUS,
PDDF_PORT_TYPE_QSFP28
} xcvr_port_type_t;
/* Each client has this additional data
*/
struct xcvr_data {
struct device *xdev;
struct mutex update_lock;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
int index; /* port index */
xcvr_port_type_t port_type;
uint32_t modpres;
uint32_t reset;
uint32_t intr_status;
uint32_t lpmode;
uint32_t rxlos;
uint32_t txdisable;
uint32_t txfault;
};
typedef struct XCVR_SYSFS_ATTR_OPS
{
int index;
ssize_t (*show)(struct device *dev, struct device_attribute *da, char *buf);
int (*pre_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
int (*do_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
int (*post_get)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
ssize_t (*store)(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
int (*pre_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
int (*do_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
int (*post_set)(struct i2c_client *client, XCVR_ATTR *adata, struct xcvr_data *data);
} XCVR_SYSFS_ATTR_OPS;
enum xcvr_sysfs_attributes {
XCVR_PRESENT,
XCVR_RESET,
XCVR_INTR_STATUS,
XCVR_LPMODE,
XCVR_RXLOS,
XCVR_TXDISABLE,
XCVR_TXFAULT,
XCVR_ATTR_MAX
};
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#endif

View File

@ -0,0 +1,4 @@
TARGET := pddf_led_module
obj-m := $(TARGET).o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,659 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to manage various LEDs of a switch
*/
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/hwmon-sysfs.h>
#include "pddf_led_defs.h"
#include "pddf_client_defs.h"
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#define DEBUG 0
LED_OPS_DATA sys_led_ops_data[1]={0};
LED_OPS_DATA* psu_led_ops_data=NULL;
LED_OPS_DATA diag_led_ops_data[1]= {0};
LED_OPS_DATA fan_led_ops_data[1]= {0};
LED_OPS_DATA loc_led_ops_data[1]= {0};
LED_OPS_DATA* fantray_led_ops_data=NULL;
LED_OPS_DATA temp_data={0};
LED_OPS_DATA* dev_list[LED_TYPE_MAX] = {
sys_led_ops_data,
NULL,
fan_led_ops_data,
NULL,
diag_led_ops_data,
loc_led_ops_data,
};
int num_psus = 0;
int num_fantrays = 0;
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern ssize_t show_pddf_data(struct device *dev, struct device_attribute *da, char *buf);
extern ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static LED_STATUS find_state_index(const char* state_str) {
int index;
char *ptr = (char *)state_str;
while (*ptr && *ptr!= '\n' && *ptr !='\0') ptr++;
*ptr='\0';
for ( index = 0; index < MAX_LED_STATUS; index++) {
/*int rc = strcmp(state_str, LED_STATUS_STR[index]) ;*/
if (strcmp(state_str, LED_STATUS_STR[index]) == 0 ) {
return index;
}
}
return MAX_LED_STATUS;
}
static LED_TYPE get_dev_type(char* name)
{
LED_TYPE ret = LED_TYPE_MAX;
if(strcasecmp(name, "SYS_LED")==0) {
ret = LED_SYS;
} else if(strcasecmp(name, "FAN_LED")==0) {
ret = LED_FAN;
} else if(strstr(name, "PSU_LED")) {
ret = LED_PSU;
} else if(strcasecmp(name, "DIAG_LED")==0) {
ret = LED_DIAG;
} else if(strcasecmp(name, "LOC_LED")==0) {
ret = LED_LOC;
} else if(strstr(name, "FANTRAY_LED")) {
ret = LED_FANTRAY;
}
#if DEBUG > 1
pddf_dbg(LED, KERN_INFO "LED get_dev_type: %s; %d\n", name, ret);
#endif
return (ret);
}
static int dev_index_check(LED_TYPE type, int index)
{
#if DEBUG
pddf_dbg(LED, "dev_index_check: type:%s index:%d num_psus:%d num_fantrays:%d\n",
LED_TYPE_STR[type], index, num_psus, num_fantrays);
#endif
switch(type)
{
case LED_PSU:
if(index >= num_psus) return (-1);
break;
case LED_FANTRAY:
if(index >= num_fantrays) return (-1);
break;
default:
if(index >= 1) return (-1);
break;
}
return (0);
}
static LED_OPS_DATA* find_led_ops_data(struct device_attribute *da)
{
struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da;
LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr;
LED_TYPE led_type;
if(!ptr || strlen(ptr->device_name)==0 ) return(NULL);
if((led_type=get_dev_type(ptr->device_name))==LED_TYPE_MAX) {
printk(KERN_ERR "PDDF_LED ERROR *%s Unsupported Led Type\n", __func__);
return(NULL);
}
if(dev_index_check(led_type, ptr->index)==-1) {
printk(KERN_ERR "PDDF_LED ERROR %s invalid index: %d for type:%s\n", __func__, ptr->index, ptr->device_name);
return(NULL);
}
#if DEBUG > 1
pddf_dbg(LED, "find_led_ops_data: name:%s; index=%d tempAddr:%p actualAddr:%p\n",
ptr->device_name, ptr->index, ptr, dev_list[led_type]+ptr->index);
#endif
return (dev_list[led_type]+ptr->index);
}
static void print_led_data(LED_OPS_DATA *ptr, LED_STATUS state)
{
int i = 0;
if(!ptr) return ;
pddf_dbg(LED, KERN_INFO "Print %s index:%d num_psus:%d num_fantrays:%d ADDR=%p\n",
ptr->device_name, ptr->index, num_psus, num_fantrays, ptr);
pddf_dbg(LED, KERN_INFO "\tindex: %d\n", ptr->index);
pddf_dbg(LED, KERN_INFO "\tcur_state: %d; %s \n", ptr->cur_state.state, ptr->cur_state.color);
for (i = 0; i< MAX_LED_STATUS; i++) {
if(ptr->data[i].swpld_addr && (i == state || state == -1)) {
pddf_dbg(LED, KERN_INFO "\t\t[%s]: addr/offset:0x%x;0x%x color:%s; value:%x; mask_bits: 0x%x; pos:%d\n",
LED_STATUS_STR[i],
ptr->data[i].swpld_addr, ptr->data[i].swpld_addr_offset,
LED_STATUS_STR[i], ptr->data[i].value, ptr->data[i].bits.mask_bits, ptr->data[i].bits.pos);
}
}
}
ssize_t get_status_led(struct device_attribute *da)
{
int ret=0;
struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da;
LED_OPS_DATA* temp_data_ptr=(LED_OPS_DATA*)_ptr->addr;
LED_OPS_DATA* ops_ptr=find_led_ops_data(da);
uint32_t color_val=0, sys_val=0;
int state=0;
if (!ops_ptr) {
pddf_dbg(LED, KERN_ERR "ERROR %s: Cannot find LED Ptr", __func__);
return (-1);
}
if (ops_ptr->swpld_addr == 0x0) {
pddf_dbg(LED, KERN_ERR "ERROR %s: device: %s %d not configured\n", __func__,
temp_data_ptr->device_name, temp_data_ptr->index);
return (-1);
}
sys_val = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset);
if (sys_val < 0)
return sys_val;
strcpy(temp_data.cur_state.color, "None");
for (state=0; state<MAX_LED_STATUS; state++) {
color_val = (sys_val & ~ops_ptr->data[state].bits.mask_bits);
if ((color_val ^ (ops_ptr->data[state].value<<ops_ptr->data[state].bits.pos))==0) {
strcpy(temp_data.cur_state.color, LED_STATUS_STR[state]);
}
}
#if DEBUG > 1
pddf_dbg(LED, KERN_ERR "Get : %s:%d addr/offset:0x%x; 0x%x value=0x%x [%s]\n",
ops_ptr->device_name, ops_ptr->index,
ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset, sys_val,
temp_data.cur_state.color);
#endif
return(ret);
}
ssize_t set_status_led(struct device_attribute *da)
{
int ret=0;
uint32_t sys_val=0, new_val=0;
LED_STATUS cur_state = MAX_LED_STATUS;
struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da;
LED_OPS_DATA* temp_data_ptr=(LED_OPS_DATA*)_ptr->addr;
LED_OPS_DATA* ops_ptr=find_led_ops_data(da);
char* _buf=temp_data_ptr->cur_state.color;
if (!ops_ptr) {
pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: Cannot find LED Ptr", __func__);
return (-1);
}
if (ops_ptr->swpld_addr == 0x0) {
pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: device: %s %d not configured\n",
__func__, ops_ptr->device_name, ops_ptr->index);
return (-1);
}
pddf_dbg(LED, KERN_ERR "%s: Set [%s;%d] color[%s]\n", __func__,
temp_data_ptr->device_name, temp_data_ptr->index,
temp_data_ptr->cur_state.color);
cur_state = find_state_index(_buf);
if (cur_state == MAX_LED_STATUS) {
pddf_dbg(LED, KERN_ERR "ERROR %s: not supported: %s\n", _buf, __func__);
return (-1);
}
if(ops_ptr->data[cur_state].swpld_addr != 0x0) {
sys_val = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset);
if (sys_val < 0)
return sys_val;
new_val = (sys_val & ops_ptr->data[cur_state].bits.mask_bits) |
(ops_ptr->data[cur_state].value << ops_ptr->data[cur_state].bits.pos);
} else {
pddf_dbg(LED, KERN_ERR "ERROR %s: %s %d state %d; %s not configured\n",__func__,
ops_ptr->device_name, ops_ptr->index, cur_state, _buf);
return (-1);
}
board_i2c_cpld_write(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset, new_val);
pddf_dbg(LED, KERN_INFO "Set color:%s; 0x%x:0x%x sys_val:0x%x new_val:0x%x read:0x%x\n",
LED_STATUS_STR[cur_state],
ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset,
sys_val, new_val,
ret = board_i2c_cpld_read(ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset));
if (ret < 0)
{
pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s: Error %d in reading from cpld(0x%x) offset 0x%x\n", __FUNCTION__, ret, ops_ptr->swpld_addr, ops_ptr->swpld_addr_offset);
return ret;
}
return(ret);
}
ssize_t show_pddf_data(struct device *dev, struct device_attribute *da,
char *buf)
{
int ret = 0;
struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da;
switch(ptr->type)
{
case PDDF_CHAR:
ret = sprintf(buf, "%s\n", ptr->addr);
break;
case PDDF_INT_DEC:
ret = sprintf(buf, "%d\n", *(int*)(ptr->addr));
break;
case PDDF_INT_HEX:
ret = sprintf(buf, "0x%x\n", *(int*)(ptr->addr));
break;
case PDDF_USHORT:
ret = sprintf(buf, "0x%x\n", *(unsigned short *)(ptr->addr));
break;
case PDDF_UINT32:
ret = sprintf(buf, "0x%x\n", *(uint32_t *)(ptr->addr));
break;
default:
break;
}
#if DEBUG > 1
pddf_dbg(LED, "[ READ ] DATA ATTR PTR [%s] TYPE:%d, Value:[%s]\n",
ptr->dev_attr.attr.name, ptr->type, buf);
#endif
return ret;
}
ssize_t store_pddf_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int ret = 0, num = 0;
struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da;
switch(ptr->type)
{
case PDDF_CHAR:
strncpy(ptr->addr, buf, strlen(buf)-1); // to discard newline char form buf
ptr->addr[strlen(buf)-1] = '\0';
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_CHAR VALUE:%s\n",
ptr->dev_attr.attr.name, ptr->addr);
#endif
break;
case PDDF_INT_DEC:
ret = kstrtoint(buf,10,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_DEC VALUE:%d\n",
ptr->dev_attr.attr.name, *(int *)(ptr->addr));
#endif
break;
case PDDF_INT_HEX:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_HEX VALUE:0x%x\n",
ptr->dev_attr.attr.name, *(int *)(ptr->addr));
#endif
break;
case PDDF_USHORT:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(unsigned short *)(ptr->addr) = (unsigned short)num;
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_USHORT VALUE:%x\n",
ptr->dev_attr.attr.name, *(unsigned short *)(ptr->addr));
#endif
break;
case PDDF_UINT32:
ret = kstrtoint(buf,16,&num);
if (ret==0)
*(uint32_t *)(ptr->addr) = (uint32_t)num;
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR [%s] PDDF_UINT32 VALUE:%d\n",
ptr->dev_attr.attr.name, *(uint32_t *)(ptr->addr));
#endif
break;
default:
break;
}
return count;
}
static int load_led_ops_data(struct device_attribute *da, LED_STATUS state)
{
struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da;
LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr;
LED_TYPE led_type;
LED_OPS_DATA* ops_ptr=NULL;
if(!ptr || strlen(ptr->device_name)==0 ) {
pddf_dbg(LED, KERN_INFO "SYSTEM_LED: load_led_ops_data return -1 device_name:%s\n", ptr? ptr->device_name:"NULL");
return(-1);
}
if(ptr->device_name)
{
pddf_dbg(LED, KERN_INFO "[%s]: load_led_ops_data: index=%d addr=0x%x;0x%x valu=0x%x\n",
ptr->device_name, ptr->index, ptr->swpld_addr, ptr->swpld_addr_offset, ptr->data[0].value);
}
if((led_type=get_dev_type(ptr->device_name))==LED_TYPE_MAX) {
pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR *%s Unsupported Led Type\n", __func__);
return(-1);
}
if(dev_index_check(led_type, ptr->index)==-1) {
pddf_dbg(LED, KERN_ERR "PDDF_LED ERROR %s invalid index: %d for type:%d\n", __func__, ptr->index, led_type);
return(-1);
}
ops_ptr = dev_list[led_type]+ptr->index;
memcpy(ops_ptr->device_name, ptr->device_name, sizeof(ops_ptr->device_name));
ops_ptr->index = ptr->index;
memcpy(&ops_ptr->data[state], &ptr->data[0], sizeof(LED_DATA));
ops_ptr->data[state].swpld_addr = ptr->swpld_addr;
ops_ptr->data[state].swpld_addr_offset = ptr->swpld_addr_offset;
ops_ptr->swpld_addr = ptr->swpld_addr;
ops_ptr->swpld_addr_offset = ptr->swpld_addr_offset;
print_led_data(dev_list[led_type]+ptr->index, state);
memset(ptr, 0, sizeof(LED_OPS_DATA));
return (0);
}
static int show_led_ops_data(struct device_attribute *da)
{
LED_OPS_DATA* ops_ptr=find_led_ops_data(da);
print_led_data(ops_ptr, -1);
return(0);
}
static int verify_led_ops_data(struct device_attribute *da)
{
struct pddf_data_attribute *_ptr = (struct pddf_data_attribute *)da;
LED_OPS_DATA* ptr=(LED_OPS_DATA*)_ptr->addr;
LED_OPS_DATA* ops_ptr=find_led_ops_data(da);
if(ops_ptr)
memcpy(ptr, ops_ptr, sizeof(LED_OPS_DATA));
else
{
pddf_dbg(LED, "SYSTEM_LED: verify_led_ops_data: Failed to find ops_ptr name:%s; index=%d\n", ptr->device_name, ptr->index);
}
return (0);
}
ssize_t dev_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
#if DEBUG
pddf_dbg(LED, KERN_INFO "dev_operation [%s]\n", buf);
#endif
if(strstr(buf, "STATUS_LED_COLOR")!= NULL) {
LED_STATUS index = find_state_index(buf);
if (index < MAX_LED_STATUS ) {
load_led_ops_data(da, index);
} else {
printk(KERN_ERR "PDDF_ERROR %s: Invalid state for dev_ops %s", __FUNCTION__, buf);
}
}
else if(strncmp(buf, "show", strlen("show"))==0 ) {
show_led_ops_data(da);
}
else if(strncmp(buf, "verify", strlen("verify"))==0 ) {
verify_led_ops_data(da);
}
else if(strncmp(buf, "get_status", strlen("get_status"))==0 ) {
get_status_led(da);
}
else if(strncmp(buf, "set_status", strlen("set_status"))==0 ) {
set_status_led(da);
}
else {
printk(KERN_ERR "PDDF_ERROR %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
return(count);
}
ssize_t store_config_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int ret, num;
struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da;
if(strncmp(ptr->dev_attr.attr.name, "num_psus", strlen("num_psus"))==0 ) {
ret = kstrtoint(buf,10,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
if(psu_led_ops_data == NULL) {
if ((psu_led_ops_data = kzalloc(num * sizeof(LED_OPS_DATA), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "PDDF_LED ERROR failed to allocate memory for PSU LED\n");
return (count);
}
pddf_dbg(LED, "Allocate PSU LED Memory ADDR=%p\n", psu_led_ops_data);
dev_list[LED_PSU]=psu_led_ops_data;
}
#if DEBUG
pddf_dbg(LED, "[ WRITE ] ATTR CONFIG [%s] VALUE:%d; %d\n",
ptr->dev_attr.attr.name, num, num_psus);
#endif
return(count);
}
if(strncmp(ptr->dev_attr.attr.name, "num_fantrays", strlen("num_fantrays"))==0 ) {
ret = kstrtoint(buf,10,&num);
if (ret==0)
*(int *)(ptr->addr) = num;
if (fantray_led_ops_data == NULL) {
if ((fantray_led_ops_data = kzalloc(num * sizeof(LED_OPS_DATA), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "PDDF_LED ERROR failed to allocate memory for FANTRAY LED\n");
return (count);
}
pddf_dbg(LED, "Allocate FanTray LED Memory ADDR=%p\n", fantray_led_ops_data);
dev_list[LED_FANTRAY]=fantray_led_ops_data;
}
#if DEBUG
pddf_dbg(LED, "[ WRITE ] ATTR CONFIG [%s] VALUE:%d; %d\n",
ptr->dev_attr.attr.name, num, num_fantrays);
#endif
return(count);
}
return (count);
}
ssize_t store_bits_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int len = 0, num1 = 0, num2 = 0, i=0, rc1=0, rc2=0;
char mask=0xFF;
char *pptr=NULL;
char bits[NAME_SIZE];
struct pddf_data_attribute *ptr = (struct pddf_data_attribute *)da;
MASK_BITS* bits_ptr=(MASK_BITS*)(ptr->addr);
strncpy(bits_ptr->bits, buf, strlen(buf)-1); // to discard newline char form buf
bits_ptr->bits[strlen(buf)-1] = '\0';
if((pptr=strstr(buf,":")) != NULL) {
len=pptr-buf;
sprintf(bits, buf);
bits[len]='\0';
rc1=kstrtoint(bits,16,&num1);
if (rc1==0)
{
sprintf(bits, ++pptr);
rc2=kstrtoint(bits,16,&num2);
if (rc2==0)
{
for (i=num2; i<=num1; i++) {
mask &= ~(1 << i);
}
bits_ptr->mask_bits = mask;
bits_ptr->pos = num2;
}
}
} else {
rc1=kstrtoint(buf,16,&num1);
if (rc1==0)
{
bits_ptr->mask_bits = mask & ~(1 << num1);
bits_ptr->pos = num1;
}
}
#if DEBUG
pddf_dbg(LED, KERN_ERR "[ WRITE ] ATTR PTR Bits [%s] VALUE:%s mask:0x%x; pos:0x%x\n",
ptr->dev_attr.attr.name, bits_ptr->bits, bits_ptr->mask_bits, bits_ptr->pos);
#endif
return (count);
}
/**************************************************************************
* platform/ attributes
**************************************************************************/
PDDF_LED_DATA_ATTR(platform, num_psus, S_IWUSR|S_IRUGO, show_pddf_data,
store_config_data, PDDF_INT_DEC, sizeof(int), (void*)&num_psus);
PDDF_LED_DATA_ATTR(platform, num_fantrays, S_IWUSR|S_IRUGO, show_pddf_data,
store_config_data, PDDF_INT_DEC, sizeof(int), (void*)&num_fantrays);
struct attribute* attrs_platform[]={
&pddf_dev_platform_attr_num_psus.dev_attr.attr,
&pddf_dev_platform_attr_num_fantrays.dev_attr.attr,
NULL,
};
struct attribute_group attr_group_platform={
.attrs = attrs_platform,
};
/**************************************************************************
* led/ attributes
**************************************************************************/
PDDF_LED_DATA_ATTR(dev, device_name, S_IWUSR|S_IRUGO, show_pddf_data,
store_pddf_data, PDDF_CHAR, NAME_SIZE, (void*)&temp_data.device_name);
PDDF_LED_DATA_ATTR(dev, index, S_IWUSR|S_IRUGO, show_pddf_data,
store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&temp_data.index);
PDDF_LED_DATA_ATTR(dev, swpld_addr, S_IWUSR|S_IRUGO, show_pddf_data,
store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&temp_data.swpld_addr);
PDDF_LED_DATA_ATTR(dev, swpld_addr_offset, S_IWUSR|S_IRUGO, show_pddf_data,
store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&temp_data.swpld_addr_offset);
PDDF_LED_DATA_ATTR(dev, dev_ops , S_IWUSR, NULL,
dev_operation, PDDF_CHAR, NAME_SIZE, (void*)&temp_data);
struct attribute* attrs_dev[]={
&pddf_dev_dev_attr_device_name.dev_attr.attr,
&pddf_dev_dev_attr_index.dev_attr.attr,
&pddf_dev_dev_attr_swpld_addr.dev_attr.attr,
&pddf_dev_dev_attr_swpld_addr_offset.dev_attr.attr,
&pddf_dev_dev_attr_dev_ops.dev_attr.attr,
NULL,
};
struct attribute_group attr_group_dev={
.attrs = attrs_dev,
};
/**************************************************************************
* state_attr/ attributes
**************************************************************************/
#define LED_DEV_STATE_ATTR_GROUP(name, func) \
PDDF_LED_DATA_ATTR(name, bits, S_IWUSR|S_IRUGO, show_pddf_data, \
store_bits_data, PDDF_CHAR, NAME_SIZE, func.bits.bits); \
PDDF_LED_DATA_ATTR(name, value, S_IWUSR|S_IRUGO, show_pddf_data, \
store_pddf_data, PDDF_USHORT, sizeof(unsigned short), func.value); \
struct attribute* attrs_##name[]={ \
&pddf_dev_##name##_attr_bits.dev_attr.attr, \
&pddf_dev_##name##_attr_value.dev_attr.attr, \
NULL, \
}; \
struct attribute_group attr_group_##name={ \
.attrs = attrs_##name, \
}; \
LED_DEV_STATE_ATTR_GROUP(state_attr, (void*)&temp_data.data[0])
/**************************************************************************
* cur_state/ attributes
**************************************************************************/
PDDF_LED_DATA_ATTR(cur_state, color, S_IWUSR|S_IRUGO, show_pddf_data,
store_pddf_data, PDDF_CHAR, NAME_SIZE, (void*)&temp_data.cur_state.color);
struct attribute* attrs_cur_state[]={
&pddf_dev_cur_state_attr_color.dev_attr.attr,
NULL,
};
struct attribute_group attr_group_cur_state={
.attrs = attrs_cur_state,
};
/*************************************************************************/
#define KOBJ_FREE(obj) \
if(obj) kobject_put(obj); \
void free_kobjs(void)
{
KOBJ_FREE(cur_state_kobj)
KOBJ_FREE(state_attr_kobj)
KOBJ_FREE(led_kobj)
KOBJ_FREE(platform_kobj)
}
int KBOJ_CREATE(char* name, struct kobject* parent, struct kobject** child)
{
if (parent) {
*child = kobject_create_and_add(name, parent);
} else {
printk(KERN_ERR "PDDF_LED ERROR to create %s kobj; null parent\n", name);
free_kobjs();
return (-ENOMEM);
}
return (0);
}
int LED_DEV_ATTR_CREATE(struct kobject *kobj, const struct attribute_group *attr, const char* name)
{
int status = sysfs_create_group(kobj, attr);
if(status) {
pddf_dbg(LED, KERN_ERR "Driver ERROR: sysfs_create %s failed rc=%d\n", name, status);
}
return (status);
}
static int __init led_init(void) {
struct kobject *device_kobj;
pddf_dbg(LED, KERN_INFO "PDDF GENERIC LED MODULE init..\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
KBOJ_CREATE("platform", device_kobj, &platform_kobj);
KBOJ_CREATE("led", device_kobj, &led_kobj);
KBOJ_CREATE("state_attr", led_kobj, &state_attr_kobj);
KBOJ_CREATE("cur_state", led_kobj, &cur_state_kobj);
LED_DEV_ATTR_CREATE(platform_kobj, &attr_group_platform, "attr_group_platform");
LED_DEV_ATTR_CREATE(led_kobj, &attr_group_dev, "attr_group_dev");
LED_DEV_ATTR_CREATE(state_attr_kobj, &attr_group_state_attr, "attr_group_state_attr");
LED_DEV_ATTR_CREATE(cur_state_kobj, &attr_group_cur_state, "attr_group_cur_state");
return (0);
}
static void __exit led_exit(void) {
pddf_dbg(LED, "PDDF GENERIC LED MODULE exit..\n");
free_kobjs();
if(psu_led_ops_data) kfree(psu_led_ops_data);
if(fantray_led_ops_data) kfree(fantray_led_ops_data);
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("led driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
obj-m := pddf_mux_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,211 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to create I2C client for pca954x type of multiplexer
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_mux_defs.h"
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void* get_device_table(char *name);
extern void delete_device_table(char *name);
MUX_DATA mux_data = {0};
/* MUX CLIENT DATA */
PDDF_DATA_ATTR(virt_bus, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&mux_data.virt_bus, NULL);
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&mux_data, (void*)&pddf_data);
static struct attribute *mux_attributes[] = {
&attr_virt_bus.dev_attr.attr,
&attr_dev_ops.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_mux_client_data_group = {
.attrs = mux_attributes,
};
struct i2c_board_info *i2c_get_mux_board_info(MUX_DATA* mdata, NEW_DEV_ATTR *device_data)
{
static struct i2c_board_info board_info;
static struct pca954x_platform_mode platform_modes[8];
static struct pca954x_platform_data mux_platform_data;
int num_modes, i;
if (strncmp(device_data->dev_type, "pca9548", strlen("pca9548")) == 0)
num_modes = 8;
else if (strncmp(device_data->dev_type, "pca9546", strlen("pca9546")) == 0)
num_modes = 6;
else
{
printk(KERN_ERR "%s: Unknown type of mux device\n", __FUNCTION__);
return NULL;
}
for(i = 0; i < num_modes; i++) {
platform_modes[i] = (struct pca954x_platform_mode) {
.adap_id = (mdata->virt_bus + i),
.deselect_on_exit = 1,
};
}
mux_platform_data = (struct pca954x_platform_data) {
.modes = platform_modes,
.num_modes = num_modes,
};
board_info = (struct i2c_board_info) {
.platform_data = &mux_platform_data,
};
board_info.addr = device_data->dev_addr;
strcpy(board_info.type, device_data->dev_type);
return &board_info;
}
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
MUX_DATA *mux_ptr = (MUX_DATA *)(ptr->addr);
NEW_DEV_ATTR *device_ptr = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
struct i2c_board_info *board_info;
struct i2c_client *client_ptr;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
adapter = i2c_get_adapter(device_ptr->parent_bus);
board_info = i2c_get_mux_board_info(mux_ptr, device_ptr);
client_ptr = i2c_new_device(adapter, board_info);
if (client_ptr != NULL)
{
i2c_put_adapter(adapter);
pddf_dbg(MUX, KERN_ERR "Created %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
add_device_table(device_ptr->i2c_name, (void*)client_ptr);
}
else
{
i2c_put_adapter(adapter);
goto free_data;
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(device_ptr->i2c_name);
if (client_ptr)
{
pddf_dbg(MUX, KERN_ERR "Removing %s client: 0x%p\n", device_ptr->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
/*TODO: Nullyfy the platform data*/
delete_device_table(device_ptr->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", device_ptr->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
free_data:
memset(mux_ptr, 0, sizeof(MUX_DATA));
/*TODO: free the device_ptr->data is dynamically allocated*/
memset(device_ptr, 0 , sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *mux_kobj;
int __init mux_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(MUX, "MUX_DATA MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
mux_kobj = kobject_create_and_add("mux", device_kobj);
if(!mux_kobj)
return -ENOMEM;
ret = sysfs_create_group(mux_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(mux_kobj);
return ret;
}
pddf_dbg(MUX, "CREATED PDDF I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(mux_kobj, &pddf_mux_client_data_group);
if (ret)
{
sysfs_remove_group(mux_kobj, &pddf_clients_data_group);
kobject_put(mux_kobj);
return ret;
}
pddf_dbg(MUX, "CREATED MUX DATA SYSFS GROUP\n");
return ret;
}
void __exit mux_data_exit(void)
{
pddf_dbg(MUX, "MUX_DATA MODULE.. exit\n");
sysfs_remove_group(mux_kobj, &pddf_mux_client_data_group);
sysfs_remove_group(mux_kobj, &pddf_clients_data_group);
kobject_put(mux_kobj);
pddf_dbg(MUX, KERN_ERR "%s: Removed the kobjects for 'mux'\n",__FUNCTION__);
return;
}
module_init(mux_data_init);
module_exit(mux_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("mux platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
subdir-m := driver
obj-m := pddf_psu_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,6 @@
TARGET = pddf_psu_driver_module
obj-m := $(TARGET).o
$(TARGET)-objs := pddf_psu_api.o pddf_psu_driver.o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,707 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description of various APIs related to PSU component
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_psu_defs.h"
#include "pddf_psu_driver.h"
/*#define PSU_DEBUG*/
#ifdef PSU_DEBUG
#define psu_dbg(...) printk(__VA_ARGS__)
#else
#define psu_dbg(...)
#endif
void get_psu_duplicate_sysfs(int idx, char *str)
{
switch (idx)
{
case PSU_V_OUT:
strcpy(str, "in3_input");
break;
case PSU_I_OUT:
strcpy(str, "curr2_input");
break;
case PSU_P_OUT:
strcpy(str, "power2_input");
break;
case PSU_FAN1_SPEED:
strcpy(str, "fan1_input");
break;
case PSU_TEMP1_INPUT:
strcpy(str, "temp1_input");
break;
default:
break;
}
return;
}
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;
}
int psu_update_hw(struct device *dev, struct psu_attr_info *info, PSU_DATA_ATTR *udata)
{
int status = 0;
struct i2c_client *client = to_i2c_client(dev);
PSU_SYSFS_ATTR_DATA *sysfs_attr_data = NULL;
mutex_lock(&info->update_lock);
sysfs_attr_data = udata->access_data;
if (sysfs_attr_data->pre_set != NULL)
{
status = (sysfs_attr_data->pre_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->do_set != NULL)
{
status = (sysfs_attr_data->do_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->post_set != NULL)
{
status = (sysfs_attr_data->post_set)(client, udata, info);
if (status!=0)
printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
mutex_unlock(&info->update_lock);
return 0;
}
int psu_update_attr(struct device *dev, struct psu_attr_info *data, PSU_DATA_ATTR *udata)
{
int status = 0;
struct i2c_client *client = to_i2c_client(dev);
PSU_SYSFS_ATTR_DATA *sysfs_attr_data=NULL;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid)
{
dev_dbg(&client->dev, "Starting update for %s\n", data->name);
sysfs_attr_data = udata->access_data;
if (sysfs_attr_data->pre_get != NULL)
{
status = (sysfs_attr_data->pre_get)(client, udata, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->do_get != NULL)
{
status = (sysfs_attr_data->do_get)(client, udata, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
if (sysfs_attr_data->post_get != NULL)
{
status = (sysfs_attr_data->post_get)(client, udata, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, udata->aname);
}
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return 0;
}
ssize_t psu_show_default(struct device *dev, struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct psu_data *data = i2c_get_clientdata(client);
PSU_PDATA *pdata = (PSU_PDATA *)(client->dev.platform_data);
PSU_DATA_ATTR *usr_data = NULL;
struct psu_attr_info *sysfs_attr_info = NULL;
int i, status=0;
u16 value = 0;
int exponent, mantissa;
int multiplier = 1000;
char new_str[ATTR_NAME_LEN] = "";
PSU_SYSFS_ATTR_DATA *ptr = NULL;
for (i=0;i<data->num_attr;i++)
{
ptr = (PSU_SYSFS_ATTR_DATA *)pdata->psu_attrs[i].access_data;
get_psu_duplicate_sysfs(ptr->index , new_str);
if ( strcmp(attr->dev_attr.attr.name, pdata->psu_attrs[i].aname) == 0 || strcmp(attr->dev_attr.attr.name, new_str) == 0 )
{
sysfs_attr_info = &data->attr_info[i];
usr_data = &pdata->psu_attrs[i];
strcpy(new_str, "");
}
}
if (sysfs_attr_info==NULL || usr_data==NULL)
{
printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name);
goto exit;
}
psu_update_attr(dev, sysfs_attr_info, usr_data);
switch(attr->index)
{
case PSU_PRESENT:
case PSU_POWER_GOOD:
status = sysfs_attr_info->val.intval;
return sprintf(buf, "%d\n", status);
break;
case PSU_MODEL_NAME:
case PSU_MFR_ID:
case PSU_SERIAL_NUM:
case PSU_FAN_DIR:
return sprintf(buf, "%s\n", sysfs_attr_info->val.strval);
break;
case PSU_V_OUT:
case PSU_I_OUT:
case PSU_V_IN:
case PSU_I_IN:
multiplier = 1000;
value = sysfs_attr_info->val.shortval;
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
if (exponent >= 0)
return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier);
else
return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
break;
case PSU_P_OUT:
multiplier = 1000000;
value = sysfs_attr_info->val.shortval;
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
if (exponent >= 0)
return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier);
else
return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
break;
case PSU_FAN1_SPEED:
value = sysfs_attr_info->val.shortval;
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
if (exponent >= 0)
return sprintf(buf, "%d\n", (mantissa << exponent));
else
return sprintf(buf, "%d\n", (mantissa) / (1 << -exponent));
break;
case PSU_TEMP1_INPUT:
multiplier = 1000;
value = sysfs_attr_info->val.shortval;
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
if (exponent >= 0)
return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier);
else
return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
break;
default:
printk(KERN_ERR "%s: Unable to find attribute index for %s\n", __FUNCTION__, usr_data->aname);
goto exit;
}
exit:
return sprintf(buf, "%d\n", status);
}
ssize_t psu_store_default(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct psu_data *data = i2c_get_clientdata(client);
PSU_PDATA *pdata = (PSU_PDATA *)(client->dev.platform_data);
PSU_DATA_ATTR *usr_data = NULL;
struct psu_attr_info *sysfs_attr_info = NULL;
int i;
for (i=0;i<data->num_attr;i++)
{
if (strcmp(data->attr_info[i].name, attr->dev_attr.attr.name) == 0 && strcmp(pdata->psu_attrs[i].aname, attr->dev_attr.attr.name) == 0)
{
sysfs_attr_info = &data->attr_info[i];
usr_data = &pdata->psu_attrs[i];
}
}
if (sysfs_attr_info==NULL || usr_data==NULL) {
printk(KERN_ERR "%s is not supported attribute for this client\n", attr->dev_attr.attr.name);
goto exit;
}
switch(attr->index)
{
/*No write attributes for now in PSU*/
default:
goto exit;
}
psu_update_hw(dev, sysfs_attr_info, usr_data);
exit:
return count;
}
int sonic_i2c_get_psu_present_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0;
int val = 0;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
if (strncmp(adata->devtype, "cpld", strlen("cpld")) == 0)
{
val = board_i2c_cpld_read(adata->devaddr , adata->offset);
if (val < 0)
return val;
padata->val.intval = ((val & adata->mask) == adata->cmpval);
psu_dbg(KERN_ERR "%s: status_value = 0x%x\n", __FUNCTION__, padata->val.intval);
}
return status;
}
int sonic_i2c_get_psu_power_good_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0;
int val = 0;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
if (strncmp(adata->devtype, "cpld", strlen("cpld")) == 0)
{
val = board_i2c_cpld_read(adata->devaddr , adata->offset);
if (val < 0)
return val;
padata->val.intval = ((val & adata->mask) == adata->cmpval);
psu_dbg(KERN_ERR "%s: status_value = 0x%x\n", __FUNCTION__, padata->val.intval);
}
return status;
}
int sonic_i2c_get_psu_model_name_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
char model[32]=""; //temporary placeholder for model name
uint8_t offset = (uint8_t)adata->offset;
int data_len = adata->len;
while (retry)
{
status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, model);
if (unlikely(status<0))
{
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
model[0] = '\0';
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read model name from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
model[data_len-1] = '\0';
}
if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0)
strncpy(padata->val.strval, model+1, data_len-1);
else
strncpy(padata->val.strval, model, data_len);
psu_dbg(KERN_ERR "%s: status = %d, model_name : %s\n", __FUNCTION__, status, padata->val.strval);
return 0;
}
int sonic_i2c_get_psu_mfr_id_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
char mfr_id[16] = ""; // temporary place holder for mfr_id
uint8_t offset = (uint8_t)adata->offset;
int data_len = adata->len;
while (retry)
{
status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, mfr_id);
if (unlikely(status<0))
{
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
mfr_id[0] = '\0';
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read mfr_id from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
mfr_id[data_len-1] = '\0';
}
if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0)
strncpy(padata->val.strval, mfr_id+1, data_len-1);
else
strncpy(padata->val.strval, mfr_id, data_len);
psu_dbg(KERN_ERR "%s: status = %d, mfr_id : %s\n", __FUNCTION__, status, padata->val.strval);
return 0;
}
int sonic_i2c_get_psu_serial_num_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
char serial[32] = ""; // temporary string to store the serial num
uint8_t offset = (uint8_t)adata->offset;
int data_len = adata->len;
while (retry)
{
status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, serial);
if (unlikely(status<0))
{
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
serial[0] = '\0';
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read serial num from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
serial[data_len-1] = '\0';
}
if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0)
strncpy(padata->val.strval, serial+1, data_len-1);
else
strncpy(padata->val.strval, serial, data_len);
psu_dbg(KERN_ERR "%s: status = %d, serial_num : %s\n", __FUNCTION__, status, padata->val.strval);
return 0;
}
int sonic_i2c_get_psu_fan_dir_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
char fan_dir[5] = "";
uint8_t offset = (uint8_t)adata->offset;
int data_len = adata->len;
while (retry)
{
status = i2c_smbus_read_i2c_block_data((struct i2c_client *)client, offset, data_len-1, fan_dir);
if (unlikely(status<0))
{
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
fan_dir[0] = '\0';
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read fan_dir from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
fan_dir[data_len-1] = '\0';
}
if (strncmp(adata->devtype, "pmbus", strlen("pmbus")) == 0)
strncpy(padata->val.strval, fan_dir+1, data_len-1);
else
strncpy(padata->val.strval, fan_dir, data_len);
psu_dbg(KERN_ERR "%s: status = %d, fan_dir : %s\n", __FUNCTION__, status, padata->val.strval);
return 0;
}
int sonic_i2c_get_psu_v_out_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read v_out from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: v_out : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_i_out_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read i_out from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: i_out : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_p_out_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read p_out from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: p_out : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_v_in_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read v_in from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: v_in : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_i_in_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read i_in from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: i_in : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_fan1_speed_rpm_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read fan1_speed_rpm from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: fan1_speed_rpm : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}
int sonic_i2c_get_psu_temp1_input_default(void *client, PSU_DATA_ATTR *adata, void *data)
{
int status = 0, retry = 10;
struct psu_attr_info *padata = (struct psu_attr_info *)data;
uint8_t offset = (uint8_t)adata->offset;
while (retry) {
status = i2c_smbus_read_word_data((struct i2c_client *)client, offset);
if (unlikely(status < 0)) {
msleep(60);
retry--;
continue;
}
break;
}
if (status < 0)
{
padata->val.shortval = 0;
dev_dbg(&((struct i2c_client *)client)->dev, "unable to read temp1_input from (0x%x)\n", ((struct i2c_client *)client)->addr);
}
else
{
padata->val.shortval = status;
}
psu_dbg(KERN_ERR "%s: temp1_input : %d\n", __FUNCTION__, padata->val.shortval);
return 0;
}

View File

@ -0,0 +1,381 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module driver for PSU
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_psu_defs.h"
#include "pddf_psu_driver.h"
#include "pddf_psu_api.h"
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
struct pddf_ops_t pddf_psu_ops = {
.pre_init = NULL,
.post_init = NULL,
.pre_probe = NULL,
.post_probe = NULL,
.pre_remove = NULL,
.post_remove = NULL,
.pre_exit = NULL,
.post_exit = NULL,
};
EXPORT_SYMBOL(pddf_psu_ops);
PSU_SYSFS_ATTR_DATA access_psu_present = {PSU_PRESENT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_present_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_present);
PSU_SYSFS_ATTR_DATA access_psu_model_name = {PSU_MODEL_NAME, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_model_name_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_model_name);
PSU_SYSFS_ATTR_DATA access_psu_power_good = {PSU_POWER_GOOD, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_power_good_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_power_good);
PSU_SYSFS_ATTR_DATA access_psu_mfr_id = {PSU_MFR_ID, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_mfr_id_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_mfr_id);
PSU_SYSFS_ATTR_DATA access_psu_serial_num = {PSU_SERIAL_NUM, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_serial_num_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_serial_num);
PSU_SYSFS_ATTR_DATA access_psu_fan_dir = {PSU_FAN_DIR, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_fan_dir_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_fan_dir);
PSU_SYSFS_ATTR_DATA access_psu_v_out = {PSU_V_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_v_out_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_v_out);
PSU_SYSFS_ATTR_DATA access_psu_i_out = {PSU_I_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_i_out_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_i_out);
PSU_SYSFS_ATTR_DATA access_psu_p_out = {PSU_P_OUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_p_out_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_p_out);
PSU_SYSFS_ATTR_DATA access_psu_fan1_speed_rpm = {PSU_FAN1_SPEED, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_fan1_speed_rpm_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_fan1_speed_rpm);
PSU_SYSFS_ATTR_DATA access_psu_temp1_input = {PSU_TEMP1_INPUT, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_temp1_input_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_temp1_input);
PSU_SYSFS_ATTR_DATA access_psu_v_in = {PSU_V_IN, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_v_in_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_v_in);
PSU_SYSFS_ATTR_DATA access_psu_i_in = {PSU_I_IN, S_IRUGO, psu_show_default, NULL, sonic_i2c_get_psu_i_in_default, NULL, NULL, NULL, NULL, NULL};
EXPORT_SYMBOL(access_psu_i_in);
PSU_SYSFS_ATTR_DATA_ENTRY psu_sysfs_attr_data_tbl[]=
{
{ "psu_present", &access_psu_present},
{ "psu_model_name", &access_psu_model_name},
{ "psu_power_good" , &access_psu_power_good},
{ "psu_mfr_id" , &access_psu_mfr_id},
{ "psu_serial_num" , &access_psu_serial_num},
{ "psu_fan_dir" , &access_psu_fan_dir},
{ "psu_v_out" , &access_psu_v_out},
{ "psu_i_out" , &access_psu_i_out},
{ "psu_p_out" , &access_psu_p_out},
{ "psu_fan1_speed_rpm" , &access_psu_fan1_speed_rpm},
{ "psu_temp1_input" , &access_psu_temp1_input},
{ "psu_v_in" , &access_psu_v_in},
{ "psu_i_in" , &access_psu_i_in}
};
void *get_psu_access_data(char *name)
{
int i=0;
for(i=0; i<(sizeof(psu_sysfs_attr_data_tbl)/sizeof(psu_sysfs_attr_data_tbl[0])); i++)
{
if(strcmp(name, psu_sysfs_attr_data_tbl[i].name) ==0)
{
return &psu_sysfs_attr_data_tbl[i];
}
}
return NULL;
}
EXPORT_SYMBOL(get_psu_access_data);
static int psu_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct psu_data *data;
int status =0;
int i,num, j=0;
PSU_PDATA *psu_platform_data;
PSU_DATA_ATTR *data_attr;
PSU_SYSFS_ATTR_DATA_ENTRY *sysfs_data_entry;
char new_str[ATTR_NAME_LEN] = "";
if (client == NULL) {
printk("NULL Client.. \n");
goto exit;
}
if (pddf_psu_ops.pre_probe)
{
status = (pddf_psu_ops.pre_probe)(client, dev_id);
if (status != 0)
goto exit;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct psu_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
dev_info(&client->dev, "chip found\n");
/* Take control of the platform data */
psu_platform_data = (PSU_PDATA *)(client->dev.platform_data);
num = psu_platform_data->len;
data->index = psu_platform_data->idx - 1;
data->num_psu_fans = psu_platform_data->num_psu_fans;
data->num_attr = num;
/* Create and Add supported attr in the 'attributes' list */
for (i=0; i<num; i++)
{
/*struct attribute *aptr = NULL;*/
struct sensor_device_attribute *dy_ptr = NULL;
data_attr = psu_platform_data->psu_attrs + i;
sysfs_data_entry = get_psu_access_data(data_attr->aname);
if (sysfs_data_entry == NULL)
{
printk(KERN_ERR "%s: Wrong attribute name provided by user '%s'\n", __FUNCTION__, data_attr->aname);
continue;
}
dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL);
dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1];
strcpy((char *)dy_ptr->dev_attr.attr.name, data_attr->aname);
dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode;
dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show;
dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store;
dy_ptr->index = sysfs_data_entry->a_ptr->index;
data->psu_attribute_list[i] = &dy_ptr->dev_attr.attr;
strcpy(data->attr_info[i].name, data_attr->aname);
data->attr_info[i].valid = 0;
mutex_init(&data->attr_info[i].update_lock);
/*Create a duplicate entry*/
get_psu_duplicate_sysfs(dy_ptr->index, new_str);
if (strcmp(new_str,""))
{
dy_ptr = (struct sensor_device_attribute *)kzalloc(sizeof(struct sensor_device_attribute)+ATTR_NAME_LEN, GFP_KERNEL);
dy_ptr->dev_attr.attr.name = (char *)&dy_ptr[1];
strcpy((char *)dy_ptr->dev_attr.attr.name, new_str);
dy_ptr->dev_attr.attr.mode = sysfs_data_entry->a_ptr->mode;
dy_ptr->dev_attr.show = sysfs_data_entry->a_ptr->show;
dy_ptr->dev_attr.store = sysfs_data_entry->a_ptr->store;
dy_ptr->index = sysfs_data_entry->a_ptr->index;
data->psu_attribute_list[num+j] = &dy_ptr->dev_attr.attr;
j++;
strcpy(new_str,"");
}
}
data->psu_attribute_list[i+j] = NULL;
data->psu_attribute_group.attrs = data->psu_attribute_list;
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &data->psu_attribute_group);
if (status) {
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
dev_info(&client->dev, "%s: psu '%s'\n",
dev_name(data->hwmon_dev), client->name);
/* Add a support for post probe function */
if (pddf_psu_ops.post_probe)
{
status = (pddf_psu_ops.post_probe)(client, dev_id);
if (status != 0)
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->psu_attribute_group);
exit_free:
/* Free all the allocated attributes */
for (i=0;data->psu_attribute_list[i]!=NULL;i++)
{
struct sensor_device_attribute *ptr = (struct sensor_device_attribute *)data->psu_attribute_list[i];
kfree(ptr);
data->psu_attribute_list[i] = NULL;
pddf_dbg(PSU, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__);
}
kfree(data);
exit:
return status;
}
static int psu_remove(struct i2c_client *client)
{
int i=0, ret = 0;
struct psu_data *data = i2c_get_clientdata(client);
PSU_PDATA *platdata = (PSU_PDATA *)client->dev.platform_data; // use dev_get_platdata()
PSU_DATA_ATTR *platdata_sub = platdata->psu_attrs;
struct sensor_device_attribute *ptr = NULL;
if (pddf_psu_ops.pre_remove)
{
ret = (pddf_psu_ops.pre_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN pre_remove function failed\n");
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->psu_attribute_group);
for (i=0; data->psu_attribute_list[i]!=NULL; i++)
{
ptr = (struct sensor_device_attribute *)data->psu_attribute_list[i];
kfree(ptr);
data->psu_attribute_list[i] = NULL;
}
pddf_dbg(PSU, KERN_ERR "%s: Freed all the memory allocated for attributes\n", __FUNCTION__);
kfree(data);
if (platdata_sub) {
printk(KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__);
kfree(platdata_sub);
}
if (platdata) {
printk(KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__);
kfree(platdata);
}
if (pddf_psu_ops.post_remove)
{
ret = (pddf_psu_ops.post_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN post_remove function failed\n");
}
return ret;
}
enum psu_intf
{
eeprom_intf,
smbus_intf
};
static const struct i2c_device_id psu_id[] = {
{"psu_eeprom", eeprom_intf},
{"psu_pmbus", smbus_intf},
{}
};
MODULE_DEVICE_TABLE(i2c, psu_id);
static struct i2c_driver psu_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "psu",
},
.probe = psu_probe,
.remove = psu_remove,
.id_table = psu_id,
.address_list = normal_i2c,
};
int example_fun(void)
{
pddf_dbg(PSU, KERN_ERR "CALLING FUN...\n");
return 0;
}
EXPORT_SYMBOL(example_fun);
int psu_init(void)
{
int status = 0;
if (pddf_psu_ops.pre_init)
{
status = (pddf_psu_ops.pre_init)();
if (status!=0)
return status;
}
pddf_dbg(PSU, KERN_ERR "GENERIC_PSU_DRIVER.. init Invoked..\n");
status = i2c_add_driver(&psu_driver);
if (status!=0)
return status;
if (pddf_psu_ops.post_init)
{
status = (pddf_psu_ops.post_init)();
if (status!=0)
return status;
}
return status;
}
EXPORT_SYMBOL(psu_init);
void __exit psu_exit(void)
{
pddf_dbg(PSU, "GENERIC_PSU_DRIVER.. exit\n");
if (pddf_psu_ops.pre_exit) (pddf_psu_ops.pre_exit)();
i2c_del_driver(&psu_driver);
if (pddf_psu_ops.post_exit) (pddf_psu_ops.post_exit)();
}
EXPORT_SYMBOL(psu_exit);
module_init(psu_init);
module_exit(psu_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("psu driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,283 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to create I2C client for PSU
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_psu_defs.h"
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void *get_psu_access_data(char *);
extern void* get_device_table(char *name);
extern void delete_device_table(char *name);
PSU_DATA psu_data = {0};
/* PSU CLIENT DATA */
PDDF_DATA_ATTR(psu_idx, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.idx, NULL);
PDDF_DATA_ATTR(psu_fans, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.num_psu_fans, NULL);
PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&psu_data.psu_attr.aname, NULL);
PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&psu_data.psu_attr.devtype, NULL);
PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&psu_data.psu_attr.devname, NULL);
PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.devaddr, NULL);
PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.offset, NULL);
PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.mask, NULL);
PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&psu_data.psu_attr.cmpval, NULL);
PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&psu_data.psu_attr.len, NULL);
PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&psu_data, NULL);
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&psu_data, (void*)&pddf_data);
static struct attribute *psu_attributes[] = {
&attr_psu_idx.dev_attr.attr,
&attr_psu_fans.dev_attr.attr,
&attr_attr_name.dev_attr.attr,
&attr_attr_devtype.dev_attr.attr,
&attr_attr_devname.dev_attr.attr,
&attr_attr_devaddr.dev_attr.attr,
&attr_attr_offset.dev_attr.attr,
&attr_attr_mask.dev_attr.attr,
&attr_attr_cmpval.dev_attr.attr,
&attr_attr_len.dev_attr.attr,
&attr_attr_ops.dev_attr.attr,
&attr_dev_ops.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_psu_client_data_group = {
.attrs = psu_attributes,
};
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
PSU_DATA *pdata = (PSU_DATA *)(ptr->addr);
PSU_SYSFS_ATTR_DATA_ENTRY *access_ptr;
pdata->psu_attrs[pdata->len] = pdata->psu_attr;
access_ptr = get_psu_access_data(pdata->psu_attrs[pdata->len].aname);
if (access_ptr != NULL && access_ptr->a_ptr != NULL)
{
pdata->psu_attrs[pdata->len].access_data = access_ptr->a_ptr ;
}
pdata->len++;
memset(&pdata->psu_attr, 0, sizeof(pdata->psu_attr));
return count;
}
struct i2c_board_info *i2c_get_psu_board_info(PSU_DATA *pdata, NEW_DEV_ATTR *cdata)
{
int num = pdata->len;
int i = 0;
static struct i2c_board_info board_info;
PSU_PDATA *psu_platform_data;
if (strcmp(cdata->dev_type, "psu_pmbus")==0 || strcmp(cdata->dev_type, "psu_eeprom")==0 )
{
/* Allocate the psu_platform_data */
psu_platform_data = (PSU_PDATA *)kzalloc(sizeof(PSU_PDATA), GFP_KERNEL);
psu_platform_data->psu_attrs = (PSU_DATA_ATTR *)kzalloc(num*sizeof(PSU_DATA_ATTR), GFP_KERNEL);
psu_platform_data->idx = pdata->idx;
psu_platform_data->num_psu_fans = pdata->num_psu_fans;
psu_platform_data->len = pdata->len;
for (i=0;i<num;i++)
{
psu_platform_data->psu_attrs[i] = pdata->psu_attrs[i];
}
board_info = (struct i2c_board_info) {
.platform_data = psu_platform_data,
};
board_info.addr = cdata->dev_addr;
strcpy(board_info.type, cdata->dev_type);
}
else
{
printk(KERN_ERR "%s:Unknown type of device %s. Unable to clreate I2C client for it\n",__FUNCTION__, cdata->dev_type);
}
return &board_info;
}
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
PSU_DATA *pdata = (PSU_DATA *)(ptr->addr);
NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
struct i2c_board_info *board_info;
struct i2c_client *client_ptr;
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
adapter = i2c_get_adapter(cdata->parent_bus);
board_info = i2c_get_psu_board_info(pdata, cdata);
/* Populate the platform data for psu */
client_ptr = i2c_new_device(adapter, board_info);
if(client_ptr != NULL)
{
i2c_put_adapter(adapter);
pddf_dbg(PSU, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name , (void *)client_ptr);
add_device_table(cdata->i2c_name, (void*)client_ptr);
}
else
{
i2c_put_adapter(adapter);
goto free_data;
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name);
if (client_ptr)
{
pddf_dbg(PSU, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
delete_device_table(cdata->i2c_name);
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
goto clear_data;
free_data:
if (board_info->platform_data)
{
PSU_PDATA *psu_platform_data = board_info->platform_data;
if (psu_platform_data->psu_attrs)
{
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__);
kfree(psu_platform_data->psu_attrs);
}
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__);
kfree(psu_platform_data);
}
clear_data:
memset(pdata, 0, sizeof(PSU_DATA));
/*TODO: free the data cdata->data if data is dynal=mically allocated*/
memset(cdata, 0, sizeof(NEW_DEV_ATTR));
return count;
}
static struct kobject *psu_kobj;
static struct kobject *i2c_kobj;
int __init pddf_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(PSU, "PDDF_DATA MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
psu_kobj = kobject_create_and_add("psu", device_kobj);
if(!psu_kobj)
return -ENOMEM;
i2c_kobj = kobject_create_and_add("i2c", psu_kobj);
if(!i2c_kobj)
return -ENOMEM;
ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(i2c_kobj);
kobject_put(psu_kobj);
return ret;
}
pddf_dbg(PSU, "CREATED PSU I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(i2c_kobj, &pddf_psu_client_data_group);
if (ret)
{
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(psu_kobj);
return ret;
}
pddf_dbg(PSU, "CREATED PDDF PSU DATA SYSFS GROUP\n");
return ret;
}
void __exit pddf_data_exit(void)
{
pddf_dbg(PSU, "PDDF_DATA MODULE.. exit\n");
sysfs_remove_group(i2c_kobj, &pddf_psu_client_data_group);
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(psu_kobj);
pddf_dbg(PSU, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'psu'\n",__FUNCTION__);
return;
}
module_init(pddf_data_init);
module_exit(pddf_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("psu platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
TARGET := pddf_sysstatus_module
obj-m := $(TARGET).o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,235 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module for system status registers
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_sysstatus_defs.h"
SYSSTATUS_DATA sysstatus_data = {0};
extern int board_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int board_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
ssize_t show_sysstatus_data(struct device *dev, struct device_attribute *da, char *buf);
PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32,
(void*)&sysstatus_data.sysstatus_addr_attr.aname, NULL);
PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32,
sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.devaddr , NULL);
PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32,
sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.offset, NULL);
PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32,
sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.mask , NULL);
PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32,
sizeof(uint32_t), (void*)&sysstatus_data.sysstatus_addr_attr.len , NULL);
PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&sysstatus_data, NULL);
static struct attribute *sysstatus_addr_attributes[] = {
&attr_attr_name.dev_attr.attr,
&attr_attr_devaddr.dev_attr.attr,
&attr_attr_offset.dev_attr.attr,
&attr_attr_mask.dev_attr.attr,
&attr_attr_len.dev_attr.attr,
&attr_attr_ops.dev_attr.attr,
NULL
};
PDDF_DATA_ATTR(board_info, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, 32, NULL, NULL);
PDDF_DATA_ATTR(cpld1_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(cpld2_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(cpld3_version, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(power_module_status, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset1, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset2, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset3, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset4, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset5, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset6, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset7, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(system_reset8, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(misc1, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(misc2, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
PDDF_DATA_ATTR(misc3, S_IWUSR|S_IRUGO, show_sysstatus_data, NULL, PDDF_UINT32, sizeof(uint32_t), NULL, NULL);
static struct attribute *sysstatus_data_attributes[] = {
&attr_board_info.dev_attr.attr,
&attr_cpld1_version.dev_attr.attr,
&attr_cpld2_version.dev_attr.attr,
&attr_cpld3_version.dev_attr.attr,
&attr_power_module_status.dev_attr.attr,
&attr_system_reset1.dev_attr.attr,
&attr_system_reset2.dev_attr.attr,
&attr_system_reset3.dev_attr.attr,
&attr_system_reset4.dev_attr.attr,
&attr_system_reset5.dev_attr.attr,
&attr_system_reset6.dev_attr.attr,
&attr_system_reset7.dev_attr.attr,
&attr_system_reset8.dev_attr.attr,
&attr_misc1.dev_attr.attr,
&attr_misc2.dev_attr.attr,
&attr_misc3.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_sysstatus_addr_group = {
.attrs = sysstatus_addr_attributes,
};
static const struct attribute_group pddf_sysstatus_data_group = {
.attrs = sysstatus_data_attributes,
};
static struct kobject *sysstatus_addr_kobj;
static struct kobject *sysstatus_data_kobj;
ssize_t show_sysstatus_data(struct device *dev, struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
SYSSTATUS_DATA *data = &sysstatus_data;
struct SYSSTATUS_ADDR_ATTR *sysstatus_addr_attrs = NULL;
int i, status ;
for (i=0;i<MAX_ATTRS;i++)
{
if (strcmp(data->sysstatus_addr_attrs[i].aname, attr->dev_attr.attr.name) == 0 )
{
sysstatus_addr_attrs = &data->sysstatus_addr_attrs[i];
}
}
if (sysstatus_addr_attrs==NULL )
{
printk(KERN_DEBUG "%s is not supported attribute for this client\n",data->sysstatus_addr_attrs[i].aname);
status = 0;
}
else
{
status = board_i2c_cpld_read( sysstatus_addr_attrs->devaddr, sysstatus_addr_attrs->offset);
}
return sprintf(buf, "0x%x\n", (status&sysstatus_addr_attrs->mask));
}
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
SYSSTATUS_DATA *pdata = (SYSSTATUS_DATA *)(ptr->addr);
pdata->sysstatus_addr_attrs[pdata->len] = pdata->sysstatus_addr_attr;
pdata->len++;
pddf_dbg(SYSSTATUS, KERN_ERR "%s: Populating the data for %s\n", __FUNCTION__, pdata->sysstatus_addr_attr.aname);
memset(&pdata->sysstatus_addr_attr, 0, sizeof(pdata->sysstatus_addr_attr));
return count;
}
int __init sysstatus_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(SYSSTATUS, "PDDF SYSSTATUS MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
sysstatus_addr_kobj = kobject_create_and_add("sysstatus", device_kobj);
if(!sysstatus_addr_kobj)
return -ENOMEM;
sysstatus_data_kobj = kobject_create_and_add("sysstatus_data", sysstatus_addr_kobj);
if(!sysstatus_data_kobj)
return -ENOMEM;
ret = sysfs_create_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group);
if (ret)
{
kobject_put(sysstatus_addr_kobj);
return ret;
}
ret = sysfs_create_group(sysstatus_data_kobj, &pddf_sysstatus_data_group);
if (ret)
{
sysfs_remove_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group);
kobject_put(sysstatus_data_kobj);
kobject_put(sysstatus_addr_kobj);
return ret;
}
return ret;
}
void __exit sysstatus_data_exit(void)
{
pddf_dbg(SYSSTATUS, "PDDF SYSSTATUS MODULE.. exit\n");
sysfs_remove_group(sysstatus_data_kobj, &pddf_sysstatus_data_group);
sysfs_remove_group(sysstatus_addr_kobj, &pddf_sysstatus_addr_group);
kobject_put(sysstatus_data_kobj);
kobject_put(sysstatus_addr_kobj);
pddf_dbg(SYSSTATUS, KERN_ERR "%s: Removed the kobjects for 'SYSSTATUS'\n",__FUNCTION__);
return;
}
module_init(sysstatus_data_init);
module_exit(sysstatus_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("SYSSTATUS platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,4 @@
subdir-m := driver
obj-m := pddf_xcvr_module.o
CFLAGS_$(obj-m):= -I$(M)/modules/include

View File

@ -0,0 +1,7 @@
TARGET = pddf_xcvr_driver_module
obj-m := $(TARGET).o
$(TARGET)-objs := pddf_xcvr_api.o pddf_xcvr_driver.o
ccflags-y := -I$(M)/modules/include

View File

@ -0,0 +1,909 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* Description of various APIs related to transciever component
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_xcvr_defs.h"
/*#define SFP_DEBUG*/
#ifdef SFP_DEBUG
#define sfp_dbg(...) printk(__VA_ARGS__)
#else
#define sfp_dbg(...)
#endif
extern XCVR_SYSFS_ATTR_OPS xcvr_ops[];
extern void *get_device_table(char *name);
int get_xcvr_module_attr_data(struct i2c_client *client, struct device *dev,
struct device_attribute *da);
int xcvr_i2c_cpld_read(XCVR_ATTR *info)
{
int status = -1;
if (info!=NULL)
{
if (info->len==1)
{
status = board_i2c_cpld_read(info->devaddr , info->offset);
}
else
{
/* Get the I2C client for the CPLD */
struct i2c_client *client_ptr=NULL;
client_ptr = (struct i2c_client *)get_device_table(info->devname);
if (client_ptr)
{
if (info->len==2)
{
status = i2c_smbus_read_word_swapped(client_ptr, info->offset);
}
else
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet");
}
else
printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname);
}
}
return status;
}
int sonic_i2c_get_mod_pres(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t modpres = 0;
if ( strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
modpres = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nMod presence :0x%x, reg_value = 0x%x, devaddr=0x%x, mask=0x%x, offset=0x%x\n", modpres, status, info->devaddr, info->mask, info->offset);
}
}
else if(strcmp(info->devtype, "eeprom") == 0)
{
/* get client client for eeprom - Not Applicable */
}
data->modpres = modpres;
return 0;
}
int sonic_i2c_get_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t modreset=0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
modreset = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nMod Reset :0x%x, reg_value = 0x%x\n", modreset, status);
}
}
else if(strcmp(info->devtype, "eeprom") == 0)
{
/* get client client for eeprom - Not Applicable */
}
data->reset = modreset;
return 0;
}
int sonic_i2c_get_mod_intr_status(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t mod_intr = 0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
mod_intr = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nModule Interrupt :0x%x, reg_value = 0x%x\n", mod_intr, status);
}
}
else if(strcmp(info->devtype, "eeprom") == 0)
{
/* get client client for eeprom - Not Applicable */
}
data->intr_status = mod_intr;
return 0;
}
int sonic_i2c_get_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t lpmode = 0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
lpmode = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nModule LPmode :0x%x, reg_value = 0x%x\n", lpmode, status);
}
}
else if (strcmp(info->devtype, "eeprom") == 0)
{
/* get client client for eeprom - Not Applicable */
}
data->lpmode = lpmode;
return 0;
}
int sonic_i2c_get_mod_rxlos(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t rxlos = 0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
rxlos = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nModule RxLOS :0x%x, reg_value = 0x%x\n", rxlos, status);
}
}
data->rxlos = rxlos;
return 0;
}
int sonic_i2c_get_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t txdis = 0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
txdis = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nModule TxDisable :0x%x, reg_value = 0x%x\n", txdis, status);
}
}
data->txdisable = txdis;
return 0;
}
int sonic_i2c_get_mod_txfault(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
uint32_t txflt = 0;
if (strcmp(info->devtype, "cpld") == 0)
{
status = xcvr_i2c_cpld_read(info);
if (status < 0)
return status;
else
{
txflt = ((status & BIT_INDEX(info->mask)) == info->cmpval) ? 1 : 0;
sfp_dbg(KERN_INFO "\nModule TxFault :0x%x, reg_value = 0x%x\n", txflt, status);
}
}
data->txfault = txflt;
return 0;
}
int sonic_i2c_set_mod_reset(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
unsigned int val_mask = 0, dnd_value = 0;
uint32_t reg;
struct i2c_client *client_ptr=NULL;
if (strcmp(info->devtype, "cpld") == 0)
{
val_mask = BIT_INDEX(info->mask);
/* Get the I2C client for the CPLD */
client_ptr = (struct i2c_client *)get_device_table(info->devname);
if (client_ptr)
{
if (info->len == 1)
status = board_i2c_cpld_read(info->devaddr , info->offset);
else if (info->len == 2)
status = i2c_smbus_read_word_data(client_ptr, info->offset);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet");
status = -1;
}
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname);
status = -1;
}
/*printk(KERN_ERR "sonic_i2c_set_mod_reset:client_ptr=0x%x, status=0x%x, offset=0x%x, len=%d\n", client_ptr, status, info->offset, info->len);*/
if (status < 0)
return status;
else
{
dnd_value = status & ~val_mask;
if (((data->reset == 1) && (info->cmpval != 0)) || ((data->reset == 0) && (info->cmpval == 0)))
reg = dnd_value | val_mask;
else
reg = dnd_value;
if (info->len == 1)
status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg);
else if (info->len == 2)
status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet");
status = -1;
}
}
}
return status;
}
int sonic_i2c_set_mod_lpmode(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
unsigned int val_mask = 0, dnd_value = 0;
uint32_t reg;
struct i2c_client *client_ptr=NULL;
if (strcmp(info->devtype, "cpld") == 0)
{
val_mask = BIT_INDEX(info->mask);
/* Get the I2C client for the CPLD */
client_ptr = (struct i2c_client *)get_device_table(info->devname);
if (client_ptr)
{
if (info->len == 1)
status = board_i2c_cpld_read(info->devaddr , info->offset);
else if (info->len == 2)
status = i2c_smbus_read_word_data(client_ptr, info->offset);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet");
status = -1;
}
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname);
status = -1;
}
if (status < 0)
return status;
else
{
dnd_value = status & ~val_mask;
if (((data->lpmode == 1) && (info->cmpval != 0)) || ((data->lpmode == 0) && (info->cmpval == 0)))
reg = dnd_value | val_mask;
else
reg = dnd_value;
if (info->len == 1)
status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg);
else if (info->len == 2)
status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet");
status = -1;
}
}
}
return status;
}
int sonic_i2c_set_mod_txdisable(struct i2c_client *client, XCVR_ATTR *info, struct xcvr_data *data)
{
int status = 0;
unsigned int val_mask = 0, dnd_value = 0;
uint32_t reg;
struct i2c_client *client_ptr=NULL;
if (strcmp(info->devtype, "cpld") == 0)
{
val_mask = BIT_INDEX(info->mask);
/* Get the I2C client for the CPLD */
client_ptr = (struct i2c_client *)get_device_table(info->devname);
if (client_ptr)
{
if (info->len == 1)
status = board_i2c_cpld_read(info->devaddr , info->offset);
else if (info->len == 2)
status = i2c_smbus_read_word_data(client_ptr, info->offset);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD read yet");
status = -1;
}
}
else
{
printk(KERN_ERR "Unable to get the client handle for %s\n", info->devname);
status = -1;
}
if (status < 0)
return status;
else
{
dnd_value = status & ~val_mask;
if (((data->txdisable == 1) && (info->cmpval != 0)) || ((data->txdisable == 0) && (info->cmpval == 0)))
reg = dnd_value | val_mask;
else
reg = dnd_value;
if (info->len == 1)
status = board_i2c_cpld_write(info->devaddr, info->offset, (uint8_t)reg);
else if (info->len == 2)
status = i2c_smbus_write_word_swapped(client_ptr, info->offset, (uint16_t)reg);
else
{
printk(KERN_ERR "PDDF_XCVR: Doesn't support block CPLD write yet");
status = -1;
}
}
}
return status;
}
ssize_t get_module_presence(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
int status = 0, i;
for (i=0; i<pdata->len; i++)
{
attr_data = &pdata->xcvr_attrs[i];
if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute. ret %d\n", __FUNCTION__, attr_data->aname, status);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->modpres);
}
}
return sprintf(buf, "%s","");
}
ssize_t get_module_reset(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
int status = 0, i;
for (i=0; i<pdata->len; i++)
{
attr_data = &pdata->xcvr_attrs[i];
if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->reset);
}
}
return sprintf(buf, "%s","");
}
ssize_t set_module_reset(struct device *dev, struct device_attribute *da, const char *buf,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
int status = 0, i;
unsigned int set_value;
for (i=0; i<pdata->len; i++)
{
attr_data = &pdata->xcvr_attrs[i];
if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0)
{
attr_ops = &xcvr_ops[attr->index];
if(kstrtoint(buf, 10, &set_value))
return -EINVAL;
if ((set_value != 1) && (set_value != 0))
return -EINVAL;
data->reset = set_value;
mutex_lock(&data->update_lock);
if (attr_ops->pre_set != NULL)
{
status = (attr_ops->pre_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_set != NULL)
{
status = (attr_ops->do_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_set != NULL)
{
status = (attr_ops->post_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return count;
}
}
return -EINVAL;
}
ssize_t get_module_intr_status(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
int status = 0, i;
for (i=0; i<pdata->len; i++)
{
attr_data = &pdata->xcvr_attrs[i];
if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->intr_status);
}
}
return sprintf(buf, "%s","");
}
int get_xcvr_module_attr_data(struct i2c_client *client, struct device *dev,
struct device_attribute *da)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
XCVR_ATTR *attr_data = NULL;
int i;
for (i=0; i < pdata->len; i++)
{
attr_data = &pdata->xcvr_attrs[i];
if (strcmp(attr_data->aname, attr->dev_attr.attr.name) == 0)
{
return i;
}
}
return -1;
}
ssize_t get_module_lpmode(struct device *dev, struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
int idx, status = 0;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->lpmode);
}
else
return sprintf(buf,"%s","");
}
ssize_t set_module_lpmode(struct device *dev, struct device_attribute *da, const char *buf,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
int idx, status = 0;
uint32_t set_value;
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
if(kstrtoint(buf, 10, &set_value))
return -EINVAL;
if ((set_value != 1) && (set_value != 0))
return -EINVAL;
data->lpmode = set_value;
mutex_lock(&data->update_lock);
if (attr_ops->pre_set != NULL)
{
status = (attr_ops->pre_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_set != NULL)
{
status = (attr_ops->do_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_set != NULL)
{
status = (attr_ops->post_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
}
return count;
}
ssize_t get_module_rxlos(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
int idx, status = 0;
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->rxlos);
}
else
return sprintf(buf,"%s","");
}
ssize_t get_module_txdisable(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
int idx, status = 0;
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->txdisable);
}
else
return sprintf(buf,"%s","");
}
ssize_t set_module_txdisable(struct device *dev, struct device_attribute *da, const char *buf,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
int idx, status = 0;
uint32_t set_value;
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
if(kstrtoint(buf, 10, &set_value))
return -EINVAL;
if ((set_value != 1) && (set_value != 0))
return -EINVAL;
data->txdisable = set_value;
mutex_lock(&data->update_lock);
if (attr_ops->pre_set != NULL)
{
status = (attr_ops->pre_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_set != NULL)
{
status = (attr_ops->do_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_set != NULL)
{
status = (attr_ops->post_set)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_set function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
}
return count;
}
ssize_t get_module_txfault(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
XCVR_PDATA *pdata = (XCVR_PDATA *)(client->dev.platform_data);
struct xcvr_data *data = i2c_get_clientdata(client);
int idx, status = 0;
XCVR_ATTR *attr_data = NULL;
XCVR_SYSFS_ATTR_OPS *attr_ops = NULL;
idx = get_xcvr_module_attr_data(client, dev, da);
if (idx>=0) attr_data = &pdata->xcvr_attrs[idx];
if (attr_data!=NULL)
{
attr_ops = &xcvr_ops[attr->index];
mutex_lock(&data->update_lock);
if (attr_ops->pre_get != NULL)
{
status = (attr_ops->pre_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: pre_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->do_get != NULL)
{
status = (attr_ops->do_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: do_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
if (attr_ops->post_get != NULL)
{
status = (attr_ops->post_get)(client, attr_data, data);
if (status!=0)
printk(KERN_ERR "%s: post_get function fails for %s attribute\n", __FUNCTION__, attr_data->aname);
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", data->txfault);
}
return sprintf(buf,"%s","");
}

View File

@ -0,0 +1,296 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel driver module for Optic component
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_xcvr_defs.h"
#include "pddf_xcvr_api.h"
struct pddf_ops_t pddf_xcvr_ops = {
.pre_init = NULL,
.post_init = NULL,
.pre_probe = NULL,
.post_probe = NULL,
.pre_remove = NULL,
.post_remove = NULL,
.pre_exit = NULL,
.post_exit = NULL,
};
EXPORT_SYMBOL(pddf_xcvr_ops);
XCVR_SYSFS_ATTR_OPS xcvr_ops[XCVR_ATTR_MAX] = {
{XCVR_PRESENT, get_module_presence, NULL, sonic_i2c_get_mod_pres, NULL, NULL, NULL, NULL, NULL},
{XCVR_RESET, get_module_reset, NULL, sonic_i2c_get_mod_reset, NULL, set_module_reset, NULL, sonic_i2c_set_mod_reset, NULL},
{XCVR_INTR_STATUS, get_module_intr_status, NULL, sonic_i2c_get_mod_intr_status, NULL, NULL, NULL, NULL, NULL},
{XCVR_LPMODE, get_module_lpmode, NULL, sonic_i2c_get_mod_lpmode, NULL, set_module_lpmode, NULL, sonic_i2c_set_mod_lpmode, NULL},
{XCVR_RXLOS, get_module_rxlos, NULL, sonic_i2c_get_mod_rxlos, NULL, NULL, NULL, NULL, NULL},
{XCVR_TXDISABLE, get_module_txdisable, NULL, sonic_i2c_get_mod_txdisable, NULL, set_module_txdisable, NULL, sonic_i2c_set_mod_txdisable, NULL},
{XCVR_TXFAULT, get_module_txfault, NULL, sonic_i2c_get_mod_txfault, NULL, NULL, NULL, NULL, NULL},
};
EXPORT_SYMBOL(xcvr_ops);
/* sysfs attributes
*/
static SENSOR_DEVICE_ATTR(xcvr_present, S_IWUSR|S_IRUGO, get_module_presence, NULL, XCVR_PRESENT);
static SENSOR_DEVICE_ATTR(xcvr_reset, S_IWUSR|S_IRUGO, get_module_reset, set_module_reset, XCVR_RESET);
static SENSOR_DEVICE_ATTR(xcvr_intr_status, S_IWUSR|S_IRUGO, get_module_intr_status, NULL, XCVR_INTR_STATUS);
static SENSOR_DEVICE_ATTR(xcvr_lpmode, S_IWUSR|S_IRUGO, get_module_lpmode, set_module_lpmode, XCVR_LPMODE);
static SENSOR_DEVICE_ATTR(xcvr_rxlos, S_IWUSR|S_IRUGO, get_module_rxlos, NULL, XCVR_RXLOS);
static SENSOR_DEVICE_ATTR(xcvr_txdisable, S_IWUSR|S_IRUGO, get_module_txdisable, set_module_txdisable, XCVR_TXDISABLE);
static SENSOR_DEVICE_ATTR(xcvr_txfault, S_IWUSR|S_IRUGO, get_module_txfault, NULL, XCVR_TXFAULT);
/* List of all the xcvr attribute structures
* to get name, use sensor_dev_attr_<>.dev_attr.attr.name
* to get the id, use sensor_dev_attr_<>.dev_attr.index
*/
static struct sensor_device_attribute *xcvr_attr_list[MAX_XCVR_ATTRS] = {
&sensor_dev_attr_xcvr_present,
&sensor_dev_attr_xcvr_reset,
&sensor_dev_attr_xcvr_intr_status,
&sensor_dev_attr_xcvr_lpmode,
&sensor_dev_attr_xcvr_rxlos,
&sensor_dev_attr_xcvr_txdisable,
&sensor_dev_attr_xcvr_txfault,
};
static struct attribute *xcvr_attributes[MAX_XCVR_ATTRS] = {NULL};
static const struct attribute_group xcvr_group = {
.attrs = xcvr_attributes,
};
static int xcvr_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct xcvr_data *data;
int status =0;
int i,j,num;
XCVR_PDATA *xcvr_platform_data;
XCVR_ATTR *attr_data;
if (client == NULL) {
pddf_dbg(XCVR, "NULL Client.. \n");
goto exit;
}
if (pddf_xcvr_ops.pre_probe)
{
status = (pddf_xcvr_ops.pre_probe)(client, dev_id);
if (status != 0)
goto exit;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
status = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct xcvr_data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->valid = 0;
dev_info(&client->dev, "chip found\n");
/* Take control of the platform data */
xcvr_platform_data = (XCVR_PDATA *)(client->dev.platform_data);
num = xcvr_platform_data->len;
data->index = xcvr_platform_data->idx - 1;
mutex_init(&data->update_lock);
/* Add supported attr in the 'attributes' list */
for (i=0; i<num; i++)
{
struct attribute *aptr = NULL;
attr_data = xcvr_platform_data->xcvr_attrs + i;
for(j=0;j<XCVR_ATTR_MAX;j++)
{
aptr = &xcvr_attr_list[j]->dev_attr.attr;
if (strncmp(aptr->name, attr_data->aname, strlen(attr_data->aname))==0)
break;
}
if (j<XCVR_ATTR_MAX)
xcvr_attributes[i] = &xcvr_attr_list[j]->dev_attr.attr;
}
xcvr_attributes[i] = NULL;
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &xcvr_group);
if (status) {
goto exit_free;
}
data->xdev = hwmon_device_register(&client->dev);
if (IS_ERR(data->xdev)) {
status = PTR_ERR(data->xdev);
goto exit_remove;
}
dev_info(&client->dev, "%s: xcvr '%s'\n",
dev_name(data->xdev), client->name);
/* Add a support for post probe function */
if (pddf_xcvr_ops.post_probe)
{
status = (pddf_xcvr_ops.post_probe)(client, dev_id);
if (status != 0)
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &xcvr_group);
exit_free:
kfree(data);
exit:
return status;
}
static int xcvr_remove(struct i2c_client *client)
{
int ret = 0;
struct xcvr_data *data = i2c_get_clientdata(client);
XCVR_PDATA *platdata = (XCVR_PDATA *)client->dev.platform_data;
XCVR_ATTR *platdata_sub = platdata->xcvr_attrs;
if (pddf_xcvr_ops.pre_remove)
{
ret = (pddf_xcvr_ops.pre_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN pre_remove function failed\n");
}
hwmon_device_unregister(data->xdev);
sysfs_remove_group(&client->dev.kobj, &xcvr_group);
kfree(data);
if (platdata_sub) {
pddf_dbg(XCVR, KERN_DEBUG "%s: Freeing platform subdata\n", __FUNCTION__);
kfree(platdata_sub);
}
if (platdata) {
pddf_dbg(XCVR, KERN_DEBUG "%s: Freeing platform data\n", __FUNCTION__);
kfree(platdata);
}
if (pddf_xcvr_ops.post_remove)
{
ret = (pddf_xcvr_ops.post_remove)(client);
if (ret!=0)
printk(KERN_ERR "FAN post_remove function failed\n");
}
return 0;
}
enum xcvr_intf
{
XCVR_CTRL_INTF,
};
static const struct i2c_device_id xcvr_ids[] = {
{ "pddf_xcvr", XCVR_CTRL_INTF },
{}
};
MODULE_DEVICE_TABLE(i2c, xcvr_ids);
static struct i2c_driver xcvr_driver = {
/*.class = I2C_CLASS_HWMON,*/
.driver = {
.name = "xcvr",
.owner = THIS_MODULE,
},
.probe = xcvr_probe,
.remove = xcvr_remove,
.id_table = xcvr_ids,
};
/*int __init xcvr_init(void)*/
int xcvr_init(void)
{
int ret = 0;
if (pddf_xcvr_ops.pre_init)
{
ret = (pddf_xcvr_ops.pre_init)();
if (ret!=0)
return ret;
}
pddf_dbg(XCVR, KERN_ERR "PDDF XCVR DRIVER.. init Invoked..\n");
ret = i2c_add_driver(&xcvr_driver);
if (ret!=0)
return ret;
if (pddf_xcvr_ops.post_init)
{
ret = (pddf_xcvr_ops.post_init)();
if (ret!=0)
return ret;
}
return ret;
}
EXPORT_SYMBOL(xcvr_init);
void __exit xcvr_exit(void)
{
pddf_dbg(XCVR, "PDDF XCVR DRIVER.. exit\n");
if (pddf_xcvr_ops.pre_exit) (pddf_xcvr_ops.pre_exit)();
i2c_del_driver(&xcvr_driver);
if (pddf_xcvr_ops.post_exit) (pddf_xcvr_ops.post_exit)();
}
EXPORT_SYMBOL(xcvr_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("Driver for transceiver operations");
MODULE_LICENSE("GPL");
module_init(xcvr_init);
module_exit(xcvr_exit);

View File

@ -0,0 +1,275 @@
/*
* Copyright 2019 Broadcom.
* The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* 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.
*
*
* A pddf kernel module to create i2C client for optics
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
#include "pddf_xcvr_defs.h"
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count);
extern void* get_device_table(char *name);
extern void delete_device_table(char *name);
XCVR_DATA xcvr_data = {0};
/* XCVR CLIENT DATA */
PDDF_DATA_ATTR(dev_idx, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&xcvr_data.idx, NULL);
PDDF_DATA_ATTR(attr_name, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 32, (void*)&xcvr_data.xcvr_attr.aname, NULL);
PDDF_DATA_ATTR(attr_devtype, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&xcvr_data.xcvr_attr.devtype, NULL);
PDDF_DATA_ATTR(attr_devname, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_CHAR, 8, (void*)&xcvr_data.xcvr_attr.devname, NULL);
PDDF_DATA_ATTR(attr_devaddr, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.devaddr, NULL);
PDDF_DATA_ATTR(attr_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.offset, NULL);
PDDF_DATA_ATTR(attr_mask, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.mask, NULL);
PDDF_DATA_ATTR(attr_cmpval, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_UINT32, sizeof(uint32_t), (void*)&xcvr_data.xcvr_attr.cmpval, NULL);
PDDF_DATA_ATTR(attr_len, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_DEC, sizeof(int), (void*)&xcvr_data.xcvr_attr.len, NULL);
PDDF_DATA_ATTR(attr_ops, S_IWUSR, NULL, do_attr_operation, PDDF_CHAR, 8, (void*)&xcvr_data, NULL);
PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&xcvr_data, (void*)&pddf_data);
static struct attribute *xcvr_attributes[] = {
&attr_dev_idx.dev_attr.attr,
&attr_attr_name.dev_attr.attr,
&attr_attr_devtype.dev_attr.attr,
&attr_attr_devname.dev_attr.attr,
&attr_attr_devaddr.dev_attr.attr,
&attr_attr_offset.dev_attr.attr,
&attr_attr_mask.dev_attr.attr,
&attr_attr_cmpval.dev_attr.attr,
&attr_attr_len.dev_attr.attr,
&attr_attr_ops.dev_attr.attr,
&attr_dev_ops.dev_attr.attr,
NULL
};
static const struct attribute_group pddf_xcvr_client_data_group = {
.attrs = xcvr_attributes,
};
static ssize_t do_attr_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
XCVR_DATA *pdata = (XCVR_DATA *)(ptr->addr);
pdata->xcvr_attrs[pdata->len] = pdata->xcvr_attr;
pdata->len++;
memset(&pdata->xcvr_attr, 0, sizeof(pdata->xcvr_attr));
return count;
}
/*PDDF_DATA_ATTR(dev_ops, S_IWUSR, NULL, do_device_operation, PDDF_CHAR, 8, (void*)&pddf_attr, (void*)NULL);*/
static ssize_t do_device_operation(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
{
int i = 0;
PDDF_ATTR *ptr = (PDDF_ATTR *)da;
XCVR_DATA *pdata = (XCVR_DATA *)(ptr->addr);
NEW_DEV_ATTR *cdata = (NEW_DEV_ATTR *)(ptr->data);
struct i2c_adapter *adapter;
struct i2c_board_info board_info;
struct i2c_client *client_ptr;
/* Populate the platform data for xcvr */
if (strncmp(buf, "add", strlen(buf)-1)==0)
{
if (strcmp(cdata->dev_type, "pddf_xcvr")==0)
{
int num = pdata->len;
XCVR_PDATA *xcvr_platform_data;
adapter = i2c_get_adapter(cdata->parent_bus);
/* Allocate the xcvr_platform_data */
xcvr_platform_data = (XCVR_PDATA *)kzalloc(sizeof(XCVR_PDATA), GFP_KERNEL);
xcvr_platform_data->xcvr_attrs = (XCVR_ATTR *)kzalloc(num*sizeof(XCVR_ATTR), GFP_KERNEL);
xcvr_platform_data->idx = pdata->idx;
xcvr_platform_data->len = pdata->len;
for (i=0;i<num;i++)
{
xcvr_platform_data->xcvr_attrs[i] = pdata->xcvr_attrs[i];
}
board_info = (struct i2c_board_info) {
.platform_data = xcvr_platform_data,
};
board_info.addr = cdata->dev_addr;
strcpy(board_info.type, cdata->dev_type);
client_ptr = i2c_new_device(adapter, &board_info);
if (client_ptr != NULL) {
i2c_put_adapter(adapter);
pddf_dbg(XCVR, KERN_ERR "Created a %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr);
add_device_table(cdata->i2c_name, (void*)client_ptr);
}
else
{
i2c_put_adapter(adapter);
goto free_data;
}
}
else if((strcmp(cdata->dev_type, "optoe1")==0) || (strcmp(cdata->dev_type, "optoe2")==0))
{
adapter = i2c_get_adapter(cdata->parent_bus);
board_info = (struct i2c_board_info) {
.platform_data = (void *)NULL,
};
board_info.addr = cdata->dev_addr;
strcpy(board_info.type, cdata->dev_type);
client_ptr = i2c_new_device(adapter, &board_info);
if(client_ptr != NULL) {
i2c_put_adapter(adapter);
pddf_dbg(XCVR, KERN_ERR "Created %s, type:%s client: 0x%p\n", cdata->i2c_name, cdata->dev_type, (void *)client_ptr);
add_device_table(cdata->i2c_name, (void*)client_ptr);
}
else
{
i2c_put_adapter(adapter);
printk(KERN_ERR "Error creating a client %s on 0x%x, client_ptr:0x%p\n", board_info.type, board_info.addr, (void *)client_ptr);
goto free_data;
}
}
else
{
printk(KERN_ERR "%s:Unknown type of device %s. Unable to create I2C client for it\n",__FUNCTION__, cdata->dev_type);
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
{
/*Get the i2c_client handle for the created client*/
client_ptr = (struct i2c_client *)get_device_table(cdata->i2c_name);
if (client_ptr)
{
pddf_dbg(XCVR, KERN_ERR "Removing %s client: 0x%p\n", cdata->i2c_name, (void *)client_ptr);
i2c_unregister_device(client_ptr);
delete_device_table(cdata->i2c_name);
}
else
{
pddf_dbg(XCVR, KERN_ERR "Unable to get the client handle for %s\n", cdata->i2c_name);
}
}
else
{
printk(KERN_ERR "PDDF_ERROR: %s: Invalid value for dev_ops %s", __FUNCTION__, buf);
}
goto clear_data;
free_data:
if (board_info.platform_data)
{
XCVR_PDATA *xcvr_platform_data = board_info.platform_data;
if (xcvr_platform_data->xcvr_attrs)
{
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform subdata\n", __FUNCTION__);
kfree(xcvr_platform_data->xcvr_attrs);
}
printk(KERN_ERR "%s: Unable to create i2c client. Freeing the platform data\n", __FUNCTION__);
kfree(xcvr_platform_data);
}
clear_data:
memset(pdata, 0, sizeof(XCVR_DATA));
/*TODO: free the data cdata->data if data is dynal=mically allocated*/
memset(cdata, 0, sizeof(NEW_DEV_ATTR));
return count;
}
struct kobject *xcvr_kobj;
struct kobject *i2c_kobj;
int __init pddf_data_init(void)
{
struct kobject *device_kobj;
int ret = 0;
pddf_dbg(XCVR, KERN_ERR "XCVR PDDF MODULE.. init\n");
device_kobj = get_device_i2c_kobj();
if(!device_kobj)
return -ENOMEM;
xcvr_kobj = kobject_create_and_add("xcvr", device_kobj);
if(!xcvr_kobj)
return -ENOMEM;
i2c_kobj = kobject_create_and_add("i2c", xcvr_kobj);
if(!i2c_kobj)
return -ENOMEM;
ret = sysfs_create_group(i2c_kobj, &pddf_clients_data_group);
if (ret)
{
kobject_put(i2c_kobj);
kobject_put(xcvr_kobj);
return ret;
}
pddf_dbg(XCVR, "CREATED SFP I2C CLIENTS CREATION SYSFS GROUP\n");
ret = sysfs_create_group(i2c_kobj, &pddf_xcvr_client_data_group);
if (ret)
{
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(xcvr_kobj);
return ret;
}
pddf_dbg(XCVR, "CREATED PDDF SFP DATA SYSFS GROUP\n");
return ret;
}
void __exit pddf_data_exit(void)
{
pddf_dbg(XCVR, "XCVR PDDF MODULE.. exit\n");
sysfs_remove_group(i2c_kobj, &pddf_xcvr_client_data_group);
sysfs_remove_group(i2c_kobj, &pddf_clients_data_group);
kobject_put(i2c_kobj);
kobject_put(xcvr_kobj);
pddf_dbg(XCVR, KERN_ERR "%s: Removed the kobjects for 'i2c' and 'xcvr'\n",__FUNCTION__);
return;
}
module_init(pddf_data_init);
module_exit(pddf_data_exit);
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("sfp platform data");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,13 @@
[Unit]
Description=PDDF module and device initialization service
Before=pmon.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/pddf_util.py install
ExecStop=/usr/local/bin/pddf_util.py clean
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

14
platform/pddf/i2c/setup.py Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env python
from setuptools import setup
import os
setup(
name='pddf-platform',
version='%s' % os.environ.get('PLATFORM_MODULE_VERSION', '1.0'),
description='Module to initialize Platform',
packages=[
'modules',
],
)

View File

@ -0,0 +1,605 @@
#!/usr/bin/env python
"""
Usage: %(scriptName)s [options] command object
options:
-h | --help : this help message
-d | --debug : run with debug mode
-f | --force : ignore error during installation or clean
command:
install : install drivers and generate related sysfs nodes
clean : uninstall drivers and remove related sysfs nodes
switch-pddf : switch to pddf mode, installing pddf drivers and generating sysfs nodes
switch-nonpddf : switch to per platform, non-pddf mode
"""
import commands
import logging
import getopt
import os
import shutil
import subprocess
import sys
import pddfparse
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'
PROJECT_NAME = 'PDDF'
version = '1.1'
verbose = False
DEBUG = False
args = []
ALL_DEVICE = {}
FORCE = 0
kos = []
perm_kos = []
devs = []
# Instantiate the class pddf_obj
try:
pddf_obj = pddfparse.PddfParse()
except Exception as e:
print "%s" % str(e)
sys.exit()
if DEBUG == True:
print sys.argv[0]
print 'ARGV :', sys.argv[1:]
def main():
global DEBUG
global args
global FORCE
global kos
if len(sys.argv)<2:
show_help()
options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help',
'debug',
'force',
])
if DEBUG == True:
print options
print args
print len(sys.argv)
# generate the KOS list from pddf device JSON file
if 'std_perm_kos' in pddf_obj.data['PLATFORM'].keys():
kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos'])
perm_kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos'])
kos.extend(pddf_obj.data['PLATFORM']['std_kos'])
kos.extend(pddf_obj.data['PLATFORM']['pddf_kos'])
kos = ['modprobe '+i for i in kos]
if 'custom_kos' in pddf_obj.data['PLATFORM']:
custom_kos = pddf_obj.data['PLATFORM']['custom_kos']
kos.extend(['modprobe -f '+i for i in custom_kos])
for opt, arg in options:
if opt in ('-h', '--help'):
show_help()
elif opt in ('-d', '--debug'):
DEBUG = True
logging.basicConfig(level=logging.INFO)
elif opt in ('-f', '--force'):
FORCE = 1
else:
logging.info('no option')
for arg in args:
if arg == 'install':
do_install()
elif arg == 'clean':
do_uninstall()
elif arg == 'switch-pddf':
do_switch_pddf()
elif arg == 'switch-nonpddf':
do_switch_nonpddf()
else:
show_help()
return 0
def show_help():
print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print "[PDDF]"+txt
return
def log_os_system(cmd, show):
logging.info('Run :'+cmd)
status, output = commands.getstatusoutput(cmd)
my_log (cmd +"with result:" + str(status))
my_log (" output:"+output)
if status:
logging.info('Failed :'+cmd)
if show:
print('Failed :'+cmd)
return status, output
def driver_check():
ret, lsmod = log_os_system("lsmod| grep pddf", 0)
if ret:
return False
logging.info('mods:'+lsmod)
if len(lsmod) ==0:
return False
return True
# Returns platform and HW SKU
def get_platform_and_hwsku():
try:
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
platform = stdout.rstrip('\n')
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
hwsku = stdout.rstrip('\n')
except OSError, e:
raise OSError("Cannot detect platform")
return (platform, hwsku)
def get_path_to_device():
# Get platform and hwsku
(platform, hwsku) = get_platform_and_hwsku()
# Load platform module from source
platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
return platform_path
def get_path_to_pddf_plugin():
pddf_path = "/".join([PLATFORM_ROOT_PATH, "pddf/plugins"])
return pddf_path
def config_pddf_utils():
device_path = get_path_to_device()
pddf_path = get_path_to_pddf_plugin()
# ##########################################################################
SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl'])
SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py2-none-any.whl'])
SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl.orig'])
status, output = log_os_system("pip show sonic-platform > /dev/null 2>&1", 1)
if status:
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
# Platform API 2.0 is supported
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG):
# bsp whl pkg is present but not installed on host <special case>
if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1)
# PDDF whl package exist ... this must be the whl package created from
# PDDF 2.0 ref API classes and some changes on top of it ... install it
shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG)
print "Attemting to install the PDDF sonic_platform wheel package ..."
status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)
return status
else:
print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)
else:
# PDDF with platform APIs 1.5 must be supported
device_plugin_path = "/".join([device_path, "plugins"])
backup_path = "/".join([device_plugin_path, "orig"])
print "Loading PDDF generic plugins (1.0)"
if os.path.exists(backup_path) is False:
os.mkdir(backup_path)
log_os_system("mv "+device_plugin_path+"/*.*"+" "+backup_path, 0)
for item in os.listdir(pddf_path):
shutil.copy(pddf_path+"/"+item, device_plugin_path+"/"+item)
shutil.copy('/usr/local/bin/pddfparse.py', device_plugin_path+"/pddfparse.py")
else:
# sonic_platform whl pkg is installed 2 possibilities, 1) bsp 2.0 classes
# are installed, 2) system rebooted and either pddf/bsp 2.0 classes are already installed
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
# bsp 2.0 classes are installed. Take a backup and copy pddf 2.0 whl pkg
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1)
shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG)
# uninstall the existing bsp whl pkg
status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1)
if status:
print "Error: Unable to uninstall BSP sonic-platform whl package"
return status
print "Attemting to install the PDDF sonic_platform wheel package ..."
status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)
return status
else:
print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)
else:
# system rebooted in pddf mode
print "System rebooted in PDDF mode, hence keeping the PDDF 2.0 classes"
else:
# pddf whl package doesnt exist
print "Error: PDDF 2.0 classes doesnt exist. PDDF mode can not be enabled"
sys.exit(1)
# ##########################################################################
# Take a backup of orig fancontrol
if os.path.exists(device_path+"/fancontrol"):
log_os_system("mv "+device_path+"/fancontrol"+" "+device_path+"/fancontrol.bak", 0)
# Create a link to fancontrol of PDDF
if os.path.exists(device_path+"/pddf/fancontrol") and not os.path.exists(device_path+"/fancontrol"):
shutil.copy(device_path+"/pddf/fancontrol",device_path+"/fancontrol")
# BMC support
f_sensors="/usr/bin/sensors"
f_sensors_org="/usr/bin/sensors.org"
f_pddf_sensors="/usr/local/bin/pddf_sensors"
if os.path.exists(f_pddf_sensors) is True:
if os.path.exists(f_sensors_org) is False:
shutil.copy(f_sensors, f_sensors_org)
shutil.copy(f_pddf_sensors, f_sensors)
return 0
def cleanup_pddf_utils():
device_path = get_path_to_device()
SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl'])
SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py2-none-any.whl'])
SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py2-none-any.whl.orig'])
# ##########################################################################
status, output = log_os_system("pip show sonic-platform > /dev/null 2>&1", 1)
if status:
# PDDF Platform API 2.0 is not supported but system is in PDDF mode, hence PDDF 1.0 plugins are present
device_plugin_path = "/".join([device_path, "plugins"])
backup_path = "/".join([device_plugin_path, "orig"])
if os.path.exists(backup_path) is True:
for item in os.listdir(device_plugin_path):
if os.path.isdir(device_plugin_path+"/"+item) is False:
os.remove(device_plugin_path+"/"+item)
log_os_system("mv "+backup_path+"/*"+" "+device_plugin_path, 1)
os.rmdir(backup_path)
else:
print "\nERR: Unable to locate original device files...\n"
else:
# PDDF 2.0 apis are supported and PDDF whl package is installed
if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG):
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK):
# platform is 2.0 compliant and original bsp 2.0 whl package exist
log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG_BK+' '+SONIC_PLATFORM_BSP_WHL_PKG, 1)
status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1)
if status:
print "Error: Unable to uninstall PDDF sonic-platform whl package"
return status
print "Attemting to install the BSP sonic_platform wheel package ..."
status, output = log_os_system("pip install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1)
if status:
print "Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)
return status
else:
print "Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)
else:
# platform doesnt support 2.0 APIs but PDDF is 2.0 based
# remove and uninstall the PDDF whl package
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG):
os.remove(SONIC_PLATFORM_BSP_WHL_PKG)
status, output = log_os_system("pip uninstall sonic-platform -y &> /dev/null", 1)
if status:
print "Error: Unable to uninstall PDDF sonic-platform whl package"
return status
else:
# something seriously wrong. System is in PDDF mode but pddf whl pkg is not present
print "Error: Fatal error as the system is in PDDF mode but the pddf .whl original is not present"
# ################################################################################################################
if os.path.exists(device_path+"/fancontrol"):
os.remove(device_path+"/fancontrol")
if os.path.exists(device_path+"/fancontrol.bak"):
log_os_system("mv "+device_path+"/fancontrol.bak"+" "+device_path+"/fancontrol", 0)
# BMC support
f_sensors="/usr/bin/sensors"
f_sensors_org="/usr/bin/sensors.org"
if os.path.exists(f_sensors_org) is True:
shutil.copy(f_sensors_org, f_sensors)
return 0
def create_pddf_log_files():
if not os.path.exists('/var/log/pddf'):
log_os_system("sudo mkdir /var/log/pddf", 1)
log_os_system("sudo touch /var/log/pddf/led.txt", 1)
log_os_system("sudo touch /var/log/pddf/psu.txt", 1)
log_os_system("sudo touch /var/log/pddf/fan.txt", 1)
log_os_system("sudo touch /var/log/pddf/xcvr.txt", 1)
log_os_system("sudo touch /var/log/pddf/sysstatus.txt", 1)
log_os_system("sudo touch /var/log/pddf/cpld.txt", 1)
log_os_system("sudo touch /var/log/pddf/cpldmux.txt", 1)
log_os_system("sudo touch /var/log/pddf/client.txt", 1)
log_os_system("sudo touch /var/log/pddf/mux.txt", 1)
def driver_install():
global FORCE
# check for pre_driver_install script
if os.path.exists('/usr/local/bin/pddf_pre_driver_install.sh'):
status, output = log_os_system('/usr/local/bin/pddf_pre_driver_install.sh', 1)
if status:
print "Error: pddf_pre_driver_install script failed with error %d"%status
return status
log_os_system("depmod", 1)
for i in range(0,len(kos)):
status, output = log_os_system(kos[i], 1)
if status:
print "driver_install() failed with error %d"%status
if FORCE == 0:
return status
output = config_pddf_utils()
if output:
print "config_pddf_utils() failed with error %d"%output
# check for post_driver_install script
if os.path.exists('/usr/local/bin/pddf_post_driver_install.sh'):
status, output = log_os_system('/usr/local/bin/pddf_post_driver_install.sh', 1)
if status:
print "Error: pddf_post_driver_install script failed with error %d"%status
return status
return 0
def driver_uninstall():
global FORCE
status = cleanup_pddf_utils()
if status:
print "cleanup_pddf_utils() failed with error %d"%status
for i in range(0,len(kos)):
# if it is in perm_kos, do not remove
if (kos[-(i+1)].split())[-1] in perm_kos or 'i2c-i801' in kos[-(i+1)]:
continue
rm = kos[-(i+1)].replace("modprobe", "modprobe -rq")
rm = rm.replace("insmod", "rmmod")
status, output = log_os_system(rm, 1)
if status:
print "driver_uninstall() failed with error %d"%status
if FORCE == 0:
return status
return 0
def device_install():
global FORCE
# check for pre_device_creation script
if os.path.exists('/usr/local/bin/pddf_pre_device_create.sh'):
status, output = log_os_system('/usr/local/bin/pddf_pre_device_create.sh', 1)
if status:
print "Error: pddf_pre_device_create script failed with error %d"%status
return status
# trigger the pddf_obj script for FAN, PSU, CPLD, MUX, etc
status = pddf_obj.create_pddf_devices()
if status:
print "Error: create_pddf_devices() failed with error %d"%status
if FORCE == 0:
return status
# check for post_device_create script
if os.path.exists('/usr/local/bin/pddf_post_device_create.sh'):
status, output = log_os_system('/usr/local/bin/pddf_post_device_create.sh', 1)
if status:
print "Error: pddf_post_device_create script failed with error %d"%status
return status
return
def device_uninstall():
global FORCE
# Trigger the paloparse script for deletion of FAN, PSU, OPTICS, CPLD clients
status = pddf_obj.delete_pddf_devices()
if status:
print "Error: delete_pddf_devices() failed with error %d"%status
if FORCE == 0:
return status
return
def do_install():
print "Checking system...."
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print PROJECT_NAME.upper() +" mode is not enabled"
return
if driver_check()== False :
print PROJECT_NAME.upper() +" has no PDDF driver installed...."
create_pddf_log_files()
print "Installing ..."
status = driver_install()
if status:
return status
else:
print PROJECT_NAME.upper() +" drivers detected...."
print "Creating devices ..."
status = device_install()
if status:
return status
return
def do_uninstall():
print "Checking system...."
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print PROJECT_NAME.upper() +" mode is not enabled"
return
if os.path.exists('/var/log/pddf'):
print "Remove pddf log files....."
log_os_system("sudo rm -rf /var/log/pddf", 1)
print "Remove all the devices..."
status = device_uninstall()
if status:
return status
if driver_check()== False :
print PROJECT_NAME.upper() +" has no PDDF driver installed...."
else:
print "Removing installed driver...."
status = driver_uninstall()
if status:
if FORCE == 0:
return status
return
def do_switch_pddf():
try:
import pddf_switch_svc
except ImportError:
print "Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform"
sys.exit()
print "Check the pddf support..."
status = pddf_switch_svc.check_pddf_support()
if not status:
print "PDDF is not supported on this platform"
return status
print "Checking system...."
if os.path.exists('/usr/share/sonic/platform/pddf_support'):
print PROJECT_NAME.upper() +" system is already in pddf mode...."
else:
print "Check if the native sonic-platform whl package is installed in the pmon docker"
status, output = log_os_system("docker exec -it pmon pip show sonic-platform", 1)
if not status:
# Need to remove this whl module
status, output = log_os_system("docker exec -it pmon pip uninstall sonic-platform -y", 1)
if not status:
print "Successfully uninstalled the native sonic-platform whl pkg from pmon container"
else:
print "Error: Unable to uninstall the sonic-platform whl pkg from pmon container.\
Do it manually before moving to nonpddf mode"
return status
print "Stopping the pmon service ..."
status, output = log_os_system("systemctl stop pmon.service", 1)
if status:
print "Pmon stop failed"
if FORCE==0:
return status
print "Stopping the platform services.."
status = pddf_switch_svc.stop_platform_svc()
if not status:
if FORCE==0:
return status
print "Creating the pddf_support file..."
if os.path.exists('/usr/share/sonic/platform'):
log_os_system("touch /usr/share/sonic/platform/pddf_support", 1)
else:
print "/usr/share/sonic/platform path doesn't exist. Unable to set pddf mode"
return -1
print "Starting the PDDF platform service..."
status = pddf_switch_svc.start_platform_pddf()
if not status:
if FORCE==0:
return status
print "Restart the pmon service ..."
status, output = log_os_system("systemctl start pmon.service", 1)
if status:
print "Pmon restart failed"
if FORCE==0:
return status
return
def do_switch_nonpddf():
try:
import pddf_switch_svc
except ImportError:
print "Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform"
sys.exit()
print "Checking system...."
if not os.path.exists('/usr/share/sonic/platform/pddf_support'):
print PROJECT_NAME.upper() +" system is already in non-pddf mode...."
else:
print "Check if the sonic-platform whl package is installed in the pmon docker"
status, output = log_os_system("docker exec -it pmon pip show sonic-platform", 1)
if not status:
# Need to remove this whl module
status, output = log_os_system("docker exec -it pmon pip uninstall sonic-platform -y", 1)
if not status:
print "Successfully uninstalled the sonic-platform whl pkg from pmon container"
else:
print "Error: Unable to uninstall the sonic-platform whl pkg from pmon container.\
Do it manually before moving to nonpddf mode"
return status
print "Stopping the pmon service ..."
status, output = log_os_system("systemctl stop pmon.service", 1)
if status:
print "Stopping pmon service failed"
if FORCE==0:
return status
print "Stopping the PDDF platform service..."
status = pddf_switch_svc.stop_platform_pddf()
if not status:
if FORCE==0:
return status
print "Removing the pddf_support file..."
if os.path.exists('/usr/share/sonic/platform'):
log_os_system("rm -f /usr/share/sonic/platform/pddf_support", 1)
else:
print "/usr/share/sonic/platform path doesnt exist. Unable to set non-pddf mode"
return -1
print "Starting the platform services..."
status = pddf_switch_svc.start_platform_svc()
if not status:
if FORCE==0:
return status
print "Restart the pmon service ..."
status, output = log_os_system("systemctl start pmon.service", 1)
if status:
print "Restarting pmon service failed"
if FORCE==0:
return status
return
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"CPLD": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"dev_attr": {
"type": "object"
}
},
"required": [
"topo_info"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"CPLD"
]
}

View File

@ -0,0 +1,80 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"CPU": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "null"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"CONTROLLERS": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"dev_name": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"dev_name",
"dev"
]
},
{
"type": "object",
"properties": {
"dev_name": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"dev_name",
"dev"
]
}
]
}
},
"required": [
"CONTROLLERS"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"CPU"
]
}

View File

@ -0,0 +1,93 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"EEPROM": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"dev_attr": {
"type": "object",
"properties": {
"access_mode": {
"type": "string"
}
},
"required": [
"access_mode"
]
},
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
}
},
"required": [
"attr_name"
]
}
]
}
},
"required": [
"topo_info",
"dev_attr",
"attr_list"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"EEPROM"
]
}

View File

@ -0,0 +1,113 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"FAN": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"dev_attr": {
"type": "object",
"properties": {
"num_fantrays": {
"type": "string"
}
},
"required": [
"num_fantrays"
]
},
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devtype": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_cmpval": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devtype",
"attr_offset",
"attr_mask",
"attr_cmpval",
"attr_len"
]
}
]
}
},
"required": [
"topo_info",
"dev_attr",
"attr_list"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"FAN"
]
}

View File

@ -0,0 +1,69 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"FAN": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
}
},
"required": [
"device_type"
]
},
"bmc": {
"type": "object",
"properties": {
"ipmitool": {
"type": "object",
"properties": {
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw"
]
}
]
}
},
"required": [
"attr_list"
]
}
},
"required": [
"ipmitool"
]
}
},
"required": [
"dev_info",
"bmc"
]
}
},
"required": [
"FAN"
]
}

View File

@ -0,0 +1,120 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"LED": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
}
},
"required": [
"device_type",
"device_name"
]
},
"dev_attr": {
"type": "object",
"properties": {
"index": {
"type": "string"
}
},
"required": [
"index"
]
},
"i2c": {
"type": "object",
"properties": {
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bits": {
"type": "string"
},
"color": {
"type": "string"
},
"value": {
"type": "string"
},
"swpld_addr": {
"type": "string"
},
"swpld_addr_offset": {
"type": "string"
}
},
"required": [
"attr_name",
"bits",
"color",
"value",
"swpld_addr",
"swpld_addr_offset"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bits": {
"type": "string"
},
"color": {
"type": "string"
},
"value": {
"type": "string"
},
"swpld_addr": {
"type": "string"
},
"swpld_addr_offset": {
"type": "string"
}
},
"required": [
"attr_name",
"bits",
"color",
"value",
"swpld_addr",
"swpld_addr_offset"
]
}
]
}
},
"required": [
"attr_list"
]
}
},
"required": [
"dev_info",
"dev_attr",
"i2c"
]
}
},
"required": [
"LED"
]
}

View File

@ -0,0 +1,97 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"MUX": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"dev_attr": {
"type": "object",
"properties": {
"virt_bus": {
"type": "string"
}
},
"required": [
"virt_bus"
]
},
"channel": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"chn": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"chn",
"dev"
]
}
]
}
},
"required": [
"topo_info",
"dev_attr",
"channel"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"MUX"
]
}

View File

@ -0,0 +1,109 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"PSU-PMBUS": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
},
"virt_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent",
"virt_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_devtype": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_cmpval": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_devtype",
"attr_offset",
"attr_mask",
"attr_cmpval",
"attr_len"
]
}
]
}
},
"required": [
"topo_info",
"attr_list"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"PSU-PMBUS"
]
}

View File

@ -0,0 +1,81 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"PSU": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"dev_attr": {
"type": "object",
"properties": {
"dev_idx": {
"type": "string"
},
"num_psu_fans": {
"type": "string"
}
},
"required": [
"dev_idx",
"num_psu_fans"
]
},
"i2c": {
"type": "object",
"properties": {
"interface": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"itf": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"itf",
"dev"
]
}
]
}
},
"required": [
"interface"
]
}
},
"required": [
"dev_info",
"dev_attr",
"i2c"
]
}
},
"required": [
"PSU"
]
}

View File

@ -0,0 +1,336 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"PSU": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
}
},
"required": [
"device_type"
]
},
"dev_attr": {
"type": "object",
"properties": {
"dev_idx": {
"type": "string"
},
"num_psu_fans": {
"type": "string"
}
},
"required": [
"dev_idx",
"num_psu_fans"
]
},
"bmc": {
"type": "object",
"properties": {
"ipmitool": {
"type": "object",
"properties": {
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"type": {
"type": "string"
},
"mask": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"type",
"mask"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"type"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"type"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"type"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"type"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
},
"mult": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos",
"mult"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
},
"mult": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos",
"mult"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
},
"mult": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos",
"mult"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
},
"mult": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos",
"mult"
]
}
]
}
},
"required": [
"attr_list"
]
}
},
"required": [
"ipmitool"
]
}
},
"required": [
"dev_info",
"dev_attr",
"bmc"
]
}
},
"required": [
"PSU"
]
}

View File

@ -0,0 +1,92 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"QSFP": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"dev_attr": {
"type": "object",
"properties": {
"dev_idx": {
"type": "string"
}
},
"required": [
"dev_idx"
]
},
"i2c": {
"type": "object",
"properties": {
"interface": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"itf": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"itf",
"dev"
]
},
{
"type": "object",
"properties": {
"itf": {
"type": "string"
},
"dev": {
"type": "string"
}
},
"required": [
"itf",
"dev"
]
}
]
}
},
"required": [
"interface"
]
}
},
"required": [
"dev_info",
"dev_attr",
"i2c"
]
}
},
"required": [
"QSFP"
]
}

View File

@ -0,0 +1,128 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"SMBUS": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_name",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"dev_addr": {
"type": "string"
}
},
"required": [
"dev_addr"
]
},
"DEVICES": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
},
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
},
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
},
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
},
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
},
{
"type": "object",
"properties": {
"dev": {
"type": "string"
}
},
"required": [
"dev"
]
}
]
}
},
"required": [
"topo_info",
"DEVICES"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"SMBUS"
]
}

View File

@ -0,0 +1,285 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"SYSSTAT": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
}
},
"required": [
"device_type",
"device_name"
]
},
"dev_attr": {
"type": "object"
},
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"attr_devaddr": {
"type": "string"
},
"attr_offset": {
"type": "string"
},
"attr_mask": {
"type": "string"
},
"attr_len": {
"type": "string"
}
},
"required": [
"attr_name",
"attr_devaddr",
"attr_offset",
"attr_mask",
"attr_len"
]
}
]
}
},
"required": [
"dev_info",
"dev_attr",
"attr_list"
]
}
},
"required": [
"SYSSTAT"
]
}

View File

@ -0,0 +1,102 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"TEMP_SENSOR": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
},
"device_name": {
"type": "string"
},
"device_parent": {
"type": "string"
}
},
"required": [
"device_type",
"device_parent"
]
},
"i2c": {
"type": "object",
"properties": {
"topo_info": {
"type": "object",
"properties": {
"parent_bus": {
"type": "string"
},
"dev_addr": {
"type": "string"
},
"dev_type": {
"type": "string"
}
},
"required": [
"parent_bus",
"dev_addr",
"dev_type"
]
},
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
}
},
"required": [
"attr_name"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
}
},
"required": [
"attr_name"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
}
},
"required": [
"attr_name"
]
}
]
}
},
"required": [
"topo_info",
"attr_list"
]
}
},
"required": [
"dev_info",
"i2c"
]
}
},
"required": [
"TEMP_SENSOR"
]
}

View File

@ -0,0 +1,143 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"TEMP_SENSOR": {
"type": "object",
"properties": {
"dev_info": {
"type": "object",
"properties": {
"device_type": {
"type": "string"
}
},
"required": [
"device_type"
]
},
"dev_attr": {
"type": "object",
"properties": {
"display_name": {
"type": "string"
}
},
"required": [
"display_name"
]
},
"bmc": {
"type": "object",
"properties": {
"ipmitool": {
"type": "object",
"properties": {
"attr_list": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos"
]
},
{
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"bmc_cmd": {
"type": "string"
},
"raw": {
"type": "string"
},
"field_name": {
"type": "string"
},
"field_pos": {
"type": "string"
}
},
"required": [
"attr_name",
"bmc_cmd",
"raw",
"field_name",
"field_pos"
]
}
]
}
},
"required": [
"attr_list"
]
}
},
"required": [
"ipmitool"
]
}
},
"required": [
"dev_info",
"dev_attr",
"bmc"
]
}
},
"required": [
"TEMP_SENSOR"
]
}

View File

@ -0,0 +1,9 @@
MPATH := $($(PDDF_PLATFORM_API_BASE_PY2)_SRC_PATH)
DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/pddf/platform-api-pddf-base.mk platform/pddf/platform-api-pddf-base.dep
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
DEP_FILES += $(shell git ls-files $(MPATH))
$(PDDF_PLATFORM_API_BASE_PY2)_CACHE_MODE := GIT_CONTENT_SHA
$(PDDF_PLATFORM_API_BASE_PY2)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
$(PDDF_PLATFORM_API_BASE_PY2)_DEP_FILES := $(DEP_FILES)

View File

@ -0,0 +1,15 @@
####################################################
# PDDF Generic 2.0 Platform API base classes
####################################################
PDDF_PLATFORM_API_BASE_VERSION = 1.0
export PDDF_PLATFORM_API_BASE_VERSION
PDDF_PLATFORM_API_BASE_PY2 = sonic_platform_pddf_common-$(PDDF_PLATFORM_API_BASE_VERSION)-py2-none-any.whl
$(PDDF_PLATFORM_API_BASE_PY2)_SRC_PATH = $(PLATFORM_PDDF_PATH)/platform-api-pddf-base
$(PDDF_PLATFORM_API_BASE_PY2)_PYTHON_VERSION = 2
$(PDDF_PLATFORM_API_BASE_PY2)_DEPENDS = $(SONIC_CONFIG_ENGINE)
SONIC_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY2)
export pddf_platform_api_base_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(PDDF_PLATFORM_API_BASE_PY2))"
export PDDF_PLATFORM_API_BASE_PY2

View File

@ -0,0 +1,30 @@
from setuptools import setup
setup(
name='sonic-platform-pddf-common',
version='1.0',
description='SONIC platform APIs base (2.0) implementation on PDDF supported platforms',
license='Apache 2.0',
author='SONiC Team',
author_email='linuxnetdev@microsoft.com',
url='https://github.com/Azure/sonic-buildimage',
maintainer='Fuzail Khan',
maintainer_email='fuzail.khan@broadcom.com',
packages=[
'sonic_platform_pddf_base',
],
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Plugins',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: Apache Software License',
'Natural Language :: English',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 2.7',
'Topic :: Utilities',
],
keywords='sonic SONiC platform PLATFORM',
)

View File

@ -0,0 +1,516 @@
#!/usr/bin/env python
#############################################################################
# PDDF
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import sys
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.sfp import Sfp
from sonic_platform.psu import Psu
from sonic_platform.fan import Fan
from sonic_platform.thermal import Thermal
from sonic_platform.eeprom import Eeprom
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PddfChassis(ChassisBase):
"""
PDDF Generic Chassis class
"""
pddf_obj = {}
plugin_data = {}
def __init__(self, pddf_data=None, pddf_plugin_data=None):
ChassisBase.__init__(self)
self.pddf_obj = pddf_data if pddf_data else None
self.plugin_data = pddf_plugin_data if pddf_plugin_data else None
if not self.pddf_obj or not self.plugin_data:
try:
import pddfparse
import json
self.pddf_obj = pddfparse.PddfParse()
with open('/usr/share/sonic/platform/pddf/pd-plugin.json') as pd:
self.plugin_data = json.load(pd)
except Exception as e:
raise Exception("Error: Unable to load PDDF JSON data - %s" % str(e))
self.platform_inventory = self.pddf_obj.get_platform()
# Initialize EEPROM
self.sys_eeprom = Eeprom(self.pddf_obj, self.plugin_data)
# FANs
for i in range(self.platform_inventory['num_fantrays']):
for j in range(self.platform_inventory['num_fans_pertray']):
fan = Fan(i, j, self.pddf_obj, self.plugin_data)
self._fan_list.append(fan)
# PSUs
for i in range(self.platform_inventory['num_psus']):
psu = Psu(i, self.pddf_obj, self.plugin_data)
self._psu_list.append(psu)
# OPTICs
for index in range(self.platform_inventory['num_ports']):
sfp = Sfp(index, self.pddf_obj, self.plugin_data)
self._sfp_list.append(sfp)
# THERMALs
for i in range(self.platform_inventory['num_temps']):
thermal = Thermal(i, self.pddf_obj, self.plugin_data)
self._thermal_list.append(thermal)
# SYSTEM LED Test Cases
"""
#comment out test cases
sys_led_list= { "LOC":0,
"DIAG":0,
"FAN":0,
"SYS":0,
"PSU1":0,
"PSU2":1
}
for led in sys_led_list:
color=self.get_system_led(led, sys_led_list[led])
print color
self.set_system_led("LOC_LED","STATUS_LED_COLOR_GREEN")
color=self.get_system_led("LOC_LED")
print "Set Green: " + color
self.set_system_led("LOC_LED", "STATUS_LED_COLOR_OFF")
color=self.get_system_led("LOC_LED")
print "Set off: " + color
"""
def get_name(self):
"""
Retrieves the name of the chassis
Returns:
string: The name of the chassis
"""
return self.sys_eeprom.modelstr()
def get_presence(self):
"""
Retrieves the presence of the chassis
Returns:
bool: True if chassis is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the chassis
Returns:
string: Model/part number of chassis
"""
return self.sys_eeprom.part_number_str()
def get_serial(self):
"""
Retrieves the serial number of the chassis (Service tag)
Returns:
string: Serial number of chassis
"""
return self.sys_eeprom.serial_str()
def get_status(self):
"""
Retrieves the operational status of the chassis
Returns:
bool: A boolean value, True if chassis is operating properly
False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self.sys_eeprom.base_mac_addr()
def get_serial_number(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this
chassis.
"""
return self.sys_eeprom.serial_number_str()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self.sys_eeprom.system_eeprom_info()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
raise NotImplementedError
def get_component_name_list(self):
"""
Retrieves a list of the names of components available on the chassis (e.g., BIOS, CPLD, FPGA, etc.)
Returns:
A list containing the names of components available on the chassis
"""
return self._component_name_list
def get_firmware_version(self, component_name):
"""
Retrieves platform-specific hardware/firmware versions for chassis
componenets such as BIOS, CPLD, FPGA, etc.
Args:
component_name: A string, the component name.
Returns:
A string containing platform-specific component versions
"""
raise NotImplementedError
def install_component_firmware(self, component_name, image_path):
"""
Install firmware to component
Args:
component_name: A string, the component name.
image_path: A string, path to firmware image.
Returns:
A boolean, True if install was successful, False if not
"""
raise NotImplementedError
##############################################
# Module methods
##############################################
def get_num_modules(self):
"""
Retrieves the number of modules available on this chassis
Returns:
An integer, the number of modules available on this chassis
"""
return len(self._module_list)
def get_all_modules(self):
"""
Retrieves all modules available on this chassis
Returns:
A list of objects derived from ModuleBase representing all
modules available on this chassis
"""
return self._module_list
def get_module(self, index):
"""
Retrieves module represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the module to
retrieve
Returns:
An object dervied from ModuleBase representing the specified
module
"""
module = None
try:
module = self._module_list[index]
except IndexError:
sys.stderr.write("Module index {} out of range (0-{})\n".format(
index, len(self._module_list)-1))
return module
##############################################
# Fan methods
##############################################
def get_num_fans(self):
"""
Retrieves the number of fans available on this chassis
Returns:
An integer, the number of fan modules available on this chassis
"""
return len(self._fan_list)
def get_all_fans(self):
"""
Retrieves all fan modules available on this chassis
Returns:
A list of objects derived from FanBase representing all fan
modules available on this chassis
"""
return self._fan_list
def get_fan(self, index):
"""
Retrieves fan module represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the fan module to
retrieve
Returns:
An object dervied from FanBase representing the specified fan
module
"""
fan = None
try:
fan = self._fan_list[index]
except IndexError:
sys.stderr.write("Fan index {} out of range (0-{})\n".format(
index, len(self._fan_list)-1))
return fan
##############################################
# PSU methods
##############################################
def get_num_psus(self):
"""
Retrieves the number of power supply units available on this chassis
Returns:
An integer, the number of power supply units available on this
chassis
"""
return len(self._psu_list)
def get_all_psus(self):
"""
Retrieves all power supply units available on this chassis
Returns:
A list of objects derived from PsuBase representing all power
supply units available on this chassis
"""
return self._psu_list
def get_psu(self, index):
"""
Retrieves power supply unit represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the power supply unit to
retrieve
Returns:
An object dervied from PsuBase representing the specified power
supply unit
"""
psu = None
try:
psu = self._psu_list[index]
except IndexError:
sys.stderr.write("PSU index {} out of range (0-{})\n".format(
index, len(self._psu_list)-1))
return psu
##############################################
# THERMAL methods
##############################################
def get_num_thermals(self):
"""
Retrieves the number of thermals available on this chassis
Returns:
An integer, the number of thermals available on this chassis
"""
return len(self._thermal_list)
def get_all_thermals(self):
"""
Retrieves all thermals available on this chassis
Returns:
A list of objects derived from ThermalBase representing all thermals
available on this chassis
"""
return self._thermal_list
def get_thermal(self, index):
"""
Retrieves thermal unit represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the thermal to
retrieve
Returns:
An object dervied from ThermalBase representing the specified thermal
"""
thermal = None
try:
thermal = self._thermal_list[index]
except IndexError:
sys.stderr.write("THERMAL index {} out of range (0-{})\n".format(
index, len(self._thermal_list)-1))
return thermal
##############################################
# SFP methods
##############################################
def get_num_sfps(self):
"""
Retrieves the number of sfps available on this chassis
Returns:
An integer, the number of sfps available on this chassis
"""
return len(self._sfp_list)
def get_all_sfps(self):
"""
Retrieves all sfps available on this chassis
Returns:
A list of objects derived from SfpBase representing all sfps
available on this chassis
"""
return self._sfp_list
def get_sfp(self, index):
"""
Retrieves sfp represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 0.
For example, 0 for Ethernet0, 1 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
try:
sfp = self._sfp_list[index]
except IndexError:
sys.stderr.write("SFP index {} out of range (0-{})\n".format(
index, len(self._sfp_list)-1))
return sfp
##############################################
# System LED methods
##############################################
def set_system_led(self, led_device_name, color):
result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color);
if result == False:
print msg
return (False)
index=self.pddf_obj.data[led_device_name]['dev_attr']['index']
device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path())
self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path())
return (True)
def get_system_led(self, led_device_name):
if (not led_device_name in self.pddf_obj.data.keys()):
status= "[FAILED] " + led_device_name + " is not configured"
return (status)
index=self.pddf_obj.data[led_device_name]['dev_attr']['index']
device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path())
color=self.pddf_obj.get_led_color()
return (color)
##############################################
# Other methods
##############################################
def get_watchdog(self):
"""
Retreives hardware watchdog device on this chassis
Returns:
An object derived from WatchdogBase representing the hardware
watchdog device
"""
return self._watchdog
def get_eeprom(self):
"""
Retreives eeprom device on this chassis
Returns:
An object derived from WatchdogBase representing the hardware
eeprom device
"""
return self.sys_eeprom
def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
Args:
timeout: Timeout in milliseconds (optional). If timeout == 0,
this method will block until a change is detected.
Returns:
(bool, dict):
- True if call successful, False if not;
- A nested dictionary where key is a device type,
value is a dictionary with key:value pairs in the format of
{'device_id':'device_event'},
where device_id is the device ID for this device and
device_event,
status='1' represents device inserted,
status='0' represents device removed.
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
indicates that fan 0 has been removed, fan 2
has been inserted and sfp 11 has been removed.
"""
raise NotImplementedError

View File

@ -0,0 +1,124 @@
#!/usr/bin/env python
#############################################################################
# PDDF
#
# PDDF syseeprom base class inherited from the base class
#############################################################################
try:
from sonic_eeprom import eeprom_tlvinfo
import binascii
except ImportError, e:
raise ImportError(str(e) + "- required module not found")
class PddfEeprom(eeprom_tlvinfo.TlvInfoDecoder):
_TLV_INFO_MAX_LEN = 256
pddf_obj = {}
plugin_data = {}
def __init__(self, pddf_data=None, pddf_plugin_data=None):
if not pddf_data or not pddf_plugin_data:
raise ValueError('PDDF JSON data error')
self.pddf_obj = pddf_data
self.plugin_data = pddf_plugin_data
# system EEPROM always has device name EEPROM1
self.eeprom_path = self.pddf_obj.get_path("EEPROM1", "eeprom")
if self.eeprom_path is None:
return
super(PddfEeprom, self).__init__(self.eeprom_path, 0, '', True)
self.eeprom_tlv_dict = dict()
try:
self.eeprom_data = self.read_eeprom()
except:
self.eeprom_data = "N/A"
raise RuntimeError("PddfEeprom is not Programmed")
else:
eeprom = self.eeprom_data
if not self.is_valid_tlvinfo_header(eeprom):
return
total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10])
tlv_index = self._TLV_INFO_HDR_LEN
tlv_end = self._TLV_INFO_HDR_LEN + total_length
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
if not self.is_valid_tlv(eeprom[tlv_index:]):
break
tlv = eeprom[tlv_index:tlv_index + 2
+ ord(eeprom[tlv_index + 1])]
code = "0x%02X" % (ord(tlv[0]))
if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT:
value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) |
(ord(tlv[4]) << 8) | ord(tlv[5]))
value += str(tlv[6:6 + ord(tlv[1])])
else:
name, value = self.decoder(None, tlv)
self.eeprom_tlv_dict[code] = value
if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32:
break
tlv_index += ord(eeprom[tlv_index+1]) + 2
def serial_number_str(self):
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER)
if not is_valid:
return "N/A"
return results[2]
def base_mac_addr(self):
(is_valid, t) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_MAC_BASE)
if not is_valid or t[1] != 6:
return super(TlvInfoDecoder, self).switchaddrstr(e)
return ":".join([binascii.b2a_hex(T) for T in t[2]])
def modelstr(self):
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PRODUCT_NAME)
if not is_valid:
return "N/A"
return results[2]
def part_number_str(self):
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PART_NUMBER)
if not is_valid:
return "N/A"
return results[2]
def serial_str(self):
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERVICE_TAG)
if not is_valid:
return "N/A"
return results[2]
def revision_str(self):
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_DEVICE_VERSION)
if not is_valid:
return "N/A"
return results[2]
def system_eeprom_info(self):
"""
Returns a dictionary, where keys are the type code defined in
ONIE EEPROM format and values are their corresponding values
found in the system EEPROM.
"""
return self.eeprom_tlv_dict

View File

@ -0,0 +1,332 @@
#!/usr/bin/env python
# All the supported FAN SysFS aattributes are
#- fan<idx>_present
#- fan<idx>_direction
#- fan<idx>_input
#- fan<idx>_pwm
#- fan<idx>_fault
# where idx is in the range [1-32]
#
try:
from sonic_platform_base.fan_base import FanBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PddfFan(FanBase):
"""PDDF generic Fan class"""
pddf_obj = {}
plugin_data = {}
def __init__(self, tray_idx, fan_idx=0, pddf_data=None, pddf_plugin_data=None, is_psu_fan=False, psu_index=0):
# idx is 0-based
if not pddf_data or not pddf_plugin_data:
raise ValueError('PDDF JSON data error')
self.pddf_obj = pddf_data
self.plugin_data = pddf_plugin_data
self.platform = self.pddf_obj.get_platform()
if tray_idx<0 or tray_idx>=self.platform['num_fantrays']:
print "Invalid fantray index %d\n"%tray_idx
return
if fan_idx<0 or fan_idx>=self.platform['num_fans_pertray']:
print "Invalid fan index (within a tray) %d\n"%fan_idx
return
self.fantray_index = tray_idx+1
self.fan_index = fan_idx+1
self.is_psu_fan = is_psu_fan
if self.is_psu_fan:
self.fans_psu_index = psu_index
def get_name(self):
"""
Retrieves the fan name
Returns: String containing fan-name
"""
if self.is_psu_fan:
return "PSU{}_FAN{}".format(self.fans_psu_index, self.fan_index)
else:
if 'name' in self.plugin_data['FAN']:
return self.plugin_data['FAN']['name'][str(self.fantray_index)]
else:
return "Fantray{}_{}".format(self.fantray_index, self.fan_index)
def get_presence(self):
if self.is_psu_fan:
return True
else:
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr_name = "fan" + str(idx) + "_present"
output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr_name)
if not output:
return False
mode = output['mode']
presence = output['status'].rstrip()
vmap = self.plugin_data['FAN']['present'][mode]['valmap']
if presence in vmap:
status = vmap[presence]
else:
status = False
return status
def get_status(self):
speed = self.get_speed()
status = True if (speed != 0) else False
return status
def get_direction(self):
"""
Retrieves the direction of fan
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
"""
if self.is_psu_fan:
device = "PSU{}".format(self.fans_psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_fan_dir")
if not output:
return False
mode = output['mode']
val = output['status']
val = val.rstrip()
vmap = self.plugin_data['PSU']['psu_fan_dir'][mode]['valmap']
if val in vmap:
direction = vmap[val]
else:
direction = val
else:
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr = "fan" + str(idx) + "_direction"
output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return False
mode = output['mode']
val = output['status']
val = val.rstrip()
vmap = self.plugin_data['FAN']['direction'][mode]['valmap']
if val in vmap:
direction = vmap[val]
else:
direction = val
return direction
def get_speed(self):
"""
Retrieves the speed of fan as a percentage of full speed
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
if self.is_psu_fan:
attr = "psu_fan{}_speed_rpm".format(self.fan_index)
device = "PSU{}".format(self.fans_psu_index)
output = self.pddf_obj.get_attr_name_output(device, attr)
if not output:
return 0
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
speed = int(output['status'])
max_speed = int(self.plugin_data['PSU']['PSU_FAN_MAX_SPEED'])
speed_percentage = (speed*100)/max_speed
return speed_percentage
else:
# TODO This calculation should change based on MAX FAN SPEED
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr = "fan" + str(idx) + "_pwm"
output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return 0
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
fpwm = int(output['status'])
pwm_to_dc = eval(self.plugin_data['FAN']['pwm_to_duty_cycle'])
speed_percentage = int(round(pwm_to_dc(fpwm)))
return speed_percentage
def get_speed_rpm(self):
"""
Retrieves the speed of fan in RPM
Returns:
An integer, Speed of fan in RPM
"""
if self.is_psu_fan:
attr = "psu_fan{}_speed_rpm".format(self.fan_index)
device = "PSU{}".format(self.fans_psu_index)
output = self.pddf_obj.get_attr_name_output(device, attr)
if not output:
return 0
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
speed = int(float(output['status']))
rpm_speed = speed
return rpm_speed
else:
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr = "fan" + str(idx) + "_input"
output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if output is None:
return 0
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
rpm_speed = int(float(output['status']))
return rpm_speed
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
target_speed = 0
if self.is_psu_fan:
# Target speed not usually supported for PSU fans
target_speed = 0
else:
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr = "fan" + str(idx) + "_pwm"
output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr)
if not output:
return 0
output['status'] = output['status'].rstrip()
if output['status'].isalpha():
return 0
else:
fpwm = int(output['status'])
pwm_to_dc = eval(self.plugin_data['FAN']['pwm_to_duty_cycle'])
speed_percentage = int(round(pwm_to_dc(fpwm)))
target_speed = speed_percentage
return target_speed
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
# Fix the speed vairance to 10 percent. If it changes based on platforms, overwrite
# this value in derived pddf fan class
return 10
def set_speed(self, speed):
"""
Sets the fan speed
Args:
speed: An integer, the percentage of full fan speed to set fan to,
in the range 0 (off) to 100 (full speed)
Returns:
A boolean, True if speed is set successfully, False if not
"""
if self.is_psu_fan:
print "Setting PSU fan speed is not allowed"
return False
else:
if speed<0 or speed>100:
print "Error: Invalid speed %d. Please provide a valid speed percentage"%speed
return False
if 'duty_cycle_to_pwm' not in self.plugin_data['FAN']:
print "Setting fan speed is not allowed !"
return False
else:
duty_cycle_to_pwm = eval(self.plugin_data['FAN']['duty_cycle_to_pwm'])
pwm = int(round(duty_cycle_to_pwm(speed)))
status = False
idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index
attr = "fan" + str(idx) + "_pwm"
output = self.pddf_obj.set_attr_name_output("FAN-CTRL", attr, pwm)
if not output:
return False
status = output['status']
return status
def set_status_led(self, color):
index = str(self.fantray_index-1)
led_device_name = "FANTRAY{}".format(self.fantray_index) + "_LED"
result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color);
if result == False:
print msg
return (False)
device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path())
self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path())
return (True)
def get_status_led(self):
index = str(self.fantray_index-1)
fan_led_device = "FANTRAY{}".format(self.fantray_index) + "_LED"
if (not fan_led_device in self.pddf_obj.data.keys()):
# Implement a generic status_led color scheme
if self.get_status():
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_OFF
device_name=self.pddf_obj.data[fan_led_device]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path())
color=self.pddf_obj.get_led_color()
return (color)
def dump_sysfs(self):
return self.pddf_obj.cli_dump_dsysfs('fan')

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
#############################################################################
# PDDF
# Module contains an implementation of SONiC Platform API and
# provides the platform information
#
#############################################################################
try:
import json
import pddfparse
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PddfPlatform(PlatformBase):
"""
PDDF Generic Platform class
"""
pddf_data = {}
pddf_plugin_data = {}
def __init__(self):
# Initialize the JSON data
self.pddf_data = pddfparse.PddfParse()
with open('/usr/share/sonic/platform/pddf/pd-plugin.json') as pd:
self.pddf_plugin_data = json.load(pd)
if not self.pddf_data or not self.pddf_plugin_data:
print "Error: PDDF JSON data is not loaded properly ... Exiting"
raise ValueError
PlatformBase.__init__(self)
self._chassis = Chassis(self.pddf_data, self.pddf_plugin_data)

View File

@ -0,0 +1,298 @@
#!/usr/bin/env python
#
# All the supported PSU SysFS aattributes are
#- psu_present
#- psu_model_name
#- psu_power_good
#- psu_mfr_id
#- psu_serial_num
#- psu_fan_dir
#- psu_v_out
#- psu_i_out
#- psu_p_out
#- psu_fan1_speed_rpm
#
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PddfPsu(PsuBase):
"""PDDF generic PSU class"""
pddf_obj = {}
plugin_data = {}
def __init__(self, index, pddf_data=None, pddf_plugin_data=None):
PsuBase.__init__(self)
if not pddf_data or not pddf_plugin_data:
raise ValueError('PDDF JSON data error')
self.pddf_obj = pddf_data
self.plugin_data = pddf_plugin_data
self.platform = self.pddf_obj.get_platform()
self.psu_index = index + 1
self._fan_list = [] # _fan_list under PsuBase class is a global variable, hence we need to use _fan_list per class instatiation
self.num_psu_fans = int(self.pddf_obj.get_num_psu_fans('PSU{}'.format(index+1)))
for psu_fan_idx in range(self.num_psu_fans):
psu_fan = Fan(0, psu_fan_idx, pddf_data, pddf_plugin_data, True, self.psu_index)
self._fan_list.append(psu_fan)
def get_num_fans(self):
"""
Retrieves the number of fan modules available on this PSU
Returns:
An integer, the number of fan modules available on this PSU
"""
return len(self._fan_list)
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
if 'name' in self.plugin_data['PSU']:
return self.plugin_data['PSU']['name'][str(self.psu_index)]
else:
return "PSU{}".format(self.psu_index)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
status = 0
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_present")
if not output:
return False
mode = output['mode']
status = output['status']
vmap = self.plugin_data['PSU']['psu_present'][mode]['valmap']
if status.rstrip('\n') in vmap:
return vmap[status.rstrip('\n')]
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_model_name")
if not output:
return None
model = output['status']
# strip_non_ascii
stripped = (c for c in model if 0 < ord(c) < 127)
model = ''.join(stripped)
return model.rstrip('\n')
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_serial_num")
if not output:
return None
serial = output['status']
return serial.rstrip('\n')
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_power_good")
if not output:
return False
mode = output['mode']
status = output ['status']
vmap = self.plugin_data['PSU']['psu_power_good'][mode]['valmap']
if status.rstrip('\n') in vmap:
return vmap[status.rstrip('\n')]
else:
return False
def get_mfr_id(self):
"""
Retrieves the manufacturer id of the device
Returns:
string: Manufacturer Id of device
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_mfr_id")
if not output:
return None
mfr = output['status']
return mfr.rstrip('\n')
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_v_out")
if not output:
return 0.0
v_out = output['status']
return float(v_out)/1000
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_i_out")
if not output:
return 0.0
i_out = output['status']
# current in mA
return float(i_out)/1000
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts,
e.g. 302.6
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_p_out")
if not output:
return 0.0
p_out = output['status']
# power is returned in micro watts
return float(p_out)/1000000
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and
passed all its internal self-tests, False if not.
"""
return self.get_status()
def set_status_led(self, color):
index = str(self.psu_index-1)
led_device_name = "PSU{}".format(self.psu_index) + "_LED"
result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color);
if result == False:
print msg
return (False)
device_name=self.pddf_obj.data[led_device_name]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path())
self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path())
return (True)
def get_status_led(self):
index = str(self.psu_index-1)
psu_led_device = "PSU{}_LED".format(self.psu_index)
if (not psu_led_device in self.pddf_obj.data.keys()):
# Implement a generic status_led color scheme
if self.get_powergood_status():
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_OFF
device_name=self.pddf_obj.data[psu_led_device]['dev_info']['device_name']
self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path())
self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path())
color=self.pddf_obj.get_led_color()
return (color)
def get_input_voltage(self):
"""
Retrieves current PSU input voltage
Returns:
A float number, the input voltage in volts,
e.g. 12.1
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_v_in")
if not output:
return 0.0
v_in = output['status']
return float(v_in)/1000
def get_input_current(self):
"""
Retrieves present electric current supplied to the PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
device = "PSU{}".format(self.psu_index)
output = self.pddf_obj.get_attr_name_output(device, "psu_i_in")
if not output:
return 0.0
i_in = output['status']
# current in mA
return float(i_in)/1000
def dump_sysfs(self):
return self.pddf_obj.cli_dump_dsysfs('psu')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
#!/usr/bin/env python
# All the supported Temperature Sensor SysFS aattributes are
#- temp1_high_crit_threshold
#- temp1_high_threshold
#- temp1_input
#- temp_low_threshold
#- temp1_low_crit_threshold
try:
from sonic_platform_base.thermal_base import ThermalBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PddfThermal(ThermalBase):
"""PDDF generic Thermal class"""
pddf_obj = {}
plugin_data = {}
def __init__(self, index, pddf_data=None, pddf_plugin_data=None):
if not pddf_data or not pddf_plugin_data:
raise ValueError('PDDF JSON data error')
self.pddf_obj = pddf_data
self.plugin_data = pddf_plugin_data
self.platform = self.pddf_obj.get_platform()
self.thermal_index = index + 1
self.thermal_obj_name = "TEMP{}".format(self.thermal_index)
self.thermal_obj = self.pddf_obj.data[self.thermal_obj_name]
def get_name(self):
if 'dev_attr' in self.thermal_obj.keys():
if 'display_name' in self.thermal_obj['dev_attr']:
return str(self.thermal_obj['dev_attr']['display_name'])
# In case of errors
return (self.thermal_obj_name)
def get_temperature(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_input")
if not output:
return None
if output['status'].isalpha():
attr_value = None
else:
attr_value = float(output['status'])
if output['mode']=='bmc':
return attr_value
else:
return (attr_value/float(1000))
def get_high_threshold(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold")
if not output:
return None
if output['status'].isalpha():
attr_value = None
else:
attr_value = float(output['status'])
if output['mode']=='bmc':
return attr_value
else:
return (attr_value/float(1000))
def get_low_threshold(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold")
if not output:
return None
if output['status'].isalpha():
attr_value = None
else:
attr_value = float(output['status'])
if output['mode']=='bmc':
return attr_value
else:
return (attr_value/float(1000))
def set_high_threshold(self, temperature):
node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold")
if node is None:
print "ERROR %s does not exist"%node
return None
cmd = "echo '%d' > %s"%(temperature * 1000, node)
os.system(cmd)
return (True)
def set_low_threshold(self, temperature):
node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold")
if node is None:
print "ERROR %s does not exist"%node
return None
cmd = "echo '%d' > %s"%(temperature * 1000, node)
os.system(cmd)
return (True)
def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_crit_threshold")
if not output:
return None
if output['status'].isalpha():
attr_value = None
else:
attr_value = float(output['status'])
if output['mode']=='bmc':
return attr_value
else:
return (attr_value/float(1000))
def get_low_critical_threshold(self):
"""
Retrieves the low critical threshold temperature of thermal
Returns:
A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_crit_threshold")
if not output:
return None
if output['status'].isalpha():
attr_value = None
else:
attr_value = float(output['status'])
if output['mode']=='bmc':
return attr_value
else:
return (attr_value/float(1000))
# Helper Functions
def get_temp_label(self):
if 'bmc' in self.pddf_obj.data[self.thermal_obj_name].keys():
return None
else:
if self.thermal_obj_name in self.pddf_obj.data.keys():
dev= self.pddf_obj.data[self.thermal_obj_name]
topo_info = dev['i2c']['topo_info']
label="%s-i2c-%d-%x" % (topo_info['dev_type'], int(topo_info['parent_bus'], 0),
int(topo_info['dev_addr'], 0))
return (label)
else:
return None
def dump_sysfs(self):
return self.pddf_obj.cli_dump_dsysfs('temp-sensors')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
# All the derived classes for PDDF
__all__ = ["platform", "chassis", "sfp", "psu", "thermal"]
# Commenting the below code as this just for the reference for the ODMs.
# It can be uncommented when this reference code is used
#from sonic_platform import *

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
#############################################################################
# PDDF
# Module contains an implementation of SONiC Chassis API
#
#############################################################################
try:
from sonic_platform_pddf_base.pddf_chassis import PddfChassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Chassis(PddfChassis):
"""
PDDF Platform-specific Chassis class
"""
def __init__(self, pddf_data=None, pddf_plugin_data=None):
PddfChassis.__init__(self, pddf_data, pddf_plugin_data)
# Provide the functions/variables below for which implementation is to be overwritten

View File

@ -0,0 +1,14 @@
#!/usr/bin/env python
try:
from sonic_platform_pddf_base.pddf_eeprom import PddfEeprom
except ImportError, e:
raise ImportError(str(e) + "- required module not found")
class Eeprom(PddfEeprom):
def __init__(self, pddf_data=None, pddf_plugin_data=None):
PddfEeprom.__init__(self, pddf_data, pddf_plugin_data)
# Provide the functions/variables below for which implementation is to be overwritten

Some files were not shown because too many files have changed in this diff Show More