Upload wnc-osw1800

This commit is contained in:
Brand 2018-01-26 16:44:02 +08:00
parent c47c409a3a
commit 8471499077
35 changed files with 7409 additions and 4 deletions

View File

@ -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

View File

@ -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
}
]
}

View 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

View File

@ -0,0 +1,3 @@
CONSOLE_PORT=0x2f8
CONSOLE_DEV=1
CONSOLE_SPEED=57600

File diff suppressed because it is too large Load Diff

View 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)

View 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

View 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

View 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"

View File

@ -1,5 +1,5 @@
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)
$(BFN_SAI_DEV)_DEPENDS += $(BFN_PLATFORM)

View File

@ -1,5 +1,5 @@
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"
SONIC_ONLINE_DEBS += $(BFN_SAI) # $(BFN_SAI_DEV)

View File

@ -3,7 +3,8 @@
SONIC_ONE_IMAGE = sonic-barefoot.bin
$(SONIC_ONE_IMAGE)_MACHINE = barefoot
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
#$(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_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_INSTALLERS += $(SONIC_ONE_IMAGE)

View 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)

View File

@ -1,5 +1,6 @@
include $(PLATFORM_PATH)/platform-modules-bfn.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)/docker-syncd-bfn.mk
include $(PLATFORM_PATH)/docker-syncd-bfn-rpc.mk

View 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.

View File

@ -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

View File

@ -0,0 +1,2 @@
# sonic-platform-modules-wnc-osw1800
Device drivers for support of BFN platform for the SONiC project

View File

@ -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

View File

@ -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

View File

@ -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.

View File

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

View 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

View File

@ -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

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
echo "test"

View File

@ -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

View File

@ -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