Upload wnc-osw1800
This commit is contained in:
parent
c47c409a3a
commit
8471499077
@ -0,0 +1,55 @@
|
|||||||
|
# name lanes alias speed autoneg fec
|
||||||
|
Ethernet0 0 Ethernet0 25000 1 1
|
||||||
|
Ethernet4 1 Ethernet4 25000 1 1
|
||||||
|
Ethernet8 2 Ethernet8 25000 1 1
|
||||||
|
Ethernet12 3 Ethernet12 25000 1 1
|
||||||
|
Ethernet16 4 Ethernet16 25000 1 1
|
||||||
|
Ethernet20 5 Ethernet20 25000 1 1
|
||||||
|
Ethernet24 6 Ethernet24 25000 1 1
|
||||||
|
Ethernet28 7 Ethernet28 25000 1 1
|
||||||
|
Ethernet32 8 Ethernet32 25000 1 1
|
||||||
|
Ethernet36 9 Ethernet36 25000 1 1
|
||||||
|
Ethernet40 10 Ethernet40 25000 1 1
|
||||||
|
Ethernet44 11 Ethernet44 25000 1 1
|
||||||
|
Ethernet48 12 Ethernet48 25000 1 1
|
||||||
|
Ethernet52 13 Ethernet52 25000 1 1
|
||||||
|
Ethernet56 14 Ethernet56 25000 1 1
|
||||||
|
Ethernet60 15 Ethernet60 25000 1 1
|
||||||
|
Ethernet64 16 Ethernet64 25000 1 1
|
||||||
|
Ethernet68 17 Ethernet68 25000 1 1
|
||||||
|
Ethernet72 18 Ethernet72 25000 1 1
|
||||||
|
Ethernet76 19 Ethernet76 25000 1 1
|
||||||
|
Ethernet80 20 Ethernet80 25000 1 1
|
||||||
|
Ethernet84 21 Ethernet84 25000 1 1
|
||||||
|
Ethernet88 22 Ethernet88 25000 1 1
|
||||||
|
Ethernet92 23 Ethernet92 25000 1 1
|
||||||
|
Ethernet96 24 Ethernet96 25000 1 1
|
||||||
|
Ethernet100 25 Ethernet100 25000 1 1
|
||||||
|
Ethernet104 26 Ethernet104 25000 1 1
|
||||||
|
Ethernet108 27 Ethernet108 25000 1 1
|
||||||
|
Ethernet112 28 Ethernet112 25000 1 1
|
||||||
|
Ethernet116 29 Ethernet116 25000 1 1
|
||||||
|
Ethernet120 30 Ethernet120 25000 1 1
|
||||||
|
Ethernet124 31 Ethernet124 25000 1 1
|
||||||
|
Ethernet128 32 Ethernet128 25000 1 1
|
||||||
|
Ethernet132 33 Ethernet132 25000 1 1
|
||||||
|
Ethernet136 34 Ethernet136 25000 1 1
|
||||||
|
Ethernet140 35 Ethernet140 25000 1 1
|
||||||
|
Ethernet144 36 Ethernet144 25000 1 1
|
||||||
|
Ethernet148 37 Ethernet148 25000 1 1
|
||||||
|
Ethernet152 38 Ethernet152 25000 1 1
|
||||||
|
Ethernet156 39 Ethernet156 25000 1 1
|
||||||
|
Ethernet160 40 Ethernet160 25000 1 1
|
||||||
|
Ethernet164 41 Ethernet164 25000 1 1
|
||||||
|
Ethernet168 42 Ethernet168 25000 1 1
|
||||||
|
Ethernet172 43 Ethernet172 25000 1 1
|
||||||
|
Ethernet176 44 Ethernet176 25000 1 1
|
||||||
|
Ethernet180 45 Ethernet180 25000 1 1
|
||||||
|
Ethernet184 46 Ethernet184 25000 1 1
|
||||||
|
Ethernet188 47 Ethernet188 25000 1 1
|
||||||
|
Ethernet192 48,49,50,51 Ethernet192 100000 1 1
|
||||||
|
Ethernet196 52,53,54,55 Ethernet196 100000 1 1
|
||||||
|
Ethernet200 56,57,58,59 Ethernet200 100000 1 1
|
||||||
|
Ethernet204 60,61,62,63 Ethernet204 100000 1 1
|
||||||
|
Ethernet208 64,65,66,67 Ethernet208 100000 1 1
|
||||||
|
Ethernet212 68,69,70,71 Ethernet212 100000 1 1
|
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"chip_list": [
|
||||||
|
{
|
||||||
|
"id": "asic-0",
|
||||||
|
"chip_family": "Tofino",
|
||||||
|
"instance": 0,
|
||||||
|
"pcie_sysfs_prefix": "/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0",
|
||||||
|
"pcie_domain": 0,
|
||||||
|
"pcie_bus": 5,
|
||||||
|
"pcie_fn": 0,
|
||||||
|
"pcie_dev": 0,
|
||||||
|
"pcie_int_mode": 1,
|
||||||
|
"sds_fw_path": "share/tofino_sds_fw/avago/firmware"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"instance": 0,
|
||||||
|
"p4_program_list": [
|
||||||
|
{
|
||||||
|
"id": "pgm-0",
|
||||||
|
"instance": 0,
|
||||||
|
"path": "switch",
|
||||||
|
"program-name": "switch",
|
||||||
|
"pd": "lib/tofinopd/switch/libpd.so",
|
||||||
|
"pd-thrift": "lib/tofinopd/switch/libpdthrift.so",
|
||||||
|
"table-config": "share/tofinopd/switch/context.json",
|
||||||
|
"tofino-bin": "share/tofinopd/switch/tofino.bin",
|
||||||
|
"switchapi": "lib/libswitchapi.so",
|
||||||
|
"switchsai": "lib/libswitchsai.so",
|
||||||
|
"agent0": "lib/platform/x86_64-wnc_osw1800-r0/libpltfm_mgr.so",
|
||||||
|
"switchapi_port_add": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
11
device/wnc/x86_64-wnc_osw1800-r0/fancontrol
Normal file
11
device/wnc/x86_64-wnc_osw1800-r0/fancontrol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
INTERVAL=10
|
||||||
|
DEVPATH=hwmon1=devices/pci0000:00/0000:00:16.0/usb1/1-1/1-1.2/1-1.2.3/1-1.2.3:1.2/i2c-2/i2c-5/5-0033 hwmon2=devices/pci0000:00/0000:00:16.0/usb1/1-1/1-1.2/1-1.2.3/1-1.2.3:1.2/i2c-2/i2c-7/7-001e hwmon3=devices/pci0000:00/0000:00:16.0/usb1/1-1/1-1.2/1-1.2.3/1-1.2.3:1.2/i2c-2/i2c-7/7-004e hwmon4=devices/pci0000:00/0000:00:16.0/usb1/1-1/1-1.2/1-1.2.3/1-1.2.3:1.2/i2c-2/i2c-7/7-004f
|
||||||
|
DEVNAME=hwmon1=wnc_cpld3 hwmon2=tmp421 hwmon3=tmp75 hwmon4=tmp421
|
||||||
|
FCTEMPS=hwmon1/pwm1=hwmon2/temp1_input hwmon1/pwm2=hwmon2/temp2_input hwmon1/pwm3=hwmon3/temp1_input hwmon1/pwm4=hwmon4/temp1_input hwmon1/pwm5=hwmon4/temp2_input
|
||||||
|
FCFANS=hwmon1/pwm1=hwmon1/fan1_input hwmon1/pwm2=hwmon1/fan2_input hwmon1/pwm3=hwmon1/fan3_input hwmon1/pwm4=hwmon1/fan4_input hwmon1/pwm5=hwmon1/fan5_input
|
||||||
|
MINTEMP=hwmon1/pwm1=20 hwmon1/pwm2=20 hwmon1/pwm3=20 hwmon1/pwm4=20 hwmon1/pwm5=20
|
||||||
|
MAXTEMP=hwmon1/pwm1=50 hwmon1/pwm2=50 hwmon1/pwm3=50 hwmon1/pwm4=50 hwmon1/pwm5=50
|
||||||
|
MINSTART=hwmon1/pwm1=32 hwmon1/pwm2=32 hwmon1/pwm3=32 hwmon1/pwm4=32 hwmon1/pwm5=32
|
||||||
|
MINSTOP=hwmon1/pwm1=22 hwmon1/pwm2=22 hwmon1/pwm3=22 hwmon1/pwm4=22 hwmon1/pwm5=22
|
||||||
|
MINPWM=hwmon1/pwm1=10 hwmon1/pwm2=10 hwmon1/pwm3=10 hwmon1/pwm4=10 hwmon1/pwm5=10
|
||||||
|
MAXPWM=hwmon1/pwm1=100 hwmon1/pwm2=100 hwmon1/pwm3=100 hwmon1/pwm4=100 hwmon1/pwm5=100
|
3
device/wnc/x86_64-wnc_osw1800-r0/installer.conf
Normal file
3
device/wnc/x86_64-wnc_osw1800-r0/installer.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
CONSOLE_PORT=0x2f8
|
||||||
|
CONSOLE_DEV=1
|
||||||
|
CONSOLE_SPEED=57600
|
1761
device/wnc/x86_64-wnc_osw1800-r0/minigraph.xml
Normal file
1761
device/wnc/x86_64-wnc_osw1800-r0/minigraph.xml
Normal file
File diff suppressed because it is too large
Load Diff
22
device/wnc/x86_64-wnc_osw1800-r0/plugins/eeprom.py
Normal file
22
device/wnc/x86_64-wnc_osw1800-r0/plugins/eeprom.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
try:
|
||||||
|
import exceptions
|
||||||
|
import binascii
|
||||||
|
import time
|
||||||
|
import optparse
|
||||||
|
import warnings
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from sonic_eeprom import eeprom_base
|
||||||
|
from sonic_eeprom import eeprom_tlvinfo
|
||||||
|
except ImportError, e:
|
||||||
|
raise ImportError (str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class board(eeprom_tlvinfo.TlvInfoDecoder):
|
||||||
|
|
||||||
|
def __init__(self, name, path, cpld_root, ro):
|
||||||
|
self.eeprom_path = "/sys/class/i2c-adapter/i2c-8/8-0052/eeprom"
|
||||||
|
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
||||||
|
|
64
device/wnc/x86_64-wnc_osw1800-r0/plugins/psuutil.py
Normal file
64
device/wnc/x86_64-wnc_osw1800-r0/plugins/psuutil.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#
|
||||||
|
# psuutil.py
|
||||||
|
# Platform-specific PSU status interface for SONiC
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_psu.psu_base import PsuBase
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class PsuUtil(PsuBase):
|
||||||
|
"""Platform-specific PSUutil class"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
PsuBase.__init__(self)
|
||||||
|
|
||||||
|
def get_num_psus(self):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def get_psu_status(self, index):
|
||||||
|
if index == 1:
|
||||||
|
psu_path = "/sys/bus/i2c/devices/6-0050/eeprom"
|
||||||
|
elif index == 2:
|
||||||
|
psu_path = "/sys/bus/i2c/devices/6-0051/eeprom"
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = open(psu_path, "rb")
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
result = int(data.read(1).encode("hex"), 16)
|
||||||
|
data.close()
|
||||||
|
|
||||||
|
if result != 255 and result != 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_psu_presence(self, index):
|
||||||
|
if index == 1:
|
||||||
|
psu_path = "/sys/bus/i2c/devices/6-0050/eeprom"
|
||||||
|
elif index == 2:
|
||||||
|
psu_path = "/sys/bus/i2c/devices/6-0051/eeprom"
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = open(psu_path, "rb")
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
result = int(data.read(1).encode("hex"), 16)
|
||||||
|
data.close()
|
||||||
|
|
||||||
|
if result != 255 and result != 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
205
device/wnc/x86_64-wnc_osw1800-r0/plugins/sfputil.py
Normal file
205
device/wnc/x86_64-wnc_osw1800-r0/plugins/sfputil.py
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#! /usr/bin/python
|
||||||
|
#
|
||||||
|
# Platform-specific SFP transceiver interface for SONiC
|
||||||
|
#
|
||||||
|
|
||||||
|
try:
|
||||||
|
import time
|
||||||
|
from sonic_sfp.sfputilbase import SfpUtilBase
|
||||||
|
import sys
|
||||||
|
sys.path.append('/usr/lib/python2.7/dist-packages/sonic_sfp/')
|
||||||
|
from sff8472 import sff8472InterfaceId
|
||||||
|
from sff8472 import sff8472Dom
|
||||||
|
from sff8436 import sff8436InterfaceId
|
||||||
|
from sff8436 import sff8436Dom
|
||||||
|
except ImportError, e:
|
||||||
|
raise ImportError("%s - required module not found" % str(e))
|
||||||
|
|
||||||
|
|
||||||
|
class SfpUtil(SfpUtilBase):
|
||||||
|
"""Platform-specific SfpUtil class"""
|
||||||
|
|
||||||
|
PORT_START = 0
|
||||||
|
PORT_END = 53
|
||||||
|
PORTS_IN_BLOCK = 54
|
||||||
|
|
||||||
|
EEPROM_OFFSET = 11
|
||||||
|
|
||||||
|
_port_to_eeprom_mapping = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_start(self):
|
||||||
|
return self.PORT_START
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_end(self):
|
||||||
|
return self.PORT_END
|
||||||
|
|
||||||
|
@property
|
||||||
|
def qsfp_ports(self):
|
||||||
|
return range(self.PORT_START + 48, self.PORTS_IN_BLOCK)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_to_eeprom_mapping(self):
|
||||||
|
return self._port_to_eeprom_mapping
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
|
||||||
|
|
||||||
|
for x in range(0, self.port_end + 1):
|
||||||
|
self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET)
|
||||||
|
|
||||||
|
SfpUtilBase.__init__(self)
|
||||||
|
|
||||||
|
def get_presence(self, port_num):
|
||||||
|
bit_mask = port_num % 8
|
||||||
|
|
||||||
|
if port_num <= 7:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/3-0031/sfp_mod_abs1"
|
||||||
|
elif 8 <= port_num and port_num <= 15:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/3-0031/sfp_mod_abs2"
|
||||||
|
elif 16 <= port_num and port_num <= 23:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/3-0031/sfp_mod_abs3"
|
||||||
|
elif 24 <= port_num and port_num <= 27:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/3-0031/sfp_mod_abs4"
|
||||||
|
elif 28 <= port_num and port_num <= 31:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/4-0032/sfp_mod_abs1"
|
||||||
|
bit_mask = bit_mask - 4
|
||||||
|
elif 32 <= port_num and port_num <= 39:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/4-0032/sfp_mod_abs2"
|
||||||
|
elif 40 <= port_num and port_num <= 47:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/4-0032/sfp_mod_abs3"
|
||||||
|
elif 48 <= port_num and port_num <= 71:
|
||||||
|
presence_path = "/sys/bus/i2c/devices/4-0032/qsfp_modprs"
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg_file = open(presence_path, "rb")
|
||||||
|
except IOError as e:
|
||||||
|
print "Error: unable to open file: %s" % str(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = reg_file.readline().rstrip()
|
||||||
|
reg_value = int(content, 16)
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
if reg_value & (1 << bit_mask) == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_low_power_mode(self, port_num):
|
||||||
|
if port_num in self.qsfp_ports:
|
||||||
|
bit_mask = port_num % 8
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg_file = open("/sys/bus/i2c/devices/4-0032/qsfp_lpmode")
|
||||||
|
except IOError as e:
|
||||||
|
print "Error: unable to open file: %s" % str(e)
|
||||||
|
|
||||||
|
content = reg_file.readline().rstrip()
|
||||||
|
reg_value = int(content, 16)
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
if reg_value & (1 << bit_mask) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_low_power_mode(self, port_num, lpmode):
|
||||||
|
if port_num in self.qsfp_ports:
|
||||||
|
bit_mask = port_num % 8
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg_file = open("/sys/bus/i2c/devices/4-0032/qsfp_lpmode", "r+")
|
||||||
|
except IOError as e:
|
||||||
|
print "Error: unable to open file: %s" % str(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = reg_file.readline().rstrip()
|
||||||
|
reg_value = int(content, 16)
|
||||||
|
|
||||||
|
if lpmode is True:
|
||||||
|
reg_value = reg_value | (1 << bit_mask)
|
||||||
|
else:
|
||||||
|
reg_value = reg_value & ~(1 << bit_mask)
|
||||||
|
|
||||||
|
reg_file.seek(0)
|
||||||
|
reg_file.write(str(reg_value))
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reset(self, port_num):
|
||||||
|
if port_num in self.qsfp_ports:
|
||||||
|
bit_mask = (port_num % 8) + 2
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg_file = open("/sys/bus/i2c/devices/4-0032/reset_control", "r+")
|
||||||
|
except IOError as e:
|
||||||
|
print "Error: unable to open file: %s" % str(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = reg_file.readline().rstrip()
|
||||||
|
reg_value = int(content, 16)
|
||||||
|
reg_value = reg_value & ~(1 << bit_mask)
|
||||||
|
|
||||||
|
reg_file.seek(0)
|
||||||
|
reg_file.write(str(reg_value))
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg_file = open("/sys/bus/i2c/devices/4-0032/reset_control", "w")
|
||||||
|
except IOError as e:
|
||||||
|
print "Error: unable to open file: %s" % str(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
reg_value = reg_value | (1 << bit_mask)
|
||||||
|
reg_file.seek(0)
|
||||||
|
reg_file.write(str(reg_value))
|
||||||
|
reg_file.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_eeprom_dict(self, port_num):
|
||||||
|
if not self.get_presence(port_num):
|
||||||
|
return None
|
||||||
|
|
||||||
|
sfp_data = {}
|
||||||
|
|
||||||
|
eeprom_ifraw = self.get_eeprom_raw(port_num)
|
||||||
|
eeprom_domraw = self.get_eeprom_dom_raw(port_num)
|
||||||
|
|
||||||
|
if eeprom_ifraw is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if port_num in self.qsfp_ports:
|
||||||
|
sfpi_obj = sff8436InterfaceId(eeprom_ifraw)
|
||||||
|
if sfpi_obj is not None:
|
||||||
|
sfp_data['interface'] = sfpi_obj.get_data_pretty()
|
||||||
|
|
||||||
|
sfpd_obj = sff8436Dom(eeprom_ifraw)
|
||||||
|
if sfpd_obj is not None:
|
||||||
|
sfp_data['dom'] = sfpd_obj.get_data_pretty()
|
||||||
|
return sfp_data
|
||||||
|
|
||||||
|
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
|
||||||
|
if sfpi_obj is not None:
|
||||||
|
sfp_data['interface'] = sfpi_obj.get_data_pretty()
|
||||||
|
cal_type = sfpi_obj.get_calibration_type()
|
||||||
|
|
||||||
|
if eeprom_domraw is not None:
|
||||||
|
sfpd_obj = sff8472Dom(eeprom_domraw, cal_type)
|
||||||
|
if sfpd_obj is not None:
|
||||||
|
sfp_data['dom'] = sfpd_obj.get_data_pretty()
|
||||||
|
|
||||||
|
return sfp_data
|
33
device/wnc/x86_64-wnc_osw1800-r0/sensors.conf
Normal file
33
device/wnc/x86_64-wnc_osw1800-r0/sensors.conf
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# libsensors configuration filei
|
||||||
|
# --------------------------------------------------
|
||||||
|
#
|
||||||
|
|
||||||
|
bus "i2c-7" "i2c-2-mux"
|
||||||
|
chip "tmp421-i2c-7-1E"
|
||||||
|
label temp1 "ts1"
|
||||||
|
set temp1_max 50
|
||||||
|
set temp1_max_hyst 25
|
||||||
|
label temp2 "ts4"
|
||||||
|
set temp2_max 50
|
||||||
|
set temp2_max_hyst 25
|
||||||
|
|
||||||
|
chip "tmp75-i2c-7-4E"
|
||||||
|
label temp1 "ts3"
|
||||||
|
set temp1_max 50
|
||||||
|
set temp1_max_hyst 25
|
||||||
|
|
||||||
|
chip "tmp421-i2c-7-4F"
|
||||||
|
label temp1 "ts2"
|
||||||
|
set temp1_max 50
|
||||||
|
set temp1_max_hyst 25
|
||||||
|
label temp2 "ts5"
|
||||||
|
set temp2_max 50
|
||||||
|
set temp2_max_hyst 25
|
||||||
|
|
||||||
|
bus "i2c-5" "i2c-2-mux"
|
||||||
|
chip "wnc_cpld3-i2c-5-33"
|
||||||
|
label fan1 "fan1"
|
||||||
|
label fan2 "fan2"
|
||||||
|
label fan3 "fan3"
|
||||||
|
label fan4 "fan4"
|
||||||
|
label fan5 "fan5"
|
@ -1,5 +1,5 @@
|
|||||||
BFN_PLATFORM = bfnplatform_1.0.0_amd64.deb
|
BFN_PLATFORM = bfnplatform_1.0.0_amd64.deb
|
||||||
$(BFN_PLATFORM)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_7_0/bfnplatform_1.0.0_amd64.deb"
|
$(BFN_PLATFORM)_URL = "https://github.com/YaoTien/download/blob/master/sonic/sde/7_0_0_18/bfnplatform_1.0.0_amd64.deb"
|
||||||
|
|
||||||
SONIC_ONLINE_DEBS += $(BFN_PLATFORM) # $(BFN_SAI_DEV)
|
SONIC_ONLINE_DEBS += $(BFN_PLATFORM) # $(BFN_SAI_DEV)
|
||||||
$(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM)
|
$(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
BFN_SAI = bfnsdk_1.0.0_amd64.deb
|
BFN_SAI = bfnsdk_1.0.0_amd64.deb
|
||||||
$(BFN_SAI)_URL = "https://github.com/barefootnetworks/sonic-release-pkgs/raw/rel_7_0/bfnsdk_1.0.0_amd64.deb"
|
$(BFN_SAI)_URL = "https://github.com/YaoTien/download/blob/master/sonic/sde/7_0_0_18/bfnsdk_1.0.0_amd64.deb"
|
||||||
# $(BFN_SAI_DEV)_URL = "https://www.dropbox.com/s/4ljk6hzw82rudsr/bfnsdk_1.0.0_amd64.deb?dl=0"
|
# $(BFN_SAI_DEV)_URL = "https://www.dropbox.com/s/4ljk6hzw82rudsr/bfnsdk_1.0.0_amd64.deb?dl=0"
|
||||||
|
|
||||||
SONIC_ONLINE_DEBS += $(BFN_SAI) # $(BFN_SAI_DEV)
|
SONIC_ONLINE_DEBS += $(BFN_SAI) # $(BFN_SAI_DEV)
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
SONIC_ONE_IMAGE = sonic-barefoot.bin
|
SONIC_ONE_IMAGE = sonic-barefoot.bin
|
||||||
$(SONIC_ONE_IMAGE)_MACHINE = barefoot
|
$(SONIC_ONE_IMAGE)_MACHINE = barefoot
|
||||||
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
|
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
|
||||||
$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_PLATFORM_MODULE)
|
#$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
|
#$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
|
||||||
|
$(SONIC_ONE_IMAGE)_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
|
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
|
||||||
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)
|
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)
|
||||||
|
11
platform/barefoot/platform-modules-wnc-osw1800.mk
Normal file
11
platform/barefoot/platform-modules-wnc-osw1800.mk
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# BFN Platform modules
|
||||||
|
|
||||||
|
WNC_OSW1800_PLATFORM_MODULE_VERSION = 1.0
|
||||||
|
|
||||||
|
export WNC_OSW1800_PLATFORM_MODULE_VERSION
|
||||||
|
|
||||||
|
WNC_OSW1800_PLATFORM_MODULE = platform-modules-wnc-osw1800_$(WNC_OSW1800_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||||
|
$(WNC_OSW1800_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-wnc-osw1800
|
||||||
|
$(WNC_OSW1800_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
|
||||||
|
$(WNC_OSW1800_PLATFORM_MODULE)_PLATFORM = x86_64-wnc_osw1800-r0
|
||||||
|
SONIC_DPKG_DEBS += $(WNC_OSW1800_PLATFORM_MODULE)
|
@ -1,5 +1,6 @@
|
|||||||
include $(PLATFORM_PATH)/platform-modules-bfn.mk
|
include $(PLATFORM_PATH)/platform-modules-bfn.mk
|
||||||
include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk
|
include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk
|
||||||
|
include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk
|
||||||
include $(PLATFORM_PATH)/bfn-sai.mk
|
include $(PLATFORM_PATH)/bfn-sai.mk
|
||||||
include $(PLATFORM_PATH)/docker-syncd-bfn.mk
|
include $(PLATFORM_PATH)/docker-syncd-bfn.mk
|
||||||
include $(PLATFORM_PATH)/docker-syncd-bfn-rpc.mk
|
include $(PLATFORM_PATH)/docker-syncd-bfn-rpc.mk
|
||||||
|
15
platform/barefoot/sonic-platform-modules-wnc-osw1800/LICENSE
Normal file
15
platform/barefoot/sonic-platform-modules-wnc-osw1800/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Copyright (C) 2016 Microsoft, Inc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
@ -0,0 +1,7 @@
|
|||||||
|
# This file describes the maintainers for sonic-platform-modules-wnc-osw1800
|
||||||
|
# See the SONiC project governance document for more information
|
||||||
|
|
||||||
|
Name = "WNC"
|
||||||
|
Email = "wnc@wnc.com.tw"
|
||||||
|
Github = barefootnetworks
|
||||||
|
Mailinglist = wnc@wnc.com.tw
|
@ -0,0 +1,2 @@
|
|||||||
|
# sonic-platform-modules-wnc-osw1800
|
||||||
|
Device drivers for support of BFN platform for the SONiC project
|
@ -0,0 +1,5 @@
|
|||||||
|
platform-modules-wnc-osw1800 (1.0) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial release
|
||||||
|
|
||||||
|
-- WNC <wnc@wnc.com.tw> Mon, 11 Nov 2015 11:11:11 -0800
|
@ -0,0 +1 @@
|
|||||||
|
8
|
@ -0,0 +1,12 @@
|
|||||||
|
Source: platform-modules-wnc-osw1800
|
||||||
|
Section: main
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: WNC <wnc@wnc.com.tw>
|
||||||
|
Build-Depends: debhelper (>= 8.0.0), bzip2
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
|
||||||
|
Package: platform-modules-wnc-osw1800
|
||||||
|
Architecture: amd64
|
||||||
|
Depends: linux-image-3.16.0-4-amd64
|
||||||
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
Provides linux kernel driver for BF PCIe devices
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
@ -0,0 +1 @@
|
|||||||
|
platform-modules-wnc-osw1800_1.0_amd64.deb main extra
|
38
platform/barefoot/sonic-platform-modules-wnc-osw1800/debian/rules
Executable file
38
platform/barefoot/sonic-platform-modules-wnc-osw1800/debian/rules
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export INSTALL_MOD_DIR:=extra
|
||||||
|
|
||||||
|
PACKAGE_NAME := platform-modules-wnc-osw1800
|
||||||
|
KVERSION ?= $(shell uname -r)
|
||||||
|
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||||
|
MODULE_SRC := $(shell pwd)/modules
|
||||||
|
SCRIPT_SRC := $(shell pwd)/scripts
|
||||||
|
SERVICE_SRC := $(shell pwd)/service
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
|
|
||||||
|
override_dh_auto_build:
|
||||||
|
make -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
|
||||||
|
|
||||||
|
override_dh_auto_install:
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) $(KERNEL_SRC)/$(INSTALL_MOD_DIR)
|
||||||
|
cp $(MODULE_SRC)/*.ko debian/$(PACKAGE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR)
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) usr/local/bin
|
||||||
|
cp -r $(SCRIPT_SRC)/* debian/$(PACKAGE_NAME)/usr/local/bin
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) /etc/systemd/system
|
||||||
|
cp -r $(SERVICE_SRC)/* debian/$(PACKAGE_NAME)/etc/systemd/system
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) /etc/systemd/system/multi-user.target.wants
|
||||||
|
ln -s ../device_node.service debian/$(PACKAGE_NAME)/etc/systemd/system/multi-user.target.wants/device_node.service
|
||||||
|
ln -s ../driver_load.service debian/$(PACKAGE_NAME)/etc/systemd/system/multi-user.target.wants/driver_load.service
|
||||||
|
|
||||||
|
override_dh_usrlocal:
|
||||||
|
|
||||||
|
override_dh_pysupport:
|
||||||
|
|
||||||
|
override_dh_clean:
|
||||||
|
dh_clean
|
||||||
|
rm -f $(MODULE_SRC)/*.o $(MODULE_SRC)/*.ko $(MODULE_SRC)/*.mod.c $(MODULE_SRC)/.*.cmd
|
||||||
|
rm -f $(MODULE_SRC)/Module.markers $(MODULE_SRC)/Module.symvers $(MODULE_SRC)/modules.order
|
||||||
|
rm -rf $(MODULE_SRC)/.tmp_versions
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
obj-m := bf_kdrv.o
|
||||||
|
obj-m += bf_tun.o
|
||||||
|
obj-m += i2c-mcp2221.o
|
||||||
|
obj-m += wnc_cpld.o
|
||||||
|
obj-m += wnc_cpld3.o
|
||||||
|
obj-m += wnc_eeprom.o
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,611 @@
|
|||||||
|
/*
|
||||||
|
* i2c bus driver for MCP2221
|
||||||
|
*
|
||||||
|
* Derived from:
|
||||||
|
* i2c-tiny-usb.c
|
||||||
|
* i2c-diolan-u2c.c
|
||||||
|
* usb-serial.c
|
||||||
|
* onetouch.c
|
||||||
|
* usb-skeleton.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* Author: Bogdan Bolocan http://www.microchip.com/support
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#define DRIVER_NAME "i2c-mcp2221"
|
||||||
|
|
||||||
|
#define USB_VENDOR_ID_MCP2221 0x04d8
|
||||||
|
#define USB_DEVICE_ID_MCP2221 0x00dd
|
||||||
|
|
||||||
|
#define MCP2221_OUTBUF_LEN 64 /* USB write packet length */
|
||||||
|
#define MCP2221_INBUF_LEN 64 /* USB read packet length */
|
||||||
|
|
||||||
|
#define MCP2221_MAX_I2C_DATA_LEN 60
|
||||||
|
|
||||||
|
//#define MCP2221_FREQ_STD 100000
|
||||||
|
#define MCP2221_FREQ_STD 400000
|
||||||
|
//#define MCP2221_FREQ_STD 50000
|
||||||
|
#define MCP2221_FREQ_MAX 500000
|
||||||
|
|
||||||
|
#define MCP2221_RETRY_MAX 50
|
||||||
|
#define MCP2221_STD_DELAY_MS 1
|
||||||
|
//#define MCP2221_STD_DELAY_MS 2
|
||||||
|
|
||||||
|
#define RESP_ERR_NOERR 0x00
|
||||||
|
#define RESP_ADDR_NACK 0x25
|
||||||
|
#define RESP_READ_ERR 0x7F
|
||||||
|
#define RESP_READ_COMPL 0x55
|
||||||
|
#define RESP_I2C_IDLE 0x00
|
||||||
|
#define RESP_I2C_START_TOUT 0x12
|
||||||
|
#define RESP_I2C_RSTART_TOUT 0x17
|
||||||
|
#define RESP_I2C_WRADDRL_TOUT 0x23
|
||||||
|
#define RESP_I2C_WRADDRL_WSEND 0x21
|
||||||
|
#define RESP_I2C_WRADDRL_NACK 0x25
|
||||||
|
#define RESP_I2C_WRDATA_TOUT 0x44
|
||||||
|
#define RESP_I2C_RDDATA_TOUT 0x52
|
||||||
|
#define RESP_I2C_STOP_TOUT 0x62
|
||||||
|
|
||||||
|
#define CMD_MCP2221_STATUS 0x10
|
||||||
|
#define SUBCMD_STATUS_CANCEL 0x10
|
||||||
|
#define SUBCMD_STATUS_SPEED 0x20
|
||||||
|
#define MASK_ADDR_NACK 0x40
|
||||||
|
|
||||||
|
#define CMD_MCP2221_RDDATA7 0x91
|
||||||
|
#define CMD_MCP2221_GET_RDDATA 0x40
|
||||||
|
|
||||||
|
#define CMD_MCP2221_WRDATA7 0x90
|
||||||
|
|
||||||
|
/* Structure to hold all of our device specific stuff */
|
||||||
|
struct i2c_mcp2221 {
|
||||||
|
u8 obuffer[MCP2221_OUTBUF_LEN]; /* USB write buffer */
|
||||||
|
u8 ibuffer[MCP2221_INBUF_LEN]; /* USB read buffer */
|
||||||
|
/* I2C/SMBus data buffer */
|
||||||
|
u8 user_data_buffer[MCP2221_MAX_I2C_DATA_LEN];
|
||||||
|
int ep_in, ep_out; /* Endpoints */
|
||||||
|
struct usb_device *usb_dev; /* the usb device for this device */
|
||||||
|
struct usb_interface *interface;/* the interface for this device */
|
||||||
|
struct i2c_adapter adapter; /* i2c related things */
|
||||||
|
uint frequency; /* I2C/SMBus communication frequency */
|
||||||
|
/* Mutex for low-level USB transactions */
|
||||||
|
struct mutex mcp2221_usb_op_lock;
|
||||||
|
/* wq to wait for an ongoing read/write */
|
||||||
|
wait_queue_head_t usb_urb_completion_wait;
|
||||||
|
bool ongoing_usb_ll_op; /* a ll is in progress */
|
||||||
|
|
||||||
|
struct urb *interrupt_in_urb;
|
||||||
|
struct urb *interrupt_out_urb;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint frequency = MCP2221_FREQ_STD; /* I2C clock frequency in Hz */
|
||||||
|
|
||||||
|
module_param(frequency, uint, S_IRUGO | S_IWUSR);
|
||||||
|
MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
|
||||||
|
|
||||||
|
/* usb layer */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return list of supported functionality.
|
||||||
|
*/
|
||||||
|
static u32 mcp2221_usb_func(struct i2c_adapter *a)
|
||||||
|
{
|
||||||
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
|
||||||
|
I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcp2221_usb_cmpl_cbk(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct i2c_mcp2221 *dev = urb->context;
|
||||||
|
int status = urb->status;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0: /* success */
|
||||||
|
break;
|
||||||
|
case -ECONNRESET: /* unlink */
|
||||||
|
case -ENOENT:
|
||||||
|
case -ESHUTDOWN:
|
||||||
|
return;
|
||||||
|
/* -EPIPE: should clear the halt */
|
||||||
|
default: /* error */
|
||||||
|
goto resubmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wake up the waitting function
|
||||||
|
modify the flag indicating the ll status */
|
||||||
|
dev->ongoing_usb_ll_op = 0;
|
||||||
|
wake_up_interruptible(&dev->usb_urb_completion_wait);
|
||||||
|
return;
|
||||||
|
|
||||||
|
resubmit:
|
||||||
|
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
|
if (retval) {
|
||||||
|
dev_err(&dev->interface->dev,
|
||||||
|
"mcp2221(irq): can't resubmit intrerrupt urb, retval %d\n",
|
||||||
|
retval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp2221_ll_cmd(struct i2c_mcp2221 *dev)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* tell everybody to leave the URB alone */
|
||||||
|
dev->ongoing_usb_ll_op = 1;
|
||||||
|
|
||||||
|
/* submit the interrupt out ep packet */
|
||||||
|
if (usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL)) {
|
||||||
|
dev_err(&dev->interface->dev,
|
||||||
|
"mcp2221(ll): usb_submit_urb intr out failed\n");
|
||||||
|
dev->ongoing_usb_ll_op = 0;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for its completion */
|
||||||
|
rv = wait_event_interruptible(dev->usb_urb_completion_wait,
|
||||||
|
(!dev->ongoing_usb_ll_op));
|
||||||
|
if (rv < 0) {
|
||||||
|
dev_err(&dev->interface->dev, "mcp2221(ll): wait interrupted\n");
|
||||||
|
goto ll_exit_clear_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tell everybody to leave the URB alone */
|
||||||
|
dev->ongoing_usb_ll_op = 1;
|
||||||
|
|
||||||
|
/* submit the interrupt in ep packet */
|
||||||
|
if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL)) {
|
||||||
|
dev_err(&dev->interface->dev, "mcp2221(ll): usb_submit_urb intr in failed\n");
|
||||||
|
dev->ongoing_usb_ll_op = 0;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for its completion */
|
||||||
|
rv = wait_event_interruptible(dev->usb_urb_completion_wait,
|
||||||
|
(!dev->ongoing_usb_ll_op));
|
||||||
|
if (rv < 0) {
|
||||||
|
dev_err(&dev->interface->dev, "mcp2221(ll): wait interrupted\n");
|
||||||
|
goto ll_exit_clear_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
ll_exit_clear_flag:
|
||||||
|
dev->ongoing_usb_ll_op = 0;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp2221_init(struct i2c_mcp2221 *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
if (frequency > MCP2221_FREQ_MAX)
|
||||||
|
frequency = MCP2221_FREQ_MAX;
|
||||||
|
|
||||||
|
/* initialize the MCP2221 and bring it to "idle/ready" state */
|
||||||
|
dev_info(&dev->interface->dev,
|
||||||
|
"MCP2221 at USB bus %03d address %03d Freq=%dKhz-- mcp2221_init()\n",
|
||||||
|
dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency/1000);
|
||||||
|
|
||||||
|
/* initialize unlocked mutex */
|
||||||
|
mutex_init(&dev->mcp2221_usb_op_lock);
|
||||||
|
|
||||||
|
dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!dev->interrupt_out_urb)
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
usb_fill_int_urb(dev->interrupt_out_urb, dev->usb_dev,
|
||||||
|
usb_sndintpipe(dev->usb_dev,
|
||||||
|
dev->ep_out),
|
||||||
|
(void *)&dev->obuffer, MCP2221_OUTBUF_LEN,
|
||||||
|
mcp2221_usb_cmpl_cbk, dev,
|
||||||
|
1);
|
||||||
|
|
||||||
|
dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!dev->interrupt_in_urb)
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
usb_fill_int_urb(dev->interrupt_in_urb, dev->usb_dev,
|
||||||
|
usb_rcvintpipe(dev->usb_dev,
|
||||||
|
dev->ep_in),
|
||||||
|
(void *)&dev->ibuffer, MCP2221_INBUF_LEN,
|
||||||
|
mcp2221_usb_cmpl_cbk, dev,
|
||||||
|
1);
|
||||||
|
ret = 0;
|
||||||
|
goto init_no_error;
|
||||||
|
|
||||||
|
init_error:
|
||||||
|
dev_err(&dev->interface->dev, "mcp2221_init: Error = %d\n", ret);
|
||||||
|
ret = -ENODEV;
|
||||||
|
|
||||||
|
init_no_error:
|
||||||
|
dev_info(&dev->interface->dev, "mcp2221_init: Success\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp2221_i2c_readwrite(struct i2c_mcp2221 *dev,
|
||||||
|
struct i2c_msg *pmsg)
|
||||||
|
{
|
||||||
|
u8 ucI2cDiv, ucCancelXfer, ucXferLen;
|
||||||
|
int rv, retries;
|
||||||
|
unsigned int sleepCmd;
|
||||||
|
u8 *pSrc, *pDst, usbCmdStatus;
|
||||||
|
|
||||||
|
retries = 0;
|
||||||
|
ucCancelXfer = 0;
|
||||||
|
/* clock divider for I2C operations */
|
||||||
|
ucI2cDiv = (u8)((12000000/frequency) - 3);
|
||||||
|
|
||||||
|
/* determine the best delay value here */
|
||||||
|
/* (MCP2221_STD_DELAY_MS * MCP2221_FREQ_MAX)/frequency; */
|
||||||
|
sleepCmd = MCP2221_STD_DELAY_MS;
|
||||||
|
|
||||||
|
if (pmsg->len > MCP2221_MAX_I2C_DATA_LEN)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
readwrite_reinit:
|
||||||
|
dev->obuffer[0] = CMD_MCP2221_STATUS; /* code for STATUS cmd */
|
||||||
|
dev->obuffer[1] = 0x00;
|
||||||
|
dev->obuffer[2] = ucCancelXfer; /* cancel subcmd */
|
||||||
|
dev->obuffer[3] = SUBCMD_STATUS_SPEED; /* set the xfer speed */
|
||||||
|
dev->obuffer[4] = ucI2cDiv;
|
||||||
|
dev->obuffer[5] = 0x00;
|
||||||
|
dev->obuffer[6] = 0x00;
|
||||||
|
dev->obuffer[7] = 0x00;
|
||||||
|
|
||||||
|
rv = mcp2221_ll_cmd(dev);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[1] != RESP_ERR_NOERR)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[3] != SUBCMD_STATUS_SPEED) {
|
||||||
|
/* the speed could not be set - wait a while and retry */
|
||||||
|
if (retries < MCP2221_RETRY_MAX) {
|
||||||
|
/* wait a while and retry the operation */
|
||||||
|
retries++;
|
||||||
|
msleep(MCP2221_STD_DELAY_MS);
|
||||||
|
ucCancelXfer = SUBCMD_STATUS_CANCEL;
|
||||||
|
goto readwrite_reinit;
|
||||||
|
} else {
|
||||||
|
/* max number of retries was reached - return error */
|
||||||
|
dev_err(&dev->interface->dev,
|
||||||
|
"mcp2221 CANCEL ERROR:retries = %d\n", retries);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pmsg->flags & I2C_M_RD) {
|
||||||
|
/* I2C read */
|
||||||
|
ucXferLen = (u8)pmsg->len;
|
||||||
|
dev->obuffer[0] = CMD_MCP2221_RDDATA7;
|
||||||
|
dev->obuffer[1] = ucXferLen; /* LSB of the xfer length */
|
||||||
|
dev->obuffer[2] = 0; /* no MSB for the xfer length */
|
||||||
|
/* address in 8-bit format */
|
||||||
|
dev->obuffer[3] = (u8)((pmsg->addr) << 1);
|
||||||
|
|
||||||
|
rv = mcp2221_ll_cmd(dev);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[1] != RESP_ERR_NOERR)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
retries = 0;
|
||||||
|
dev->obuffer[0] = CMD_MCP2221_GET_RDDATA;
|
||||||
|
dev->obuffer[1] = 0x00;
|
||||||
|
dev->obuffer[2] = 0x00;
|
||||||
|
dev->obuffer[3] = 0x00;
|
||||||
|
|
||||||
|
while (retries < MCP2221_RETRY_MAX) {
|
||||||
|
msleep(sleepCmd);
|
||||||
|
|
||||||
|
rv = mcp2221_ll_cmd(dev);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[1] != RESP_ERR_NOERR)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[2] == RESP_ADDR_NACK)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* break the loop - cmd ended ok - used for bus scan */
|
||||||
|
if ((dev->ibuffer[3] == 0x00) &&
|
||||||
|
(dev->ibuffer[2] == 0x00))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (dev->ibuffer[3] == RESP_READ_ERR) {
|
||||||
|
retries++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dev->ibuffer[2] == RESP_READ_COMPL) &&
|
||||||
|
(dev->ibuffer[3] == ucXferLen)) {
|
||||||
|
/* we got the data - copy it */
|
||||||
|
pSrc = (u8 *)&dev->ibuffer[4];
|
||||||
|
pDst = (u8 *)&pmsg->buf[0];
|
||||||
|
memcpy(pDst, pSrc, ucXferLen);
|
||||||
|
|
||||||
|
if (pmsg->flags & I2C_M_RECV_LEN)
|
||||||
|
pmsg->len = ucXferLen;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (retries >= MCP2221_RETRY_MAX)
|
||||||
|
return -EFAULT;
|
||||||
|
} else {
|
||||||
|
/* I2C write */
|
||||||
|
ucXferLen = (u8)pmsg->len;
|
||||||
|
dev->obuffer[0] = CMD_MCP2221_WRDATA7;
|
||||||
|
dev->obuffer[1] = ucXferLen; /* LSB of the xfer length */
|
||||||
|
dev->obuffer[2] = 0; /* no MSB for the xfer length */
|
||||||
|
/* address in 8-bit format */
|
||||||
|
dev->obuffer[3] = (u8)((pmsg->addr) << 1);
|
||||||
|
/* copy the data we've read back */
|
||||||
|
pSrc = (u8 *)&pmsg->buf[0];
|
||||||
|
pDst = (u8 *)&dev->obuffer[4];
|
||||||
|
memcpy(pDst, pSrc, ucXferLen);
|
||||||
|
|
||||||
|
retries = 0;
|
||||||
|
|
||||||
|
while (retries < MCP2221_RETRY_MAX) {
|
||||||
|
rv = mcp2221_ll_cmd(dev);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[1] != RESP_ERR_NOERR) {
|
||||||
|
usbCmdStatus = dev->ibuffer[2];
|
||||||
|
if (usbCmdStatus == RESP_I2C_START_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRADDRL_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRADDRL_NACK)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRDATA_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_STOP_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
msleep(sleepCmd);
|
||||||
|
retries++;
|
||||||
|
continue;
|
||||||
|
} else { /* command completed successfully */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (retries >= MCP2221_RETRY_MAX)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* now, prepare for the STATUS stage */
|
||||||
|
retries = 0;
|
||||||
|
dev->obuffer[0] = CMD_MCP2221_STATUS; /* code for STATUS cmd */
|
||||||
|
dev->obuffer[1] = 0x00;
|
||||||
|
dev->obuffer[2] = 0x00;
|
||||||
|
dev->obuffer[3] = 0x00;
|
||||||
|
dev->obuffer[4] = 0x00;
|
||||||
|
dev->obuffer[5] = 0x00;
|
||||||
|
dev->obuffer[6] = 0x00;
|
||||||
|
dev->obuffer[7] = 0x00;
|
||||||
|
|
||||||
|
while (retries < MCP2221_RETRY_MAX) {
|
||||||
|
rv = mcp2221_ll_cmd(dev);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (dev->ibuffer[1] != RESP_ERR_NOERR)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* i2c slave address was nack-ed */
|
||||||
|
if (dev->ibuffer[20] & MASK_ADDR_NACK)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
usbCmdStatus = dev->ibuffer[8];
|
||||||
|
if (usbCmdStatus == RESP_I2C_IDLE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_START_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRADDRL_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRADDRL_WSEND)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRADDRL_NACK)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_WRDATA_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (usbCmdStatus == RESP_I2C_STOP_TOUT)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
msleep(sleepCmd);
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
if (retries >= MCP2221_RETRY_MAX)
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* device layer */
|
||||||
|
static int mcp2221_usb_i2c_xfer(struct i2c_adapter *adap,
|
||||||
|
struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
struct i2c_mcp2221 *dev = i2c_get_adapdata(adap);
|
||||||
|
struct i2c_msg *pmsg;
|
||||||
|
int ret, count;
|
||||||
|
|
||||||
|
for (count = 0; count < num; count++) {
|
||||||
|
pmsg = &msgs[count];
|
||||||
|
/* no concurrent users of the mcp2221 i2c xfer */
|
||||||
|
ret = mutex_lock_interruptible(&dev->mcp2221_usb_op_lock);
|
||||||
|
if (ret < 0)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
|
ret = mcp2221_i2c_readwrite(dev, pmsg);
|
||||||
|
mutex_unlock(&dev->mcp2221_usb_op_lock);
|
||||||
|
if (ret < 0)
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if all the messages were transferred ok, return "num" */
|
||||||
|
ret = num;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_algorithm mcp2221_usb_algorithm = {
|
||||||
|
.master_xfer = mcp2221_usb_i2c_xfer,
|
||||||
|
.functionality = mcp2221_usb_func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_device_id mcp2221_table[] = {
|
||||||
|
{ USB_DEVICE(USB_VENDOR_ID_MCP2221, USB_DEVICE_ID_MCP2221) },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(usb, mcp2221_table);
|
||||||
|
|
||||||
|
static void mcp2221_free(struct i2c_mcp2221 *dev)
|
||||||
|
{
|
||||||
|
usb_put_dev(dev->usb_dev);
|
||||||
|
kfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp2221_probe(struct usb_interface *interface,
|
||||||
|
const struct usb_device_id *id)
|
||||||
|
{
|
||||||
|
struct usb_host_interface *hostif = interface->cur_altsetting;
|
||||||
|
struct i2c_mcp2221 *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((hostif->desc.bInterfaceNumber != 2)
|
||||||
|
|| (hostif->desc.bInterfaceClass != 3)) {
|
||||||
|
pr_info("i2c-mcp2221(probe): Interface doesn't match the MCP2221 HID\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory for our device state and initialize it */
|
||||||
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||||
|
if (dev == NULL) {
|
||||||
|
pr_info("i2c-mcp2221(probe): no memory for device state\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->ep_in = hostif->endpoint[0].desc.bEndpointAddress;
|
||||||
|
dev->ep_out = hostif->endpoint[1].desc.bEndpointAddress;
|
||||||
|
|
||||||
|
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||||
|
dev->interface = interface;
|
||||||
|
|
||||||
|
init_waitqueue_head(&dev->usb_urb_completion_wait);
|
||||||
|
|
||||||
|
/* save our data pointer in this interface device */
|
||||||
|
usb_set_intfdata(interface, dev);
|
||||||
|
|
||||||
|
/* setup i2c adapter description */
|
||||||
|
dev->adapter.owner = THIS_MODULE;
|
||||||
|
dev->adapter.class = I2C_CLASS_HWMON;
|
||||||
|
dev->adapter.algo = &mcp2221_usb_algorithm;
|
||||||
|
i2c_set_adapdata(&dev->adapter, dev);
|
||||||
|
|
||||||
|
snprintf(dev->adapter.name, sizeof(dev->adapter.name),
|
||||||
|
DRIVER_NAME " at bus %03d device %03d",
|
||||||
|
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
|
||||||
|
|
||||||
|
dev->adapter.dev.parent = &dev->interface->dev;
|
||||||
|
|
||||||
|
/* initialize mcp2221 i2c interface */
|
||||||
|
ret = mcp2221_init(dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&interface->dev, "failed to initialize adapter\n");
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* and finally attach to i2c layer */
|
||||||
|
ret = i2c_add_adapter(&dev->adapter);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&interface->dev, "failed to add I2C adapter\n");
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&dev->interface->dev,
|
||||||
|
"mcp2221_probe() -> chip connected -> Success\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_free:
|
||||||
|
usb_set_intfdata(interface, NULL);
|
||||||
|
mcp2221_free(dev);
|
||||||
|
error:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcp2221_disconnect(struct usb_interface *interface)
|
||||||
|
{
|
||||||
|
struct i2c_mcp2221 *dev = usb_get_intfdata(interface);
|
||||||
|
|
||||||
|
i2c_del_adapter(&dev->adapter);
|
||||||
|
|
||||||
|
usb_kill_urb(dev->interrupt_in_urb);
|
||||||
|
usb_kill_urb(dev->interrupt_out_urb);
|
||||||
|
usb_free_urb(dev->interrupt_in_urb);
|
||||||
|
usb_free_urb(dev->interrupt_out_urb);
|
||||||
|
|
||||||
|
usb_set_intfdata(interface, NULL);
|
||||||
|
mcp2221_free(dev);
|
||||||
|
|
||||||
|
pr_info("i2c-mcp2221(disconnect) -> chip disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_driver mcp2221_driver = {
|
||||||
|
.name = DRIVER_NAME,
|
||||||
|
.probe = mcp2221_probe,
|
||||||
|
.disconnect = mcp2221_disconnect,
|
||||||
|
.id_table = mcp2221_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_usb_driver(mcp2221_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Bogdan Bolocan");
|
||||||
|
MODULE_DESCRIPTION(DRIVER_NAME "I2C MCP2221");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* wnc_cpld.c - A driver for control wnc_cpld base on lm75.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||||
|
* Copyright (c) 2017 WNC <wnc@wnc.com.tw>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.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>
|
||||||
|
|
||||||
|
/* Addresses scanned */
|
||||||
|
static const unsigned short normal_i2c[] = { 0x31, 0x32, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
/* Size of EEPROM in bytes */
|
||||||
|
#define CPLD_SIZE 3
|
||||||
|
|
||||||
|
/* Each client has this additional data */
|
||||||
|
struct cpld_data {
|
||||||
|
struct mutex update_lock;
|
||||||
|
char valid; /* !=0 if registers are valid */
|
||||||
|
unsigned long last_updated; /* In jiffies */
|
||||||
|
u8 data[CPLD_SIZE]; /* Register value */
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_value(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 cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->data[0] = i2c_smbus_read_byte_data(client, attr->index);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "%02x\n", data->data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_value(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 cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 temp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = kstrtou8(buf, 10, &temp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
i2c_smbus_write_byte_data(client, attr->index, temp);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(reset_control, S_IWUSR | S_IRUGO, show_value, set_value, 2);
|
||||||
|
static SENSOR_DEVICE_ATTR(sfp_mod_abs1, S_IRUGO, show_value, NULL, 3);
|
||||||
|
static SENSOR_DEVICE_ATTR(sfp_mod_abs2, S_IRUGO, show_value, NULL, 4);
|
||||||
|
static SENSOR_DEVICE_ATTR(sfp_mod_abs3, S_IRUGO, show_value, NULL, 5);
|
||||||
|
static SENSOR_DEVICE_ATTR(sfp_mod_abs4, S_IRUGO, show_value, NULL, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(qsfp_modprs, S_IRUGO, show_value, NULL, 22);
|
||||||
|
static SENSOR_DEVICE_ATTR(qsfp_lpmode, S_IWUSR | S_IRUGO, show_value, set_value, 24);
|
||||||
|
|
||||||
|
static struct attribute *cpld2_attributes[] = {
|
||||||
|
&sensor_dev_attr_reset_control.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs1.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs2.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs3.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_qsfp_modprs.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_qsfp_lpmode.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *cpld1_attributes[] = {
|
||||||
|
&sensor_dev_attr_sfp_mod_abs1.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs2.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs3.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_sfp_mod_abs4.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group cpld2_group = {
|
||||||
|
.attrs = cpld2_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group cpld1_group = {
|
||||||
|
.attrs = cpld1_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int cpld_detect(struct i2c_client *new_client, struct i2c_board_info *info)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
|
int conf;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
|
I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Unused bits */
|
||||||
|
conf = i2c_smbus_read_byte_data(new_client, 0);
|
||||||
|
if (!conf)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cpld_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct cpld_data *data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
|
return -EIO;
|
||||||
|
#if 1
|
||||||
|
data = devm_kzalloc(&client->dev, sizeof(struct cpld_data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (client->addr == 49) /* 0x31 */
|
||||||
|
/* Register sysfs hooks */
|
||||||
|
status = sysfs_create_group(&client->dev.kobj, &cpld1_group);
|
||||||
|
else if (client->addr == 50) /* 0x32 */
|
||||||
|
/* Register sysfs hooks */
|
||||||
|
status = sysfs_create_group(&client->dev.kobj, &cpld2_group);
|
||||||
|
else
|
||||||
|
status = 1;
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
dev_info(&client->dev, "cpld 0x%x found\n", client->addr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cpld_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
if (client->addr == 49) /* 0x31 */
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &cpld1_group);
|
||||||
|
else if (client->addr == 50) /* 0x32 */
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &cpld2_group);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id cpld_id[] = {
|
||||||
|
{ "wnc_cpld", 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, cpld_id);
|
||||||
|
|
||||||
|
static struct i2c_driver cpld_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
|
.driver = {
|
||||||
|
.name = "wnc_cpld",
|
||||||
|
},
|
||||||
|
.probe = cpld_probe,
|
||||||
|
.remove = cpld_remove,
|
||||||
|
.id_table = cpld_id,
|
||||||
|
.detect = cpld_detect,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(cpld_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("WNC <wnc@wnc.com.tw>");
|
||||||
|
MODULE_DESCRIPTION("WNC CPLD driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* wnc_cpld.c - A driver for control wnc_cpld3 base on lm75.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||||
|
* Copyright (c) 2017 WNC <wnc@wnc.com.tw>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.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>
|
||||||
|
|
||||||
|
/* Addresses scanned */
|
||||||
|
static const unsigned short normal_i2c[] = { 0x33, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
/* Size of EEPROM in bytes */
|
||||||
|
#define CPLD_SIZE 3
|
||||||
|
|
||||||
|
/* Each client has this additional data */
|
||||||
|
struct cpld_data {
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct mutex update_lock;
|
||||||
|
char valid; /* !=0 if registers are valid */
|
||||||
|
unsigned long last_updated; /* In jiffies */
|
||||||
|
u8 data[CPLD_SIZE]; /* Register value */
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_hwmon_value(struct device *dev, struct device_attribute *da, char *buf)
|
||||||
|
{
|
||||||
|
struct cpld_data *data = dev_get_drvdata(dev);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
int index = to_sensor_dev_attr_2(da)->index;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->data[0] = i2c_smbus_read_byte_data(client, index);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", data->data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_sysfs_value(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 cpld_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->data[0] = i2c_smbus_read_byte_data(client, attr->index);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return sprintf(buf, "%02x\n", data->data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_hwmon_value(struct device *dev, struct device_attribute *da, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct cpld_data *data = dev_get_drvdata(dev);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
int index = to_sensor_dev_attr_2(da)->index;
|
||||||
|
u8 temp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = kstrtou8(buf, 10, &temp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
i2c_smbus_write_byte_data(client, index, temp);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_hwmon_value, NULL, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_hwmon_value, NULL, 7);
|
||||||
|
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_hwmon_value, NULL, 8);
|
||||||
|
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_hwmon_value, NULL, 9);
|
||||||
|
static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_hwmon_value, NULL, 10);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_hwmon_value, set_hwmon_value, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_hwmon_value, set_hwmon_value, 7);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_hwmon_value, set_hwmon_value, 8);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_hwmon_value, set_hwmon_value, 9);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, show_hwmon_value, set_hwmon_value, 10);
|
||||||
|
|
||||||
|
static struct attribute *cpld3_hwmon_attrs[] = {
|
||||||
|
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm4.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm5.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
ATTRIBUTE_GROUPS(cpld3_hwmon);
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(cpld_version, S_IRUGO, show_sysfs_value, NULL, 1);
|
||||||
|
static SENSOR_DEVICE_ATTR(power_good, S_IRUGO, show_sysfs_value, NULL, 4);
|
||||||
|
|
||||||
|
static struct attribute *cpld3_sysfs_attrs[] = {
|
||||||
|
&sensor_dev_attr_cpld_version.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_power_good.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group cpld3_sysfs_group = {
|
||||||
|
.attrs = cpld3_sysfs_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int cpld_detect(struct i2c_client *new_client, struct i2c_board_info *info)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
|
int conf;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
|
I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Unused bits */
|
||||||
|
conf = i2c_smbus_read_byte_data(new_client, 0);
|
||||||
|
if (!conf)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cpld_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct cpld_data *data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
data = devm_kzalloc(&client->dev, sizeof(struct cpld_data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data->client = client;
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
|
status = sysfs_create_group(&client->dev.kobj, &cpld3_sysfs_group);
|
||||||
|
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, client->name, data, cpld3_hwmon_groups);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cpld_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
devm_hwmon_device_unregister(&client->dev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &cpld3_sysfs_group);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id cpld_id[] = {
|
||||||
|
{ "wnc_cpld3", 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, cpld_id);
|
||||||
|
|
||||||
|
static struct i2c_driver cpld_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
|
.driver = {
|
||||||
|
.name = "wnc_cpld3",
|
||||||
|
},
|
||||||
|
.probe = cpld_probe,
|
||||||
|
.remove = cpld_remove,
|
||||||
|
.id_table = cpld_id,
|
||||||
|
.detect = cpld_detect,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(cpld_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("WNC <wnc@wnc.com.tw>");
|
||||||
|
MODULE_DESCRIPTION("WNC CPLD3 driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||||
|
* Philip Edelbrock <phil@netroedge.com>
|
||||||
|
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
|
||||||
|
* Copyright (C) 2003 IBM Corp.
|
||||||
|
* Copyright (C) 2004 Jean Delvare <jdelvare@suse.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
|
/* Addresses to scan */
|
||||||
|
static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
|
||||||
|
0x55, 0x56, 0x57, I2C_CLIENT_END };
|
||||||
|
|
||||||
|
|
||||||
|
/* Size of EEPROM in bytes */
|
||||||
|
#define EEPROM_SIZE 256
|
||||||
|
|
||||||
|
/* possible types of eeprom devices */
|
||||||
|
enum eeprom_nature {
|
||||||
|
UNKNOWN,
|
||||||
|
VAIO,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Each client has this additional data */
|
||||||
|
struct eeprom_data {
|
||||||
|
struct mutex update_lock;
|
||||||
|
u8 valid; /* bitfield, bit!=0 if slice is valid */
|
||||||
|
unsigned long last_updated[8]; /* In jiffies, 8 slices */
|
||||||
|
u8 data[EEPROM_SIZE]; /* Register values */
|
||||||
|
enum eeprom_nature nature;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void eeprom_update_client(struct i2c_client *client, u8 slice)
|
||||||
|
{
|
||||||
|
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
|
if (!(data->valid & (1 << slice)) ||
|
||||||
|
time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
|
||||||
|
dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
|
||||||
|
|
||||||
|
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||||
|
//for (i = slice << 5; i < (slice + 1) << 5; i += 32)
|
||||||
|
for (i = slice << 5; i < (slice + 1) << 5; i += 24)
|
||||||
|
if (i2c_smbus_read_i2c_block_data(client, i,
|
||||||
|
24, data->data + i)
|
||||||
|
!= 24)
|
||||||
|
goto exit;
|
||||||
|
} else {
|
||||||
|
for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
|
||||||
|
int word = i2c_smbus_read_word_data(client, i);
|
||||||
|
if (word < 0)
|
||||||
|
goto exit;
|
||||||
|
data->data[i] = word & 0xff;
|
||||||
|
data->data[i + 1] = word >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data->last_updated[slice] = jiffies;
|
||||||
|
data->valid |= (1 << slice);
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr,
|
||||||
|
char *buf, loff_t off, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||||
|
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 slice;
|
||||||
|
|
||||||
|
data->valid = 0;
|
||||||
|
|
||||||
|
if (off > EEPROM_SIZE)
|
||||||
|
return 0;
|
||||||
|
if (off + count > EEPROM_SIZE)
|
||||||
|
count = EEPROM_SIZE - off;
|
||||||
|
|
||||||
|
/* Only refresh slices which contain requested bytes */
|
||||||
|
for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
|
||||||
|
eeprom_update_client(client, slice);
|
||||||
|
|
||||||
|
/* Hide Vaio private settings to regular users:
|
||||||
|
- BIOS passwords: bytes 0x00 to 0x0f
|
||||||
|
- UUID: bytes 0x10 to 0x1f
|
||||||
|
- Serial number: 0xc0 to 0xdf */
|
||||||
|
if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if ((off + i <= 0x1f) ||
|
||||||
|
(off + i >= 0xc0 && off + i <= 0xdf))
|
||||||
|
buf[i] = 0;
|
||||||
|
else
|
||||||
|
buf[i] = data->data[off + i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(buf, &data->data[off], count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr,
|
||||||
|
char *buf, loff_t off, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||||
|
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 temp;
|
||||||
|
int error, reg;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
|
error = kstrtou8(buf, 10, &temp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (client->addr == 0x51) { /* SFP AOC cable, page selection byte is 126 */
|
||||||
|
reg = 126;
|
||||||
|
}
|
||||||
|
else if (client->addr == 0x50) { /* QSFP, page selection byte is 127 */
|
||||||
|
data->data[0] = i2c_smbus_read_byte_data(client, 0);
|
||||||
|
|
||||||
|
/* Base on SFF-8024, determine this module is SFP or QSFP by byte 0 (Identifier) */
|
||||||
|
switch (data->data[0]){
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
case 17:
|
||||||
|
case 24:
|
||||||
|
reg = 127;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
i2c_smbus_write_byte_data(client, reg, temp);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bin_attribute eeprom_attr = {
|
||||||
|
.attr = {
|
||||||
|
.name = "eeprom",
|
||||||
|
.mode = S_IWUSR | S_IRUGO | S_IWGRP | S_IWOTH,
|
||||||
|
},
|
||||||
|
.size = EEPROM_SIZE,
|
||||||
|
.read = eeprom_read,
|
||||||
|
.write = eeprom_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
|
|
||||||
|
/* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
|
||||||
|
addresses 0x50-0x57, but we only care about 0x50. So decline
|
||||||
|
attaching to addresses >= 0x51 on DDC buses */
|
||||||
|
if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* There are four ways we can read the EEPROM data:
|
||||||
|
(1) I2C block reads (faster, but unsupported by most adapters)
|
||||||
|
(2) Word reads (128% overhead)
|
||||||
|
(3) Consecutive byte reads (88% overhead, unsafe)
|
||||||
|
(4) Regular byte data reads (265% overhead)
|
||||||
|
The third and fourth methods are not implemented by this driver
|
||||||
|
because all known adapters support one of the first two. */
|
||||||
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
|
||||||
|
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
strlcpy(info->type, "wnc_eeprom", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eeprom_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
|
struct eeprom_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(data->data, 0xff, EEPROM_SIZE);
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
data->nature = UNKNOWN;
|
||||||
|
|
||||||
|
/* Detect the Vaio nature of EEPROMs.
|
||||||
|
We use the "PCG-" or "VGN-" prefix as the signature. */
|
||||||
|
if (client->addr == 0x57
|
||||||
|
&& i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
||||||
|
char name[4];
|
||||||
|
|
||||||
|
name[0] = i2c_smbus_read_byte_data(client, 0x80);
|
||||||
|
name[1] = i2c_smbus_read_byte_data(client, 0x81);
|
||||||
|
name[2] = i2c_smbus_read_byte_data(client, 0x82);
|
||||||
|
name[3] = i2c_smbus_read_byte_data(client, 0x83);
|
||||||
|
|
||||||
|
if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
|
||||||
|
dev_info(&client->dev, "Vaio EEPROM detected, "
|
||||||
|
"enabling privacy protection\n");
|
||||||
|
data->nature = VAIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the sysfs eeprom file */
|
||||||
|
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||||
|
if (err)
|
||||||
|
goto exit_kfree;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_kfree:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eeprom_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||||
|
kfree(i2c_get_clientdata(client));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id eeprom_id[] = {
|
||||||
|
{ "wnc_eeprom", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver eeprom_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "wnc_eeprom",
|
||||||
|
},
|
||||||
|
.probe = eeprom_probe,
|
||||||
|
.remove = eeprom_remove,
|
||||||
|
.id_table = eeprom_id,
|
||||||
|
|
||||||
|
.class = I2C_CLASS_DDC | I2C_CLASS_SPD,
|
||||||
|
.detect = eeprom_detect,
|
||||||
|
.address_list = normal_i2c,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(eeprom_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||||
|
"Philip Edelbrock <phil@netroedge.com> and "
|
||||||
|
"Greg Kroah-Hartman <greg@kroah.com>");
|
||||||
|
MODULE_DESCRIPTION("I2C EEPROM driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
@ -0,0 +1,91 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SEARCH_I2C_BUS=$(ls /sys/bus/i2c/devices)
|
||||||
|
I2C_BUS=-1
|
||||||
|
|
||||||
|
for i in $SEARCH_I2C_BUS
|
||||||
|
do
|
||||||
|
if [[ -n $(cat /sys/bus/i2c/devices/$i/name | grep i2c-mcp2221) ]]; then
|
||||||
|
I2C_BUS=$(echo $i | sed 's/i2c-//g')
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $I2C_BUS == -1 ]]; then
|
||||||
|
echo "Can't find i2c-mcp2221"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOTAL_MUX=8
|
||||||
|
START_NODE_NUM=$((I2C_BUS+1))
|
||||||
|
|
||||||
|
modprobe i2c_mux_pca954x force_deselect_on_exit=1
|
||||||
|
|
||||||
|
echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-$I2C_BUS/new_device
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
/sbin/modprobe wnc_cpld
|
||||||
|
/sbin/modprobe wnc_cpld3
|
||||||
|
/sbin/modprobe wnc_eeprom
|
||||||
|
/sbin/modprobe eeprom
|
||||||
|
|
||||||
|
# MUX0: i2c-3~i2c-10
|
||||||
|
# MUX1: i2c-11~i2c-18
|
||||||
|
# MUX2: i2c-19~i2c-26
|
||||||
|
# MUX3: i2c-27~i2c-34
|
||||||
|
# MUX4: i2c-35~i2c-42
|
||||||
|
# MUX5: i2c-43~i2c-50
|
||||||
|
# MUX6: i2c-51~i2c-58
|
||||||
|
# MUX7: i2c-59~i2c-66
|
||||||
|
|
||||||
|
# MUX0 channel0
|
||||||
|
CHANNEL=0
|
||||||
|
echo wnc_cpld 0x31 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel1
|
||||||
|
CHANNEL=1
|
||||||
|
echo wnc_cpld 0x32 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel2
|
||||||
|
CHANNEL=2
|
||||||
|
echo wnc_cpld3 0x33 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
echo wnc_eeprom 0x53 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel3
|
||||||
|
CHANNEL=3
|
||||||
|
echo wnc_eeprom 0x50 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
echo wnc_eeprom 0x51 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel4
|
||||||
|
CHANNEL=4
|
||||||
|
echo wnc_eeprom 0x54 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
echo tmp421 0x1E > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
sleep 1
|
||||||
|
echo tmp75 0x4E > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
sleep 1
|
||||||
|
echo tmp421 0x4F > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel5
|
||||||
|
CHANNEL=5
|
||||||
|
echo wnc_eeprom 0x52 > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
# MUX0 channel7
|
||||||
|
CHANNEL=7
|
||||||
|
#echo wnc_eeprom 0x5B > /sys/bus/i2c/devices/i2c-$(($START_NODE_NUM+$CHANNEL))/new_device
|
||||||
|
|
||||||
|
START_PORT_NUM=$((START_NODE_NUM+8))
|
||||||
|
END_PORT_NUM=$((TOTAL_MUX*8+1))
|
||||||
|
|
||||||
|
for i in $(seq $START_PORT_NUM $END_PORT_NUM)
|
||||||
|
do
|
||||||
|
echo wnc_eeprom 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device
|
||||||
|
echo wnc_eeprom 0x51 > /sys/bus/i2c/devices/i2c-$i/new_device
|
||||||
|
done
|
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
vid=04d8
|
||||||
|
pid=00dd
|
||||||
|
|
||||||
|
#check to see if sysfs is mounted
|
||||||
|
sysfs_path=`awk '/^sysfs/{ print $2 }' < /proc/mounts`
|
||||||
|
curr_path=`pwd`
|
||||||
|
|
||||||
|
#if variable is empty, we should exit. No SYSFS found
|
||||||
|
if [[ -z $sysfs_path ]]; then
|
||||||
|
echo "No sysfs in this system! Exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function load_drivers
|
||||||
|
{
|
||||||
|
modprobe i2c-dev
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "Cannot load the \"i2c-dev\" driver! Exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
modprobe i2c-mcp2221
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "Cannot load the \"i2c-mcp2221\" driver! Exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "I2C related drivers are loaded"
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_device_path=${sysfs_path}/bus/usb/devices
|
||||||
|
|
||||||
|
cd $usb_device_path
|
||||||
|
|
||||||
|
for usbdev in *; do
|
||||||
|
idvendor=${usb_device_path}/${usbdev}/idVendor
|
||||||
|
idproduct=${usb_device_path}/${usbdev}/idProduct
|
||||||
|
usb_driver=${usb_device_path}/${usbdev}/${usbdev}:1.2/driver
|
||||||
|
if [[ -f $idvendor ]]; then
|
||||||
|
dev_vid=`grep -i $vid < $idvendor`
|
||||||
|
dev_pid=`grep -i $pid < $idproduct`
|
||||||
|
if [[ -n $dev_vid ]] && [[ -n $dev_pid ]]; then
|
||||||
|
echo "I found the requested VID/PID: $dev_vid, $dev_pid"
|
||||||
|
load_drivers
|
||||||
|
echo -n "${usbdev}:1.2" > ${usb_driver}/unbind
|
||||||
|
echo -n "${usbdev}:1.2" > ${sysfs_path}/bus/usb/drivers/i2c-mcp2221/bind
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
echo "test"
|
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Create device nodes for i2c devices.
|
||||||
|
Requires=driver_load.service
|
||||||
|
After=driver_load.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash /usr/local/bin/device_node.sh
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Initialize i2c-mcp2221 driver.
|
||||||
|
Before=pmon.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash /usr/local/bin/driver_load.sh
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Reference in New Issue
Block a user