Commit 9f164683 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

initial commit

parents
obj-m = cp210x.o
KVERSION = $(shell uname -r)
all:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
# CP210x GPIO control
A patch to the CP210x USB to UART Bridges driver that adds GPIO pins control by implementing ioctl function and a python script to program devices.
## Supported OS
* Kubuntu Linux 13.04 (kernel 3.8.0-32)
## Tested devices
* CP2103
* CP2104
## Install
1. Build:
./build_driver
2. Reload driver (from the built directory):
sudo rmmod 210x
sudo insmod 210x.ko
## Program GPIO_MAS
1. Examples:
* Set all 1's:
./cp210x_gpio.py -d /dev/ttyUSB0 -m 0xff 0xff
* Set GPIO[3]=1, others - 0:
./cp210x_gpio.py -d /dev/ttyUSB1 -m 0xff 0x08
## Changes in the driver
* Changes in the driver cp210x.c are based on the patch found [here](https://lkml.org/lkml/2012/5/1/2)
* GPIO_VALUE=arg[23:16], GPIO_MASK=arg[7:0]
## Unresolved questions
* Silabs drivers in 2.6.x and 3.x.x for GPIOs differ:
* 2.6.x: GPIO_VALUE=arg[23:16], GPIO_MASK=arg[7:0] - this matches the patch
* 3.x.x: GPIO_VALUE=arg[15: 8], GPIO_MASK=arg[7:0]
## Links
* [Silabs CP210x USB to UART Bridge VCP Drivers](http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers.aspx) - supported kernels 2.6.x, 3.x.x (but 3.x.x are not up-to-date - cannot be built in 3.8.0)
* [cp210x: Add ioctl for GPIO support](https://lkml.org/lkml/2012/5/1/2) - patch
\ No newline at end of file
#!/bin/bash
CP210X_NAME="cp210x.c"
CP210X_ADDRESS="https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/plain/drivers/usb/serial/cp210x.c?id=refs/tags/v"
PATCH_NAME="cp210x.patch"
LINUX_KERNEL_VERSION=$(uname -r | cut -f1 -d"-")
LKV_P1=$(echo $LINUX_KERNEL_VERSION | cut -f1 -d".")
LKV_P2=$(echo $LINUX_KERNEL_VERSION | cut -f2 -d".")
LKV_P3=$(echo $LINUX_KERNEL_VERSION | cut -f3 -d".")
if [ $LKV_P3 = 0 ]; then
CP210X_VERSION=$(echo "$LKV_P1.$LKV_P2")
else
CP210X_VERSION=$(echo "$LKV_P1.$LKV_P2.$LKV_P3")
fi
#uncomment if patch doesn't work
#CP210X_VERSION="3.8.0"
#get the file to patch
if [ ! -f $CP210X_NAME ]; then
wget -O $CP210X_NAME "${CP210X_ADDRESS}${CP210X_VERSION}"
fi
#patch
patch -r - -Np1 < $PATCH_NAME
#run make
make clean
make
This diff is collapsed.
--- a/cp210x.c 2013-10-30 18:43:43.000000000 -0600
+++ b/cp210x.c 2013-10-30 19:23:02.410147064 -0600
@@ -31,6 +31,8 @@
*/
static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
static void cp210x_close(struct usb_serial_port *);
+static int cp210x_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg);
static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int *cflagp, unsigned int *baudp);
@@ -174,6 +176,7 @@
.bulk_out_size = 256,
.open = cp210x_open,
.close = cp210x_close,
+ .ioctl = cp210x_ioctl,
.break_ctl = cp210x_break_ctl,
.set_termios = cp210x_set_termios,
.tiocmget = cp210x_tiocmget,
@@ -187,6 +190,10 @@
&cp210x_device, NULL
};
+/* IOCTLs */
+#define IOCTL_GPIOGET 0x8000
+#define IOCTL_GPIOSET 0x8001
+
/* Config request types */
#define REQTYPE_HOST_TO_INTERFACE 0x41
#define REQTYPE_INTERFACE_TO_HOST 0xc1
@@ -220,11 +227,16 @@
#define CP210X_SET_CHARS 0x19
#define CP210X_GET_BAUDRATE 0x1D
#define CP210X_SET_BAUDRATE 0x1E
+#define CP210X_VENDOR_SPECIFIC 0xFF
/* CP210X_IFC_ENABLE */
#define UART_ENABLE 0x0001
#define UART_DISABLE 0x0000
+/* CP210X_VENDOR_SPECIFIC */
+#define CP210X_WRITE_LATCH 0x37E1
+#define CP210X_READ_LATCH 0x00C2
+
/* CP210X_(SET|GET)_BAUDDIV */
#define BAUD_RATE_GEN_FREQ 0x384000
@@ -449,6 +461,54 @@
mutex_unlock(&port->serial->disc_mutex);
}
+static int cp210x_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ int result = 0;
+ struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+ unsigned int latch_setting = 0;
+
+ switch (cmd) {
+ case IOCTL_GPIOGET:
+ result = usb_control_msg(
+ serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ CP210X_VENDOR_SPECIFIC,
+ REQTYPE_DEVICE_TO_HOST,
+ CP210X_READ_LATCH,
+ spriv->bInterfaceNumber,
+ &latch_setting, 1,
+ USB_CTRL_GET_TIMEOUT);
+ if (result != 1)
+ return -EPROTO;
+ *(unsigned long *)arg = (unsigned long)latch_setting;
+ return 0;
+ break;
+ case IOCTL_GPIOSET:
+ latch_setting = *(unsigned int *)arg & 0x000000FF;
+ //why [23:16] bits are taken for value is unknown
+ latch_setting |= (*(unsigned int *)arg & 0x00FF0000) >> 8;
+
+ result = usb_control_msg(
+ serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ CP210X_VENDOR_SPECIFIC,
+ REQTYPE_HOST_TO_DEVICE,
+ CP210X_WRITE_LATCH,
+ latch_setting,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (result != 0)
+ return -EPROTO;
+ return 0;
+ break;
+ default:
+ break;
+ }
+ return -ENOIOCTLCMD;
+}
+
/*
* cp210x_get_termios
* Reads the baud rate, data bits, parity, stop bits and flow control mode
#!/usr/bin/python
#-----------------------------------------------------------------------------
# FILE NAME : cp210x_gpio.py
# DESCRIPTION: control GPIO pins for CP210X USB to UART Bridges
# Copyright (C) 2013 Elphel, 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 3 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.
#
# The four essential freedoms with GNU GPL software are:
# * to run the program for any purpose
# * to study how the program works and change it to make it do what you wish
# * to redistribute copies so you can help your neighbor
# * to distribute copies of your modified versions to others
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#-----------------------------------------------------------------------------
__author__ = "Oleg Dzhimiev"
__copyright__ = "Copyright 2013, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Oleg Dzhimiev"
__email__ = "oleg@elphel.com"
__status__ = "Released"
import array, fcntl
import argparse # http://docs.python.org/2/howto/argparse.html
IOCTL_GPIOGET = 0x8000
IOCTL_GPIOSET = 0x8001
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--device', default="/dev/ttyUSB0", help='USB device. Default: /dev/ttyUSB0')
parser.add_argument("gpio_value", help="hex value for GPIO. Example (GPIO[3:0]): 0xf - all 1's, 0x0 - all 0's")
parser.add_argument('-m', '--mask', default="0xff",help='hex value for masking out GPIO bits: 1 - enable rewrite, 0 - disable. Example (GPIO[3:0]): -m 0xf')
args = parser.parse_args()
device=args.device
mask = int(args.mask,0)
gpio = (int(args.gpio_value,0)<<16)|mask
print ('Target GPIO value:'),gpio
try:
fd = open(device, 'r+')
except:
raise Exception(str(device)+' is not present')
buf = array.array('l', [0])
fcntl.ioctl(fd, IOCTL_GPIOGET, buf, 1)
print ('Old GPIO value:'),hex(buf[0])
buf[0] = gpio
fcntl.ioctl(fd, IOCTL_GPIOSET, buf, 1)
fcntl.ioctl(fd, IOCTL_GPIOGET, buf, 1)
print ('New GPIO value:'),hex(buf[0])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment