Skip to content

Commit

Permalink
Merge pull request #52 from linux-automation/cfi/FAST
Browse files Browse the repository at this point in the history
Add support for the USB-SD-Mux FAST
  • Loading branch information
SmithChart authored Nov 28, 2023
2 parents 5ac53b4 + 5aba0a7 commit 319a9a0
Show file tree
Hide file tree
Showing 6 changed files with 414 additions and 153 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ dist/
.tox/
envs/
.idea
venv/
51 changes: 36 additions & 15 deletions usbsdmux/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,26 @@
import errno
import sys

from .usbsdmux import UsbSdMux
from .usbsdmux import autoselect_driver, UnknownUsbSdMuxRevisionException


def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument("sg", metavar="SG", help="/dev/sg* to use")
parser.add_argument(
"mode",
help="Action:\n"
"get - return selected mode\n"
"dut - set to dut mode\n"
"client - set to dut mode (alias for dut)\n"
"host - set to host mode\n"
"off - set to off mode",
choices=["get", "dut", "client", "host", "off"],
type=str.lower,
)
subparsers = parser.add_subparsers(help="Supply one of the following commands to interact with the device")
subparsers.required = True
subparsers.dest = "mode"

subparsers.add_parser("get", help="Read the current state of the USB-SD-Mux")
subparsers.add_parser("dut", help="Switch to the DUT")
subparsers.add_parser("client", help="Switch to the DUT")
subparsers.add_parser("host", help="Switch to the host")
subparsers.add_parser("off", help="Disconnect from host and DUT")

parser_gpio = subparsers.add_parser("gpio", help="Manipulate a GPIO (open drain output only)")
parser_gpio.add_argument("gpio", help="The GPIO to change", choices=[0, 1], type=int)
parser_gpio.add_argument("action", help="What to do with the GPIO", choices=["low", "0", "high", "1", "get"])

# These arguments were previously used for the client/service
# based method to grant USB-SD-Mux access to non-root users.
Expand All @@ -61,8 +63,13 @@ def main():
file=sys.stderr,
)

ctl = UsbSdMux(args.sg)
mode = args.mode.lower()
try:
ctl = autoselect_driver(args.sg)
except UnknownUsbSdMuxRevisionException as e:
print(e, file=sys.stderr)
print(f"Does {args.sg} really point to an USB-SD-Mux?")
sys.exit(1)
mode = args.mode

try:
if mode == "off":
Expand All @@ -77,6 +84,14 @@ def main():
elif mode == "get":
print(ctl.get_mode())

elif mode == "gpio":
if args.action == "get":
print(ctl.gpio_get(args.gpio))
elif args.action in ["0", "low"]:
ctl.gpio_set_low(args.gpio)
elif args.action in ["1", "high"]:
ctl.gpio_set_high(args.gpio)

except FileNotFoundError as fnfe:
print(fnfe, file=sys.stderr)
sys.exit(1)
Expand All @@ -85,7 +100,7 @@ def main():
sys.exit(1)
except OSError as ose:
if ose.errno == errno.ENOTTY:
# ENOTTY is raised when an error occured when calling an ioctl
# ENOTTY is raised when an error occurred when calling an ioctl
print(ose, file=sys.stderr)
print(
f"Does '{args.sg}' really point to an USB-SD-Mux?",
Expand All @@ -94,6 +109,12 @@ def main():
sys.exit(1)
else:
raise ose
except NotImplementedError:
print(
"This USB-SD-Mux does not support GPIOs.",
file=sys.stderr,
)
sys.exit(1)


if __name__ == "__main__":
Expand Down
141 changes: 141 additions & 0 deletions usbsdmux/i2c_gpio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env python3

# SPDX-License-Identifier: LGPL-2.1-or-later

# Copyright (C) 2017 Pengutronix, Chris Fiege <entwicklung@pengutronix.de>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

from .usb2642i2c import Usb2642I2C
from abc import ABC


class I2cGpio(ABC):
# Registers inside the supported GPIO expanders
_register_inputPort = 0x00
_register_outputPort = 0x01
_register_polarity = 0x02
_register_configuration = 0x03

# Values for the configuration register
_direction_output = 0
_direction_input = 1

def __init__(self, sg):
"""
Arguments:
sg -- /dev/sg* to use.
"""
self._usb = Usb2642I2C(sg)

def _write_register(self, register, value):
"""
Writes a register on the GPIO-expander with a given value.
"""
self._usb.write_to(self._I2cAddr, [register, value])

def _read_register(self, addr):
"""
Returns a register of the GPIO-expander.
"""
return self._usb.write_read_to(self._I2cAddr, [addr], 1)[0]

def set_pin_to_output(self, pins):
"""
Sets the corresponding pins as outputs.
Arguments:
pins -- Combination of I2cGpio.gpio_*
"""
direction = self._read_register(self._register_configuration)
direction = (direction & ~pins) & 0xFF
self._write_register(self._register_configuration, direction)

def set_pin_to_input(self, pins):
"""
Sets the corresponding pins as inputs.
Arguments:
pins -- Combination of I2cGpio.gpio_*
"""
direction = self._read_register(self._register_configuration)
direction = direction | pins
self._write_register(self._register_configuration, direction)

def get_gpio_config(self):
"""
Returns the state of the configuration register.
"""
return self._read_register(self._register_configuration)

def get_input_values(self):
"""
Reads the value currently present on the port from the input register.
"""
return self._read_register(self._register_inputPort)

def output_values(self, values: int, bitmask: int = 0xFF):
"""
Writes the given values to the GPIO-expander.
Pins configured as Inputs are not affected by this.
Arguments:
values -- Combination of I2cGpio.gpio_*
bitmask -- Only update bits in the register that are '1' in the bitmask
"""

if bitmask == 0xFF:
# trivial case: Let's just write the value
self._write_register(self._register_outputPort, values)
else:
# complex case: Let's do a read-modify-write
val = self._read_register(self._register_outputPort)
val = (val & ~bitmask) & 0xFF # reset masked bits
val = val | (values & bitmask) # set bits set in values and bitmask
self._write_register(self._register_outputPort, val)


class Pca9536(I2cGpio):
"""
Interface to control a Pca9536 that is connected to the auxiliary-I2C of a
Microchip USB2642.
"""

# The PCA9536 I2C slave Address in 7-Bit Format
_I2cAddr = 0b100_0001

gpio_0 = 0x01
gpio_1 = 0x02
gpio_2 = 0x04
gpio_3 = 0x08


class Tca6408(I2cGpio):
"""
Interface to control a TCA6408 that is connected to the auxiliary-I2C of a
Microchip USB2642.
"""

# The TCA6408 I2C slave Address in 7-Bit Format
_I2cAddr = 0b010_0000

gpio_0 = 0x01
gpio_1 = 0x02
gpio_2 = 0x04
gpio_3 = 0x08
gpio_4 = 0x10
gpio_5 = 0x20
gpio_6 = 0x40
gpio_7 = 0x80
102 changes: 0 additions & 102 deletions usbsdmux/pca9536.py

This file was deleted.

2 changes: 1 addition & 1 deletion usbsdmux/usb2642i2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def _get_SCSI_cmd_I2C_write_read(self, slaveAddr, writeData, readLength):
I2cReadPhaseLenHigh=(readCount >> 8) & 0xFF,
I2cReadPhaseLenLow=readCount & 0xFF,
I2cWritePhaseLen=writeCount,
I2cCommandPayload=writeDataArray,
I2cWritePayload=writeDataArray,
)

return cmd, readDataArray
Expand Down
Loading

0 comments on commit 319a9a0

Please sign in to comment.