summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-10-08 02:48:26 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-10-08 02:48:26 +0300
commitd3dcbe24a0fc6373ce7e4a65acd5c785aa8e2396 (patch)
tree2072b4977f2e22f0b51bd7e48f131c48c14e896d /drivers/usb/gadget
parent6181073dd6a7e5deafc60e7981bd765b6c93da8c (diff)
parent00988f70a0763f14c97c4c0df76fb9aa4959e953 (diff)
downloadlinux-d3dcbe24a0fc6373ce7e4a65acd5c785aa8e2396.tar.xz
Merge tag 'usb-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH: "Here is the big set of USB and Thunderbolt driver changes for 6.1-rc1. Nothing major in here, lots of little things with new devices supported and updates for a few drivers. Highlights include: - thunderbolt/USB4 devices supported a bit better than before, and some new ids to enable new hardware devices - USB gadget uvc updates for newer video formats and better v4l integration (the v4l portions were acked by those maintainers) - typec updates for tiny issues and more typec drivers for new chips. - xhci tiny updates for minor issues - big usb-serial ftdi_sio driver update to handle new devices better - lots of tiny dwc3 fixes and updates for the IP block that is showing up everywhere these days - dts updates for new devices being supported - other tiny janitorial and cleanups fixes for lots of different USB drivers. Full details are in the shortlog. All of these have been in linux-next for a while with no reported issues" * tag 'usb-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (169 commits) usb: gadget: uvc: don't put item still in use usb: gadget: uvc: Fix argument to sizeof() in uvc_register_video() usb: host: ehci-exynos: switch to using gpiod API Revert "usb: dwc3: Don't switch OTG -> peripheral if extcon is present" Revert "USB: fixup for merge issue with "usb: dwc3: Don't switch OTG -> peripheral if extcon is present"" dt-bindings: usb: Convert FOTG210 to dt schema usb: mtu3: fix failed runtime suspend in host only mode USB: omap_udc: Fix spelling mistake: "tranceiver_ctrl" -> "transceiver_ctrl" usb: typec: ucsi_ccg: Disable UCSI ALT support on Tegra usb: typec: Replace custom implementation of device_match_fwnode() usb: typec: ucsi: Don't warn on probe deferral usb: add quirks for Lenovo OneLink+ Dock MAINTAINERS: switch dwc3 to Thinh usb: idmouse: fix an uninit-value in idmouse_open USB: PHY: JZ4770: Switch to use dev_err_probe() helper usb: phy: generic: Switch to use dev_err_probe() helper usb: ulpi: use DEFINE_SHOW_ATTRIBUTE to simplify ulpi_regs usb: cdns3: remove dead code usb: cdc-wdm: Use skb_put_data() instead of skb_put/memcpy pair usb: musb: sunxi: Switch to use dev_err_probe() helper ...
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/function/f_fs.c6
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c11
-rw-r--r--drivers/usb/gadget/function/f_ncm.c60
-rw-r--r--drivers/usb/gadget/function/f_printer.c12
-rw-r--r--drivers/usb/gadget/function/f_tcm.c4
-rw-r--r--drivers/usb/gadget/function/f_uvc.c37
-rw-r--r--drivers/usb/gadget/function/rndis.c4
-rw-r--r--drivers/usb/gadget/function/u_ether.c8
-rw-r--r--drivers/usb/gadget/function/u_serial.c4
-rw-r--r--drivers/usb/gadget/function/uvc.h3
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c294
-rw-r--r--drivers/usb/gadget/function/uvc_video.c9
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c10
-rw-r--r--drivers/usb/gadget/udc/net2272.c4
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c4
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c131
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c78
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.h3
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c6
19 files changed, 544 insertions, 144 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index e0fa4b186ec6..73dc10a77cde 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -2645,10 +2645,10 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
unsigned i = 0;
vla_group(d);
vla_item(d, struct usb_gadget_strings *, stringtabs,
- lang_count + 1);
+ size_add(lang_count, 1));
vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
vla_item(d, struct usb_string, strings,
- lang_count*(needed_count+1));
+ size_mul(lang_count, (needed_count + 1)));
char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
@@ -3700,7 +3700,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name)
existing = _ffs_do_find_dev(name);
if (!existing)
- strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
+ strscpy(dev->name, name, ARRAY_SIZE(dev->name));
else if (existing != dev)
ret = -EBUSY;
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 925e99f9775c..3abf7f586e2a 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2662,11 +2662,16 @@ static ssize_t forced_eject_store(struct device *dev,
}
static DEVICE_ATTR_RW(nofua);
-/* mode wil be set in fsg_lun_attr_is_visible() */
-static DEVICE_ATTR(ro, 0, ro_show, ro_store);
-static DEVICE_ATTR(file, 0, file_show, file_store);
static DEVICE_ATTR_WO(forced_eject);
+/*
+ * Mode of the ro and file attribute files will be overridden in
+ * fsg_lun_dev_is_visible() depending on if this is a cdrom, or if it is a
+ * removable device.
+ */
+static DEVICE_ATTR_RW(ro);
+static DEVICE_ATTR_RW(file);
+
/****************************** FSG COMMON ******************************/
static void fsg_lun_release(struct device *dev)
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index dc8f078f918c..c36bcfa0e9b4 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -450,39 +450,35 @@ struct ndp_parser_opts {
unsigned next_ndp_index;
};
-#define INIT_NDP16_OPTS { \
- .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
- .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
- .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
- .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
- .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), \
- .ndplen_align = 4, \
- .dgram_item_len = 1, \
- .block_length = 1, \
- .ndp_index = 1, \
- .reserved1 = 0, \
- .reserved2 = 0, \
- .next_ndp_index = 1, \
- }
-
-
-#define INIT_NDP32_OPTS { \
- .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
- .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
- .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
- .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
- .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), \
- .ndplen_align = 8, \
- .dgram_item_len = 2, \
- .block_length = 2, \
- .ndp_index = 2, \
- .reserved1 = 1, \
- .reserved2 = 2, \
- .next_ndp_index = 2, \
- }
+static const struct ndp_parser_opts ndp16_opts = {
+ .nth_sign = USB_CDC_NCM_NTH16_SIGN,
+ .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN,
+ .nth_size = sizeof(struct usb_cdc_ncm_nth16),
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp16),
+ .dpe_size = sizeof(struct usb_cdc_ncm_dpe16),
+ .ndplen_align = 4,
+ .dgram_item_len = 1,
+ .block_length = 1,
+ .ndp_index = 1,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .next_ndp_index = 1,
+};
-static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static const struct ndp_parser_opts ndp32_opts = {
+ .nth_sign = USB_CDC_NCM_NTH32_SIGN,
+ .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN,
+ .nth_size = sizeof(struct usb_cdc_ncm_nth32),
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp32),
+ .dpe_size = sizeof(struct usb_cdc_ncm_dpe32),
+ .ndplen_align = 8,
+ .dgram_item_len = 2,
+ .block_length = 2,
+ .ndp_index = 2,
+ .reserved1 = 1,
+ .reserved2 = 2,
+ .next_ndp_index = 2,
+};
static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
{
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index abec5c58f525..a881c69b1f2b 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -89,7 +89,7 @@ struct printer_dev {
u8 printer_cdev_open;
wait_queue_head_t wait;
unsigned q_len;
- char *pnp_string; /* We don't own memory! */
+ char **pnp_string; /* We don't own memory! */
struct usb_function function;
};
@@ -1000,16 +1000,16 @@ static int printer_func_setup(struct usb_function *f,
if ((wIndex>>8) != dev->interface)
break;
- if (!dev->pnp_string) {
+ if (!*dev->pnp_string) {
value = 0;
break;
}
- value = strlen(dev->pnp_string);
+ value = strlen(*dev->pnp_string);
buf[0] = (value >> 8) & 0xFF;
buf[1] = value & 0xFF;
- memcpy(buf + 2, dev->pnp_string, value);
+ memcpy(buf + 2, *dev->pnp_string, value);
DBG(dev, "1284 PNP String: %x %s\n", value,
- dev->pnp_string);
+ *dev->pnp_string);
break;
case GET_PORT_STATUS: /* Get Port Status */
@@ -1475,7 +1475,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
kref_init(&dev->kref);
++opts->refcnt;
dev->minor = opts->minor;
- dev->pnp_string = opts->pnp_string;
+ dev->pnp_string = &opts->pnp_string;
dev->q_len = opts->q_len;
mutex_unlock(&opts->lock);
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 8e17ac831be0..658e2e21fdd0 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -2306,7 +2306,7 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi)
DECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc);
-static int tcm_init(void)
+static int __init tcm_init(void)
{
int ret;
@@ -2322,7 +2322,7 @@ static int tcm_init(void)
}
module_init(tcm_init);
-static void tcm_exit(void)
+static void __exit tcm_exit(void)
{
target_unregister_template(&usbg_ops);
usb_function_unregister(&tcmusb_func);
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 71669e0e4d00..6e196e06181e 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -421,7 +421,7 @@ uvc_register_video(struct uvc_device *uvc)
int ret;
/* TODO reference counting. */
- memset(&uvc->vdev, 0, sizeof(uvc->video));
+ memset(&uvc->vdev, 0, sizeof(uvc->vdev));
uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
uvc->vdev.fops = &uvc_v4l2_fops;
@@ -430,7 +430,7 @@ uvc_register_video(struct uvc_device *uvc)
uvc->vdev.vfl_dir = VFL_DIR_TX;
uvc->vdev.lock = &uvc->video.mutex;
uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name));
+ strscpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name));
video_set_drvdata(&uvc->vdev, uvc);
@@ -888,6 +888,7 @@ static void uvc_free(struct usb_function *f)
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst);
+ config_item_put(&uvc->header->item);
--opts->refcnt;
kfree(uvc);
}
@@ -897,10 +898,14 @@ static void uvc_function_unbind(struct usb_configuration *c,
{
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
+ struct uvc_video *video = &uvc->video;
long wait_ret = 1;
uvcg_info(f, "%s()\n", __func__);
+ if (video->async_wq)
+ destroy_workqueue(video->async_wq);
+
/*
* If we know we're connected via v4l2, then there should be a cleanup
* of the device from userspace either via UVC_EVENT_DISCONNECT or
@@ -941,6 +946,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
struct uvc_device *uvc;
struct f_uvc_opts *opts;
struct uvc_descriptor_header **strm_cls;
+ struct config_item *streaming, *header, *h;
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
if (uvc == NULL)
@@ -973,6 +979,28 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->desc.fs_streaming = opts->fs_streaming;
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
+
+ streaming = config_group_find_item(&opts->func_inst.group, "streaming");
+ if (!streaming)
+ goto err_config;
+
+ header = config_group_find_item(to_config_group(streaming), "header");
+ config_item_put(streaming);
+ if (!header)
+ goto err_config;
+
+ h = config_group_find_item(to_config_group(header), "h");
+ config_item_put(header);
+ if (!h)
+ goto err_config;
+
+ uvc->header = to_uvcg_streaming_header(h);
+ if (!uvc->header->linked) {
+ mutex_unlock(&opts->lock);
+ kfree(uvc);
+ return ERR_PTR(-EBUSY);
+ }
+
++opts->refcnt;
mutex_unlock(&opts->lock);
@@ -988,6 +1016,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->func.bind_deactivated = true;
return &uvc->func;
+
+err_config:
+ mutex_unlock(&opts->lock);
+ kfree(uvc);
+ return ERR_PTR(-ENOENT);
}
DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc);
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 713efd9aefde..29bf8664bf58 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -869,7 +869,7 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser);
static inline int rndis_get_nr(void)
{
- return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
+ return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL);
}
static inline void rndis_put_nr(int nr)
@@ -1105,7 +1105,7 @@ static int rndis_proc_show(struct seq_file *m, void *v)
"used : %s\n"
"state : %s\n"
"medium : 0x%08X\n"
- "speed : %d\n"
+ "speed : %u\n"
"cable : %s\n"
"vendor ID : 0x%08X\n"
"vendor : %s\n",
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 7887def05dc2..e06022873df1 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -144,10 +144,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
{
struct eth_dev *dev = netdev_priv(net);
- strlcpy(p->driver, "g_ether", sizeof(p->driver));
- strlcpy(p->version, UETH__VERSION, sizeof(p->version));
- strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
- strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+ strscpy(p->driver, "g_ether", sizeof(p->driver));
+ strscpy(p->version, UETH__VERSION, sizeof(p->version));
+ strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+ strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
}
/* REVISIT can also support:
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 6f68cbeeee7c..7538279f9817 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -1443,7 +1443,7 @@ void gserial_resume(struct gserial *gser)
}
EXPORT_SYMBOL_GPL(gserial_resume);
-static int userial_init(void)
+static int __init userial_init(void)
{
struct tty_driver *driver;
unsigned i;
@@ -1496,7 +1496,7 @@ fail:
}
module_init(userial_init);
-static void userial_cleanup(void)
+static void __exit userial_cleanup(void)
{
tty_unregister_driver(gs_tty_driver);
tty_driver_kref_put(gs_tty_driver);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 58e383afdd44..40226b1f7e14 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -88,6 +88,7 @@ struct uvc_video {
struct usb_ep *ep;
struct work_struct pump;
+ struct workqueue_struct *async_wq;
/* Frame parameters */
u8 bpp;
@@ -133,6 +134,8 @@ struct uvc_device {
bool func_connected;
wait_queue_head_t func_connected_queue;
+ struct uvcg_streaming_header *header;
+
/* Descriptors */
struct {
const struct uvc_descriptor_header * const *fs_control;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index fd8f73bb726d..c4ed48d6b8a4 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -18,12 +18,161 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-uvc.h>
#include "f_uvc.h"
#include "uvc.h"
#include "uvc_queue.h"
#include "uvc_video.h"
#include "uvc_v4l2.h"
+#include "uvc_configfs.h"
+
+static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
+{
+ char guid[16] = UVC_GUID_FORMAT_MJPEG;
+ struct uvc_format_desc *format;
+ struct uvcg_uncompressed *unc;
+
+ if (uformat->type == UVCG_UNCOMPRESSED) {
+ unc = to_uvcg_uncompressed(&uformat->group.cg_item);
+ if (!unc)
+ return ERR_PTR(-EINVAL);
+
+ memcpy(guid, unc->desc.guidFormat, sizeof(guid));
+ }
+
+ format = uvc_format_by_guid(guid);
+ if (!format)
+ return ERR_PTR(-EINVAL);
+
+ return format;
+}
+
+static int uvc_v4l2_get_bytesperline(struct uvcg_format *uformat,
+ struct uvcg_frame *uframe)
+{
+ struct uvcg_uncompressed *u;
+
+ if (uformat->type == UVCG_UNCOMPRESSED) {
+ u = to_uvcg_uncompressed(&uformat->group.cg_item);
+ if (!u)
+ return 0;
+
+ return u->desc.bBitsPerPixel * uframe->frame.w_width / 8;
+ }
+
+ return 0;
+}
+
+static int uvc_get_frame_size(struct uvcg_format *uformat,
+ struct uvcg_frame *uframe)
+{
+ unsigned int bpl = uvc_v4l2_get_bytesperline(uformat, uframe);
+
+ return bpl ? bpl * uframe->frame.w_height :
+ uframe->frame.dw_max_video_frame_buffer_size;
+}
+
+static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index)
+{
+ struct uvcg_format_ptr *format;
+ struct uvcg_format *uformat = NULL;
+ int i = 1;
+
+ list_for_each_entry(format, &uvc->header->formats, entry) {
+ if (index == i) {
+ uformat = format->fmt;
+ break;
+ }
+ i++;
+ }
+
+ return uformat;
+}
+
+static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
+ struct uvcg_format *uformat,
+ int index)
+{
+ struct uvcg_format_ptr *format;
+ struct uvcg_frame_ptr *frame;
+ struct uvcg_frame *uframe = NULL;
+
+ list_for_each_entry(format, &uvc->header->formats, entry) {
+ if (format->fmt->type != uformat->type)
+ continue;
+ list_for_each_entry(frame, &format->fmt->frames, entry) {
+ if (index == frame->frm->frame.b_frame_index) {
+ uframe = frame->frm;
+ break;
+ }
+ }
+ }
+
+ return uframe;
+}
+
+static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
+ u32 pixelformat)
+{
+ struct uvcg_format_ptr *format;
+ struct uvcg_format *uformat = NULL;
+
+ list_for_each_entry(format, &uvc->header->formats, entry) {
+ struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt);
+
+ if (fmtdesc->fcc == pixelformat) {
+ uformat = format->fmt;
+ break;
+ }
+ }
+
+ return uformat;
+}
+
+static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc,
+ struct uvcg_format *uformat,
+ u16 rw, u16 rh)
+{
+ struct uvc_video *video = &uvc->video;
+ struct uvcg_format_ptr *format;
+ struct uvcg_frame_ptr *frame;
+ struct uvcg_frame *uframe = NULL;
+ unsigned int d, maxd;
+
+ /* Find the closest image size. The distance between image sizes is
+ * the size in pixels of the non-overlapping regions between the
+ * requested size and the frame-specified size.
+ */
+ maxd = (unsigned int)-1;
+
+ list_for_each_entry(format, &uvc->header->formats, entry) {
+ if (format->fmt->type != uformat->type)
+ continue;
+
+ list_for_each_entry(frame, &format->fmt->frames, entry) {
+ u16 w, h;
+
+ w = frame->frm->frame.w_width;
+ h = frame->frm->frame.w_height;
+
+ d = min(w, rw) * min(h, rh);
+ d = w*h + rw*rh - 2*d;
+ if (d < maxd) {
+ maxd = d;
+ uframe = frame->frm;
+ }
+
+ if (maxd == 0)
+ break;
+ }
+ }
+
+ if (!uframe)
+ uvcg_dbg(&video->uvc->func, "Unsupported size %ux%u\n", rw, rh);
+
+ return uframe;
+}
/* --------------------------------------------------------------------------
* Requests handling
@@ -67,9 +216,9 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
struct uvc_device *uvc = video_get_drvdata(vdev);
struct usb_composite_dev *cdev = uvc->func.config->cdev;
- strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
- strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
- strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+ strscpy(cap->driver, "g_uvc", sizeof(cap->driver));
+ strscpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+ strscpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof(cap->bus_info));
return 0;
}
@@ -135,6 +284,139 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
}
static int
+uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvc_video *video = &uvc->video;
+ struct uvcg_format *uformat;
+ struct uvcg_frame *uframe;
+ u8 *fcc;
+
+ if (fmt->type != video->queue.queue.type)
+ return -EINVAL;
+
+ fcc = (u8 *)&fmt->fmt.pix.pixelformat;
+ uvcg_dbg(&uvc->func, "Trying format 0x%08x (%c%c%c%c): %ux%u\n",
+ fmt->fmt.pix.pixelformat,
+ fcc[0], fcc[1], fcc[2], fcc[3],
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+ uformat = find_format_by_pix(uvc, fmt->fmt.pix.pixelformat);
+ if (!uformat)
+ return -EINVAL;
+
+ uframe = find_closest_frame_by_size(uvc, uformat,
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+ if (!uframe)
+ return -EINVAL;
+
+ fmt->fmt.pix.width = uframe->frame.w_width;
+ fmt->fmt.pix.height = uframe->frame.w_height;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe);
+ fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe);
+ fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+static int
+uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvcg_format *uformat = NULL;
+ struct uvcg_frame *uframe = NULL;
+ struct uvcg_frame_ptr *frame;
+
+ uformat = find_format_by_pix(uvc, fival->pixel_format);
+ if (!uformat)
+ return -EINVAL;
+
+ list_for_each_entry(frame, &uformat->frames, entry) {
+ if (frame->frm->frame.w_width == fival->width &&
+ frame->frm->frame.w_height == fival->height) {
+ uframe = frame->frm;
+ break;
+ }
+ }
+ if (!uframe)
+ return -EINVAL;
+
+ if (fival->index >= uframe->frame.b_frame_interval_type)
+ return -EINVAL;
+
+ fival->discrete.numerator =
+ uframe->dw_frame_interval[fival->index];
+
+ /* TODO: handle V4L2_FRMIVAL_TYPE_STEPWISE */
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.denominator = 10000000;
+ v4l2_simplify_fraction(&fival->discrete.numerator,
+ &fival->discrete.denominator, 8, 333);
+
+ return 0;
+}
+
+static int
+uvc_v4l2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvcg_format *uformat = NULL;
+ struct uvcg_frame *uframe = NULL;
+
+ uformat = find_format_by_pix(uvc, fsize->pixel_format);
+ if (!uformat)
+ return -EINVAL;
+
+ if (fsize->index >= uformat->num_frames)
+ return -EINVAL;
+
+ uframe = find_frame_by_index(uvc, uformat, fsize->index + 1);
+ if (!uframe)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = uframe->frame.w_width;
+ fsize->discrete.height = uframe->frame.w_height;
+
+ return 0;
+}
+
+static int
+uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvc_format_desc *fmtdesc;
+ struct uvcg_format *uformat;
+
+ if (f->index >= uvc->header->num_fmt)
+ return -EINVAL;
+
+ uformat = find_format_by_index(uvc, f->index + 1);
+ if (!uformat)
+ return -EINVAL;
+
+ if (uformat->type != UVCG_UNCOMPRESSED)
+ f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+ fmtdesc = to_uvc_format(uformat);
+ f->pixelformat = fmtdesc->fcc;
+
+ strscpy(f->description, fmtdesc->name, sizeof(f->description));
+ f->description[strlen(fmtdesc->name) - 1] = 0;
+
+ return 0;
+}
+
+static int
uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
{
struct video_device *vdev = video_devdata(file);
@@ -170,7 +452,7 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
return ret;
if (uvc->state == UVC_STATE_STREAMING)
- schedule_work(&video->pump);
+ queue_work(video->async_wq, &video->pump);
return ret;
}
@@ -298,8 +580,12 @@ uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
.vidioc_querycap = uvc_v4l2_querycap,
+ .vidioc_try_fmt_vid_out = uvc_v4l2_try_format,
.vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
.vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
+ .vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals,
+ .vidioc_enum_framesizes = uvc_v4l2_enum_framesizes,
+ .vidioc_enum_fmt_vid_out = uvc_v4l2_enum_format,
.vidioc_reqbufs = uvc_v4l2_reqbufs,
.vidioc_querybuf = uvc_v4l2_querybuf,
.vidioc_qbuf = uvc_v4l2_qbuf,
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index c00ce0e91f5d..bb037fcc90e6 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -277,7 +277,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
spin_unlock_irqrestore(&video->req_lock, flags);
if (uvc->state == UVC_STATE_STREAMING)
- schedule_work(&video->pump);
+ queue_work(video->async_wq, &video->pump);
}
static int
@@ -485,7 +485,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
video->req_int_count = 0;
- schedule_work(&video->pump);
+ queue_work(video->async_wq, &video->pump);
return ret;
}
@@ -499,6 +499,11 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
spin_lock_init(&video->req_lock);
INIT_WORK(&video->pump, uvcg_video_pump);
+ /* Allocate a work queue for asynchronous video pump handler. */
+ video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0);
+ if (!video->async_wq)
+ return -EINVAL;
+
video->uvc = uvc;
video->fcc = V4L2_PIX_FMT_YUYV;
video->bpp = 16;
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index 728987280373..a9a7b3fc60ec 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -994,7 +994,7 @@ static const struct usb_gadget_ops at91_udc_ops = {
.udc_stop = at91_stop,
/*
- * VBUS-powered devices may also also want to support bigger
+ * VBUS-powered devices may also want to support bigger
* power budgets after an appropriate SET_CONFIGURATION.
*/
/* .vbus_power = at91_vbus_power, */
@@ -1779,12 +1779,14 @@ static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
board->vbus_polled = 1;
- board->vbus_pin = gpiod_get_from_of_node(np, "atmel,vbus-gpio", 0,
- GPIOD_IN, "udc_vbus");
+ board->vbus_pin = fwnode_gpiod_get_index(of_fwnode_handle(np),
+ "atmel,vbus", 0, GPIOD_IN,
+ "udc_vbus");
if (IS_ERR(board->vbus_pin))
board->vbus_pin = NULL;
- board->pullup_pin = gpiod_get_from_of_node(np, "atmel,pullup-gpio", 0,
+ board->pullup_pin = fwnode_gpiod_get_index(of_fwnode_handle(np),
+ "atmel,pullup", 0,
GPIOD_ASIS, "udc_pullup");
if (IS_ERR(board->pullup_pin))
board->pullup_pin = NULL;
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index c97cd4bc817c..84605a4d0715 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -91,7 +91,7 @@ module_param(dma_mode, ushort, 0644);
* mode 2 == ep-a 1k, ep-b 1k, ep-c 512db
* mode 3 == ep-a 1k, ep-b disabled, ep-c 512db
*/
-static ushort fifo_mode = 0;
+static ushort fifo_mode;
module_param(fifo_mode, ushort, 0644);
/*
@@ -100,7 +100,7 @@ module_param(fifo_mode, ushort, 0644);
* USB suspend requests will be ignored. This is acceptable for
* self-powered devices. For bus powered devices set this to 1.
*/
-static ushort enable_suspend = 0;
+static ushort enable_suspend;
module_param(enable_suspend, ushort, 0644);
static void assert_out_naking(struct net2272_ep *ep, const char *where)
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 61cabb9de6ae..bea346e362b2 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -2234,7 +2234,7 @@ static int proc_otg_show(struct seq_file *s)
char *ctrl_name = "(UNKNOWN)";
tmp = omap_readl(OTG_REV);
- ctrl_name = "tranceiver_ctrl";
+ ctrl_name = "transceiver_ctrl";
trans = omap_readw(USB_TRANSCEIVER_CTRL);
seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
tmp >> 4, tmp & 0xf, ctrl_name, trans);
@@ -2558,7 +2558,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
/* set up driver data structures */
BUG_ON(strlen(name) >= sizeof ep->name);
- strlcpy(ep->name, name, sizeof ep->name);
+ strscpy(ep->name, name, sizeof(ep->name));
INIT_LIST_HEAD(&ep->queue);
INIT_LIST_HEAD(&ep->iso);
ep->bEndpointAddress = addr;
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 648be3fd476a..615ba0a6fbee 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -17,6 +17,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -38,16 +39,16 @@
#define USB3_USB20_CON 0x204
#define USB3_USB30_CON 0x208
#define USB3_USB_STA 0x210
-#define USB3_DRD_CON 0x218
+#define USB3_DRD_CON(p) ((p)->is_rzv2m ? 0x400 : 0x218)
#define USB3_USB_INT_STA_1 0x220
#define USB3_USB_INT_STA_2 0x224
#define USB3_USB_INT_ENA_1 0x228
#define USB3_USB_INT_ENA_2 0x22c
#define USB3_STUP_DAT_0 0x230
#define USB3_STUP_DAT_1 0x234
-#define USB3_USB_OTG_STA 0x268
-#define USB3_USB_OTG_INT_STA 0x26c
-#define USB3_USB_OTG_INT_ENA 0x270
+#define USB3_USB_OTG_STA(p) ((p)->is_rzv2m ? 0x410 : 0x268)
+#define USB3_USB_OTG_INT_STA(p) ((p)->is_rzv2m ? 0x414 : 0x26c)
+#define USB3_USB_OTG_INT_ENA(p) ((p)->is_rzv2m ? 0x418 : 0x270)
#define USB3_P0_MOD 0x280
#define USB3_P0_CON 0x288
#define USB3_P0_STA 0x28c
@@ -135,6 +136,8 @@
#define USB_STA_VBUS_STA BIT(0)
/* DRD_CON */
+#define DRD_CON_PERI_RST BIT(31) /* rzv2m only */
+#define DRD_CON_HOST_RST BIT(30) /* rzv2m only */
#define DRD_CON_PERI_CON BIT(24)
#define DRD_CON_VBOUT BIT(0)
@@ -155,7 +158,7 @@
#define USB_INT_2_PIPE(n) BIT(n)
/* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */
-#define USB_OTG_IDMON BIT(4)
+#define USB_OTG_IDMON(p) ((p)->is_rzv2m ? BIT(0) : BIT(4))
/* P0_MOD */
#define P0_MOD_DIR BIT(6)
@@ -255,7 +258,7 @@
#define USB3_EP0_SS_MAX_PACKET_SIZE 512
#define USB3_EP0_HSFS_MAX_PACKET_SIZE 64
#define USB3_EP0_BUF_SIZE 8
-#define USB3_MAX_NUM_PIPES 6 /* This includes PIPE 0 */
+#define USB3_MAX_NUM_PIPES(p) ((p)->is_rzv2m ? 16 : 6) /* This includes PIPE 0 */
#define USB3_WAIT_US 3
#define USB3_DMA_NUM_SETTING_AREA 4
/*
@@ -326,10 +329,13 @@ struct renesas_usb3_priv {
int num_ramif;
int ramsize_per_pipe; /* unit = bytes */
bool workaround_for_vbus; /* if true, don't check vbus signal */
+ bool is_rzv2m; /* if true, RZ/V2M SoC */
};
struct renesas_usb3 {
void __iomem *reg;
+ struct reset_control *drd_rstc;
+ struct reset_control *usbp_rstc;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
@@ -363,6 +369,7 @@ struct renesas_usb3 {
bool forced_b_device;
bool start_to_connect;
bool role_sw_by_connector;
+ bool is_rzv2m;
};
#define gadget_to_renesas_usb3(_gadget) \
@@ -467,7 +474,7 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
static bool usb3_is_host(struct renesas_usb3 *usb3)
{
- return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
+ return !(usb3_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
}
static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
@@ -674,10 +681,20 @@ static void renesas_usb3_role_work(struct work_struct *work)
static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
{
+ if (usb3->is_rzv2m) {
+ if (host) {
+ usb3_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+ usb3_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+ } else {
+ usb3_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+ usb3_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+ }
+ }
+
if (host)
- usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+ usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
else
- usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+ usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
}
static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
@@ -693,9 +710,9 @@ static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
{
if (enable)
- usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+ usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
else
- usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+ usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
}
static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
@@ -716,7 +733,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
static bool usb3_is_a_device(struct renesas_usb3 *usb3)
{
- return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
+ return !(usb3_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
}
static void usb3_check_id(struct renesas_usb3 *usb3)
@@ -739,8 +756,8 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
USB3_USB_COM_CON);
- usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
- usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
+ usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
+ usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
usb3_check_id(usb3);
usb3_check_vbus(usb3);
@@ -750,7 +767,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
{
usb3_disconnect(usb3);
usb3_write(usb3, 0, USB3_P0_INT_ENA);
- usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
+ usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
usb3_write(usb3, 0, USB3_AXI_INT_ENA);
@@ -2005,9 +2022,15 @@ static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
usb3_check_id(usb3);
}
-static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta)
+static void usb3_irq_otg_int(struct renesas_usb3 *usb3)
{
- if (otg_int_sta & USB_OTG_IDMON)
+ u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA(usb3));
+
+ otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
+ if (otg_int_sta)
+ usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
+
+ if (otg_int_sta & USB_OTG_IDMON(usb3))
usb3_irq_idmon_change(usb3);
}
@@ -2015,7 +2038,6 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
{
u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
- u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA);
int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
if (int_sta_1) {
@@ -2027,11 +2049,8 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
if (int_sta_2)
usb3_irq_epc_int_2(usb3, int_sta_2);
- otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA);
- if (otg_int_sta) {
- usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA);
- usb3_irq_otg_int(usb3, otg_int_sta);
- }
+ if (!usb3->is_rzv2m)
+ usb3_irq_otg_int(usb3);
}
static void usb3_irq_dma_int(struct renesas_usb3 *usb3, u32 dma_sta)
@@ -2085,6 +2104,15 @@ static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
return ret;
}
+static irqreturn_t renesas_usb3_otg_irq(int irq, void *_usb3)
+{
+ struct renesas_usb3 *usb3 = _usb3;
+
+ usb3_irq_otg_int(usb3);
+
+ return IRQ_HANDLED;
+}
+
static void usb3_write_pn_mod(struct renesas_usb3_ep *usb3_ep,
const struct usb_endpoint_descriptor *desc)
{
@@ -2571,6 +2599,8 @@ static int renesas_usb3_remove(struct platform_device *pdev)
usb_role_switch_unregister(usb3->role_sw);
usb_del_gadget_udc(&usb3->gadget);
+ reset_control_assert(usb3->usbp_rstc);
+ reset_control_assert(usb3->drd_rstc);
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
__renesas_usb3_ep_free_request(usb3->ep0_req);
@@ -2589,8 +2619,8 @@ static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev,
usb3->num_usb3_eps = priv->ramsize_per_ramif * priv->num_ramif * 2 /
priv->ramsize_per_pipe + 1;
- if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES)
- usb3->num_usb3_eps = USB3_MAX_NUM_PIPES;
+ if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES(usb3))
+ usb3->num_usb3_eps = USB3_MAX_NUM_PIPES(usb3);
usb3->usb3_ep = devm_kcalloc(dev,
usb3->num_usb3_eps, sizeof(*usb3_ep),
@@ -2707,6 +2737,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = {
.workaround_for_vbus = true,
};
+static const struct renesas_usb3_priv renesas_usb3_priv_rzv2m = {
+ .ramsize_per_ramif = SZ_16K,
+ .num_ramif = 1,
+ .ramsize_per_pipe = SZ_4K,
+ .is_rzv2m = true,
+};
+
static const struct of_device_id usb3_of_match[] = {
{
.compatible = "renesas,r8a774c0-usb3-peri",
@@ -2718,6 +2755,9 @@ static const struct of_device_id usb3_of_match[] = {
.compatible = "renesas,r8a77990-usb3-peri",
.data = &renesas_usb3_priv_r8a77990,
}, {
+ .compatible = "renesas,rzv2m-usb3-peri",
+ .data = &renesas_usb3_priv_rzv2m,
+ }, {
.compatible = "renesas,rcar-gen3-usb3-peri",
.data = &renesas_usb3_priv_gen3,
},
@@ -2748,7 +2788,7 @@ static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
static int renesas_usb3_probe(struct platform_device *pdev)
{
struct renesas_usb3 *usb3;
- int irq, ret;
+ int irq, drd_irq, ret;
const struct renesas_usb3_priv *priv;
const struct soc_device_attribute *attr;
@@ -2762,10 +2802,18 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ if (priv->is_rzv2m) {
+ drd_irq = platform_get_irq_byname(pdev, "drd");
+ if (drd_irq < 0)
+ return drd_irq;
+ }
+
usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
if (!usb3)
return -ENOMEM;
+ usb3->is_rzv2m = priv->is_rzv2m;
+
usb3->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(usb3->reg))
return PTR_ERR(usb3->reg);
@@ -2787,6 +2835,14 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ if (usb3->is_rzv2m) {
+ ret = devm_request_irq(&pdev->dev, drd_irq,
+ renesas_usb3_otg_irq, 0,
+ dev_name(&pdev->dev), usb3);
+ if (ret < 0)
+ return ret;
+ }
+
INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
if (IS_ERR(usb3->extcon))
@@ -2817,10 +2873,27 @@ static int renesas_usb3_probe(struct platform_device *pdev)
goto err_add_udc;
}
+ usb3->drd_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
+ "drd_reset");
+ if (IS_ERR(usb3->drd_rstc)) {
+ ret = PTR_ERR(usb3->drd_rstc);
+ goto err_add_udc;
+ }
+
+ usb3->usbp_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
+ "aresetn_p");
+ if (IS_ERR(usb3->usbp_rstc)) {
+ ret = PTR_ERR(usb3->usbp_rstc);
+ goto err_add_udc;
+ }
+
+ reset_control_deassert(usb3->drd_rstc);
+ reset_control_deassert(usb3->usbp_rstc);
+
pm_runtime_enable(&pdev->dev);
ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget);
if (ret < 0)
- goto err_add_udc;
+ goto err_reset;
ret = device_create_file(&pdev->dev, &dev_attr_role);
if (ret < 0)
@@ -2858,6 +2931,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
err_dev_create:
usb_del_gadget_udc(&usb3->gadget);
+err_reset:
+ reset_control_assert(usb3->usbp_rstc);
+ reset_control_assert(usb3->drd_rstc);
+
err_add_udc:
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index c6625aeb7bca..8c57b191e52b 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -23,7 +23,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/prefetch.h>
#include <linux/io.h>
@@ -1419,8 +1419,7 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
{
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
- if (udc_info && (udc_info->udc_command ||
- gpio_is_valid(udc_info->pullup_pin))) {
+ if (udc_info && (udc_info->udc_command || udc->pullup_gpiod)) {
if (is_on)
s3c2410_udc_enable(udc);
@@ -1467,9 +1466,7 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
- value = gpio_get_value(udc_info->vbus_pin) ? 1 : 0;
- if (udc_info->vbus_pin_inverted)
- value = !value;
+ value = gpiod_get_value(dev->vbus_gpiod);
if (value != dev->vbus)
s3c2410_udc_vbus_session(&dev->gadget, value);
@@ -1504,14 +1501,15 @@ static const struct usb_gadget_ops s3c2410_ops = {
.udc_stop = s3c2410_udc_stop,
};
-static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
+static void s3c2410_udc_command(struct s3c2410_udc *udc,
+ enum s3c2410_udc_cmd_e cmd)
{
if (!udc_info)
return;
if (udc_info->udc_command) {
udc_info->udc_command(cmd);
- } else if (gpio_is_valid(udc_info->pullup_pin)) {
+ } else if (udc->pullup_gpiod) {
int value;
switch (cmd) {
@@ -1524,9 +1522,8 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
default:
return;
}
- value ^= udc_info->pullup_pin_inverted;
- gpio_set_value(udc_info->pullup_pin, value);
+ gpiod_set_value(udc->pullup_gpiod, value);
}
}
@@ -1551,7 +1548,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev)
udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
/* Good bye, cruel world */
- s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
+ s3c2410_udc_command(dev, S3C2410_UDC_P_DISABLE);
/* Set speed to unknown */
dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1613,7 +1610,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
/* time to say "hello, world" */
- s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
+ s3c2410_udc_command(dev, S3C2410_UDC_P_ENABLE);
}
static int s3c2410_udc_start(struct usb_gadget *g,
@@ -1802,14 +1799,15 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
dev_dbg(dev, "got irq %i\n", irq_usbd);
- if (udc_info && udc_info->vbus_pin > 0) {
- retval = gpio_request(udc_info->vbus_pin, "udc vbus");
- if (retval < 0) {
- dev_err(dev, "cannot claim vbus pin\n");
- goto err_int;
- }
+ udc->vbus_gpiod = gpiod_get_optional(dev, "vbus", GPIOD_IN);
+ if (IS_ERR(udc->vbus_gpiod)) {
+ retval = PTR_ERR(udc->vbus_gpiod);
+ goto err_int;
+ }
+ if (udc->vbus_gpiod) {
+ gpiod_set_consumer_name(udc->vbus_gpiod, "udc vbus");
- irq = gpio_to_irq(udc_info->vbus_pin);
+ irq = gpiod_to_irq(udc->vbus_gpiod);
if (irq < 0) {
dev_err(dev, "no irq for gpio vbus pin\n");
retval = irq;
@@ -1833,16 +1831,12 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
udc->vbus = 1;
}
- if (udc_info && !udc_info->udc_command &&
- gpio_is_valid(udc_info->pullup_pin)) {
-
- retval = gpio_request_one(udc_info->pullup_pin,
- udc_info->vbus_pin_inverted ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
- "udc pullup");
- if (retval)
- goto err_vbus_irq;
+ udc->pullup_gpiod = gpiod_get_optional(dev, "pullup", GPIOD_OUT_LOW);
+ if (IS_ERR(udc->pullup_gpiod)) {
+ retval = PTR_ERR(udc->pullup_gpiod);
+ goto err_vbus_irq;
}
+ gpiod_set_consumer_name(udc->pullup_gpiod, "udc pullup");
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval)
@@ -1856,15 +1850,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- if (udc_info && !udc_info->udc_command &&
- gpio_is_valid(udc_info->pullup_pin))
- gpio_free(udc_info->pullup_pin);
err_vbus_irq:
- if (udc_info && udc_info->vbus_pin > 0)
- free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
+ if (udc->vbus_gpiod)
+ free_irq(gpiod_to_irq(udc->vbus_gpiod), udc);
err_gpio_claim:
- if (udc_info && udc_info->vbus_pin > 0)
- gpio_free(udc_info->vbus_pin);
err_int:
free_irq(irq_usbd, udc);
err_udc_clk:
@@ -1885,7 +1874,6 @@ err_usb_bus_clk:
static int s3c2410_udc_remove(struct platform_device *pdev)
{
struct s3c2410_udc *udc = platform_get_drvdata(pdev);
- unsigned int irq;
dev_dbg(&pdev->dev, "%s()\n", __func__);
@@ -1895,14 +1883,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&udc->gadget);
debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root));
- if (udc_info && !udc_info->udc_command &&
- gpio_is_valid(udc_info->pullup_pin))
- gpio_free(udc_info->pullup_pin);
-
- if (udc_info && udc_info->vbus_pin > 0) {
- irq = gpio_to_irq(udc_info->vbus_pin);
- free_irq(irq, udc);
- }
+ if (udc->vbus_gpiod)
+ free_irq(gpiod_to_irq(udc->vbus_gpiod), udc);
free_irq(irq_usbd, udc);
@@ -1926,14 +1908,18 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
static int
s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
{
- s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
+ struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+ s3c2410_udc_command(udc, S3C2410_UDC_P_DISABLE);
return 0;
}
static int s3c2410_udc_resume(struct platform_device *pdev)
{
- s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
+ struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+ s3c2410_udc_command(udc, S3C2410_UDC_P_ENABLE);
return 0;
}
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h
index 135a5bff3c74..cdbf202e5ee8 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.h
+++ b/drivers/usb/gadget/udc/s3c2410_udc.h
@@ -83,6 +83,9 @@ struct s3c2410_udc {
u32 port_status;
int ep0state;
+ struct gpio_desc *vbus_gpiod;
+ struct gpio_desc *pullup_gpiod;
+
unsigned got_irq : 1;
unsigned req_std : 1;
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 3c37effdfa64..76919d7570d2 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -2,7 +2,7 @@
/*
* NVIDIA Tegra XUSB device mode controller
*
- * Copyright (c) 2013-2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2015, Google Inc.
*/
@@ -702,6 +702,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
pm_runtime_get_sync(xudc->dev);
+ tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy);
+
err = phy_power_on(xudc->curr_utmi_phy);
if (err < 0)
dev_err(xudc->dev, "UTMI power on failed: %d\n", err);
@@ -756,6 +758,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
/* Make sure interrupt handler has completed before powergating. */
synchronize_irq(xudc->irq);
+ tegra_phy_xusb_utmi_pad_power_down(xudc->curr_utmi_phy);
+
err = phy_power_off(xudc->curr_utmi_phy);
if (err < 0)
dev_err(xudc->dev, "UTMI PHY power off failed: %d\n", err);