forked from UncleGrumpy/spi-ch341-usb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert the whole driver to an MFD driver
This splits the driver into 4 modules: core, i2c, gpio and spi. It's that version that may be upstreamed.
- Loading branch information
Showing
9 changed files
with
1,013 additions
and
940 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
PWD := $(shell pwd) | ||
KVERSION := $(shell uname -r) | ||
KERNEL_DIR ?= /lib/modules/$(KVERSION)/build | ||
KDIR ?= /lib/modules/$(KVERSION)/build | ||
|
||
obj-m := ch341-buses.o | ||
|
||
ch341-buses-objs := ch341-core.o ch341-i2c.o ch341-gpio.o ch341-spi.o | ||
obj-m += ch341-core.o | ||
obj-m += i2c-ch341.o | ||
obj-m += gpio-ch341.o | ||
obj-m += spi-ch341.o | ||
|
||
all: | ||
make -C $(KERNEL_DIR) M=$(PWD) modules | ||
make -C $(KDIR) M=$(PWD) modules | ||
clean: | ||
make -C $(KERNEL_DIR) M=$(PWD) clean | ||
make -C $(KDIR) M=$(PWD) clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,69 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Driver for the CH341A, and CH341B USB to I2C/SPI/GPIO adapter | ||
* Driver for the CH341T USB to I2C adapter | ||
* Core driver for the CH341A, CH341B and CH341T in I2C/SPI/GPIO | ||
* mode. There are cell drivers available for I2C and GPIO. SPI is not | ||
* yet supported. | ||
* | ||
* Copyright 2021, Frank Zago | ||
* Copyright 2022, Frank Zago | ||
* Copyright (c) 2017 Gunar Schorcht ([email protected]) | ||
* Copyright (c) 2016 Tse Lun Bien | ||
* Copyright (c) 2014 Marco Gittler | ||
* Copyright (c) 2006-2007 Till Harbaum ([email protected]) | ||
* | ||
* The full UART functionality is handled by the CH341 serial driver | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
|
||
#include "ch341.h" | ||
#include <linux/mfd/core.h> | ||
#include <linux/module.h> | ||
#include <linux/slab.h> | ||
#include <linux/usb.h> | ||
|
||
static void ch341_usb_free_device(struct ch341_device *dev) | ||
{ | ||
ch341_spi_remove(dev); | ||
ch341_gpio_remove(dev); | ||
ch341_i2c_remove(dev); | ||
|
||
usb_set_intfdata(dev->iface, NULL); | ||
usb_put_dev(dev->usb_dev); | ||
|
||
kfree(dev); | ||
} | ||
static const struct mfd_cell ch341_devs[] = { | ||
{ .name = "ch341-gpio", }, | ||
{ .name = "ch341-i2c", }, | ||
}; | ||
|
||
static int ch341_usb_probe(struct usb_interface *iface, | ||
const struct usb_device_id *usb_id) | ||
{ | ||
struct usb_host_endpoint *endpoints; | ||
struct ch341_device *dev; | ||
int rc; | ||
|
||
dev = kzalloc(sizeof(struct ch341_device), GFP_KERNEL); | ||
if (!dev) | ||
struct usb_endpoint_descriptor *bulk_out; | ||
struct usb_endpoint_descriptor *bulk_in; | ||
struct usb_endpoint_descriptor *intr_in; | ||
struct ch341_ddata *ddata; | ||
int ret; | ||
|
||
ddata = devm_kzalloc(&iface->dev, sizeof(*ddata), GFP_KERNEL); | ||
if (!ddata) | ||
return -ENOMEM; | ||
|
||
dev->usb_dev = usb_get_dev(interface_to_usbdev(iface)); | ||
dev->iface = iface; | ||
mutex_init(&dev->usb_lock); | ||
ddata->usb_dev = interface_to_usbdev(iface); | ||
mutex_init(&ddata->usb_lock); | ||
|
||
if (iface->cur_altsetting->desc.bNumEndpoints != 3) { | ||
rc = -EIO; | ||
goto free_dev; | ||
ret = usb_find_common_endpoints(iface->cur_altsetting, &bulk_in, | ||
&bulk_out, &intr_in, NULL); | ||
if (ret) { | ||
dev_err(&iface->dev, "Could not find all endpoints\n"); | ||
return -ENODEV; | ||
} | ||
|
||
endpoints = iface->cur_altsetting->endpoint; | ||
if (!usb_endpoint_is_bulk_in(&endpoints[0].desc) || | ||
!usb_endpoint_is_bulk_out(&endpoints[1].desc) || | ||
!usb_endpoint_xfer_int(&endpoints[2].desc)) { | ||
rc = -EIO; | ||
goto free_dev; | ||
} | ||
|
||
dev->ep_in = endpoints[0].desc.bEndpointAddress; | ||
dev->ep_out = endpoints[1].desc.bEndpointAddress; | ||
dev->ep_intr = endpoints[2].desc.bEndpointAddress; | ||
dev->ep_intr_interval = endpoints[2].desc.bInterval; | ||
|
||
usb_set_intfdata(iface, dev); | ||
|
||
rc = ch341_i2c_init(dev); | ||
if (rc) | ||
goto free_dev; | ||
|
||
rc = ch341_gpio_init(dev); | ||
if (rc) | ||
goto rem_i2c; | ||
ddata->ep_in = bulk_in->bEndpointAddress; | ||
ddata->ep_out = bulk_out->bEndpointAddress; | ||
ddata->ep_intr = intr_in->bEndpointAddress; | ||
ddata->ep_intr_interval = intr_in->bInterval; | ||
|
||
rc = ch341_spi_init(dev); | ||
if (rc) | ||
goto rem_gpio; | ||
usb_set_intfdata(iface, ddata); | ||
|
||
return 0; | ||
ret = devm_mfd_add_devices(&iface->dev, PLATFORM_DEVID_AUTO, ch341_devs, | ||
ARRAY_SIZE(ch341_devs), NULL, 0, NULL); | ||
if (ret) | ||
dev_err(&iface->dev, "Failed to add child devices\n"); | ||
|
||
rem_gpio: | ||
ch341_gpio_remove(dev); | ||
|
||
rem_i2c: | ||
ch341_i2c_remove(dev); | ||
|
||
free_dev: | ||
usb_put_dev(dev->usb_dev); | ||
kfree(dev); | ||
|
||
return rc; | ||
return ret; | ||
} | ||
|
||
static void ch341_usb_disconnect(struct usb_interface *usb_if) | ||
{ | ||
struct ch341_device *dev = usb_get_intfdata(usb_if); | ||
|
||
ch341_usb_free_device(dev); | ||
} | ||
|
||
static const struct usb_device_id ch341_usb_table[] = { | ||
|
@@ -105,14 +73,13 @@ static const struct usb_device_id ch341_usb_table[] = { | |
MODULE_DEVICE_TABLE(usb, ch341_usb_table); | ||
|
||
static struct usb_driver ch341_usb_driver = { | ||
.name = "ch341-buses", | ||
.name = "ch341-mfd", | ||
.id_table = ch341_usb_table, | ||
.probe = ch341_usb_probe, | ||
.disconnect = ch341_usb_disconnect | ||
.disconnect = ch341_usb_disconnect, | ||
}; | ||
|
||
module_usb_driver(ch341_usb_driver); | ||
|
||
MODULE_AUTHOR("Various"); | ||
MODULE_DESCRIPTION("ch341 USB to I2C/SPI/GPIO adapter"); | ||
MODULE_LICENSE("GPL v2"); | ||
MODULE_AUTHOR("Frank Zago <[email protected]>"); | ||
MODULE_DESCRIPTION("CH341 USB to I2C/SPI/GPIO adapter"); | ||
MODULE_LICENSE("GPL"); |
Oops, something went wrong.