select HAVE_SPARSE_IRQ
select RTC_LIB
select GENERIC_ATOMIC64
- select GENERIC_HARDIRQS_NO_DEPRECATED
+ # Support the deprecated APIs until MFD and GPIOLIB catch up.
+ select GENERIC_HARDIRQS_NO_DEPRECATED if !MFD_SUPPORT && !GPIOLIB
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
config CPU_SH2A
bool
select CPU_SH2
+ select UNCACHED_MAPPING
config CPU_SH3
bool
select CPU_SH3
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
+ select USB_ARCH_HAS_OHCI
help
Select SH7720 if you have a SH3-DSP SH7720 CPU.
select CPU_SH3
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
+ select USB_ARCH_HAS_OHCI
help
Select SH7721 if you have a SH3-DSP SH7721 CPU.
config CPU_SUBTYPE_SH7763
bool "Support SH7763 processor"
select CPU_SH4A
+ select USB_ARCH_HAS_OHCI
help
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
select CPU_SHX3
select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
config CPU_SUBTYPE_SHX3
bool "Support SH-X3 processor"
#include <linux/string.h>
#include <linux/types.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include "vendorcmds.h"
#include "pd-common.h"
device_init_wakeup(&udev->dev, 1);
#ifdef CONFIG_PM
- pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
+ pm_runtime_set_autosuspend_delay(&pd->udev->dev,
+ 1000 * PM_SUSPEND_DELAY);
usb_enable_autosuspend(pd->udev);
if (in_hibernation(pd)) {
/*unregister v4l2 device */
v4l2_device_unregister(&pd->v4l2_dev);
- lock_kernel();
- {
- pd_dvb_usb_device_exit(pd);
- poseidon_fm_exit(pd);
+ pd_dvb_usb_device_exit(pd);
+ poseidon_fm_exit(pd);
- poseidon_audio_free(pd);
- pd_video_exit(pd);
- }
- unlock_kernel();
+ poseidon_audio_free(pd);
+ pd_video_exit(pd);
usb_set_intfdata(interface, NULL);
kref_put(&pd->kref, poseidon_delete);
#include <asm/unaligned.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
- #include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
*/
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ if (hcd->self.uses_pio_for_control)
+ return ret;
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC
select USB_GADGET_DUALSPEED
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
help
Some of Freescale PowerPC processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410
+ config USB_GADGET_PXA_U2O
+ boolean "PXA9xx Processor USB2.0 controller"
+ select USB_GADGET_DUALSPEED
+ help
+ PXA9xx Processor series include a high speed USB2.0 device
+ controller, which support high speed and full speed USB peripheral.
+
+ config USB_PXA_U2O
+ tristate
+ depends on USB_GADGET_PXA_U2O
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
#
# Controllers available in both integrated and discrete versions
#
default USB_GADGET
select USB_GADGET_SELECTED
- config USB_GADGET_CI13XXX
- boolean "MIPS USB CI13xxx"
+ config USB_GADGET_CI13XXX_PCI
+ boolean "MIPS USB CI13xxx PCI UDC"
depends on PCI
select USB_GADGET_DUALSPEED
help
dynamically linked module called "ci13xxx_udc" and force all
gadget drivers to also be dynamically linked.
- config USB_CI13XXX
+ config USB_CI13XXX_PCI
tristate
- depends on USB_GADGET_CI13XXX
+ depends on USB_GADGET_CI13XXX_PCI
default USB_GADGET
select USB_GADGET_SELECTED
default USB_GADGET
select USB_GADGET_SELECTED
+ config USB_GADGET_EG20T
+ boolean "Intel EG20T(Topcliff) USB Device controller"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ This is a USB device driver for EG20T PCH.
+ EG20T PCH is the platform controller hub that is used in Intel's
+ general embedded platform. EG20T PCH has USB device interface.
+ Using this interface, it is able to access system devices connected
+ to USB device.
+ This driver enables USB device function.
+ USB device is a USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+ This driver supports both control transfer and bulk transfer modes.
+ This driver dose not support interrupt transfer or isochronous
+ transfer modes.
+
+ config USB_EG20T
+ tristate
+ depends on USB_GADGET_EG20T
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+ config USB_GADGET_CI13XXX_MSM
+ boolean "MIPS USB CI13xxx for MSM"
+ depends on ARCH_MSM
+ select USB_GADGET_DUALSPEED
+ select USB_MSM_OTG_72K
+ help
+ MSM SoC has chipidea USB controller. This driver uses
+ ci13xxx_udc core.
+ This driver depends on OTG driver for PHY initialization,
+ clock management, powering up VBUS, and power management.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "ci13xxx_msm" and force all
+ gadget drivers to also be dynamically linked.
+
+ config USB_CI13XXX_MSM
+ tristate
+ depends on USB_GADGET_CI13XXX_MSM
+ default USB_GADGET
+ select USB_GADGET_SELECTED
#
# LAST -- dummy/emulated controller
If you say "y" here, the Ethernet gadget driver will use the EEM
protocol rather than ECM. If unsure, say "n".
+ config USB_G_NCM
+ tristate "Network Control Model (NCM) support"
+ depends on NET
+ select CRC32
+ help
+ This driver implements USB CDC NCM subclass standard. NCM is
+ an advanced protocol for Ethernet encapsulation, allows grouping
+ of several ethernet frames into one USB transfer and diffferent
+ alignment possibilities.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_ncm".
+
config USB_GADGETFS
tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL
/*
- * f_fs.c -- user mode filesystem api for usb composite funtcion controllers
+ * f_fs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
*
- * Based on inode.c (GadgetFS):
+ * Based on inode.c (GadgetFS) which was:
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies
*
#include <linux/blkdev.h>
#include <linux/pagemap.h>
#include <asm/unaligned.h>
-#include <linux/smp_lock.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
- /* Debuging *****************************************************************/
-
- #define ffs_printk(level, fmt, args...) printk(level "f_fs: " fmt "\n", ## args)
-
- #define FERR(...) ffs_printk(KERN_ERR, __VA_ARGS__)
- #define FINFO(...) ffs_printk(KERN_INFO, __VA_ARGS__)
-
- #ifdef DEBUG
- # define FDBG(...) ffs_printk(KERN_DEBUG, __VA_ARGS__)
- #else
- # define FDBG(...) do { } while (0)
- #endif /* DEBUG */
-
- #ifdef VERBOSE_DEBUG
- # define FVDBG FDBG
- #else
- # define FVDBG(...) do { } while (0)
- #endif /* VERBOSE_DEBUG */
-
- #define ENTER() FVDBG("%s()", __func__)
+ /* Debugging ****************************************************************/
#ifdef VERBOSE_DEBUG
+ # define pr_vdebug pr_debug
# define ffs_dump_mem(prefix, ptr, len) \
- print_hex_dump_bytes("f_fs" prefix ": ", DUMP_PREFIX_NONE, ptr, len)
+ print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
#else
+ # define pr_vdebug(...) do { } while (0)
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
- #endif
+ #endif /* VERBOSE_DEBUG */
+
+ #define ENTER() pr_vdebug("%s()\n", __func__)
/* The data structure and setup file ****************************************/
enum ffs_state {
- /* Waiting for descriptors and strings. */
- /* In this state no open(2), read(2) or write(2) on epfiles
+ /*
+ * Waiting for descriptors and strings.
+ *
+ * In this state no open(2), read(2) or write(2) on epfiles
* may succeed (which should not be the problem as there
- * should be no such files opened in the firts place). */
+ * should be no such files opened in the first place).
+ */
FFS_READ_DESCRIPTORS,
FFS_READ_STRINGS,
- /* We've got descriptors and strings. We are or have called
+ /*
+ * We've got descriptors and strings. We are or have called
* functionfs_ready_callback(). functionfs_bind() may have
- * been called but we don't know. */
- /* This is the only state in which operations on epfiles may
- * succeed. */
+ * been called but we don't know.
+ *
+ * This is the only state in which operations on epfiles may
+ * succeed.
+ */
FFS_ACTIVE,
- /* All endpoints have been closed. This state is also set if
+ /*
+ * All endpoints have been closed. This state is also set if
* we encounter an unrecoverable error. The only
* unrecoverable error is situation when after reading strings
- * from user space we fail to initialise EP files or
- * functionfs_ready_callback() returns with error (<0). */
- /* In this state no open(2), read(2) or write(2) (both on ep0
+ * from user space we fail to initialise epfiles or
+ * functionfs_ready_callback() returns with error (<0).
+ *
+ * In this state no open(2), read(2) or write(2) (both on ep0
* as well as epfile) may succeed (at this point epfiles are
* unlinked and all closed so this is not a problem; ep0 is
* also closed but ep0 file exists and so open(2) on ep0 must
- * fail). */
+ * fail).
+ */
FFS_CLOSING
};
enum ffs_setup_state {
/* There is no setup request pending. */
FFS_NO_SETUP,
- /* User has read events and there was a setup request event
+ /*
+ * User has read events and there was a setup request event
* there. The next read/write on ep0 will handle the
- * request. */
+ * request.
+ */
FFS_SETUP_PENDING,
- /* There was event pending but before user space handled it
+ /*
+ * There was event pending but before user space handled it
* some other event was introduced which canceled existing
* setup. If this state is set read/write on ep0 return
- * -EIDRM. This state is only set when adding event. */
+ * -EIDRM. This state is only set when adding event.
+ */
FFS_SETUP_CANCELED
};
struct ffs_data {
struct usb_gadget *gadget;
- /* Protect access read/write operations, only one read/write
+ /*
+ * Protect access read/write operations, only one read/write
* at a time. As a consequence protects ep0req and company.
* While setup request is being processed (queued) this is
- * held. */
+ * held.
+ */
struct mutex mutex;
- /* Protect access to enpoint related structures (basically
+ /*
+ * Protect access to endpoint related structures (basically
* usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
- * endpint zero. */
+ * endpoint zero.
+ */
spinlock_t eps_lock;
- /* XXX REVISIT do we need our own request? Since we are not
- * handling setup requests immidiatelly user space may be so
+ /*
+ * XXX REVISIT do we need our own request? Since we are not
+ * handling setup requests immediately user space may be so
* slow that another setup will be sent to the gadget but this
* time not to us but another function and then there could be
* a race. Is that the case? Or maybe we can use cdev->req
- * after all, maybe we just need some spinlock for that? */
+ * after all, maybe we just need some spinlock for that?
+ */
struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
int ep0req_status; /* P: mutex */
enum ffs_state state;
/*
- * Possible transations:
+ * Possible transitions:
* + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
* happens only in ep0 read which is P: mutex
* + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
/* Active function */
struct ffs_function *func;
- /* Device name, write once when file system is mounted.
- * Intendet for user to read if she wants. */
+ /*
+ * Device name, write once when file system is mounted.
+ * Intended for user to read if she wants.
+ */
const char *dev_name;
- /* Private data for our user (ie. gadget). Managed by
- * user. */
+ /* Private data for our user (ie. gadget). Managed by user. */
void *private_data;
/* filled by __ffs_data_got_descs() */
- /* real descriptors are 16 bytes after raw_descs (so you need
+ /*
+ * Real descriptors are 16 bytes after raw_descs (so you need
* to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
* first full speed descriptor). raw_descs_length and
- * raw_fs_descs_length do not have those 16 bytes added. */
+ * raw_fs_descs_length do not have those 16 bytes added.
+ */
const void *raw_descs;
unsigned raw_descs_length;
unsigned raw_fs_descs_length;
const void *raw_strings;
struct usb_gadget_strings **stringtabs;
- /* File system's super block, write once when file system is mounted. */
+ /*
+ * File system's super block, write once when file system is
+ * mounted.
+ */
struct super_block *sb;
- /* File permissions, written once when fs is mounted*/
+ /* File permissions, written once when fs is mounted */
struct ffs_file_perms {
umode_t mode;
uid_t uid;
gid_t gid;
} file_perms;
- /* The endpoint files, filled by ffs_epfiles_create(),
- * destroyed by ffs_epfiles_destroy(). */
+ /*
+ * The endpoint files, filled by ffs_epfiles_create(),
+ * destroyed by ffs_epfiles_destroy().
+ */
struct ffs_epfile *epfiles;
};
static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);
- /* Called with ffs->mutex held; take over ownerrship of data. */
+ /* Called with ffs->mutex held; take over ownership of data. */
static int __must_check
__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
static int __must_check
static void ffs_func_free(struct ffs_function *func);
-
static void ffs_func_eps_disable(struct ffs_function *func);
static int __must_check ffs_func_eps_enable(struct ffs_function *func);
-
static int ffs_func_bind(struct usb_configuration *,
struct usb_function *);
static void ffs_func_unbind(struct usb_configuration *,
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
-
/* The endpoints structures *************************************************/
struct ffs_ep {
unsigned char _pad;
};
-
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
complete_all(&ffs->ep0req_completion);
}
-
static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
{
struct usb_request *req = ffs->ep0req;
static int __ffs_ep0_stall(struct ffs_data *ffs)
{
if (ffs->ev.can_stall) {
- FVDBG("ep0 stall\n");
+ pr_vdebug("ep0 stall\n");
usb_ep_set_halt(ffs->gadget->ep0);
ffs->setup_state = FFS_NO_SETUP;
return -EL2HLT;
} else {
- FDBG("bogus ep0 stall!\n");
+ pr_debug("bogus ep0 stall!\n");
return -ESRCH;
}
}
-
static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
size_t len, loff_t *ptr)
{
if (unlikely(ret < 0))
return ret;
-
/* Check state */
switch (ffs->state) {
case FFS_READ_DESCRIPTORS:
}
data = ffs_prepare_buffer(buf, len);
- if (unlikely(IS_ERR(data))) {
+ if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
/* Handle data */
if (ffs->state == FFS_READ_DESCRIPTORS) {
- FINFO("read descriptors");
+ pr_info("read descriptors\n");
ret = __ffs_data_got_descs(ffs, data, len);
if (unlikely(ret < 0))
break;
ffs->state = FFS_READ_STRINGS;
ret = len;
} else {
- FINFO("read strings");
+ pr_info("read strings\n");
ret = __ffs_data_got_strings(ffs, data, len);
if (unlikely(ret < 0))
break;
}
break;
-
case FFS_ACTIVE:
data = NULL;
- /* We're called from user space, we can use _irq
- * rather then _irqsave */
+ /*
+ * We're called from user space, we can use _irq
+ * rather then _irqsave
+ */
spin_lock_irq(&ffs->ev.waitq.lock);
switch (FFS_SETUP_STATE(ffs)) {
case FFS_SETUP_CANCELED:
spin_unlock_irq(&ffs->ev.waitq.lock);
data = ffs_prepare_buffer(buf, len);
- if (unlikely(IS_ERR(data))) {
+ if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
spin_lock_irq(&ffs->ev.waitq.lock);
- /* We are guaranteed to be still in FFS_ACTIVE state
+ /*
+ * We are guaranteed to be still in FFS_ACTIVE state
* but the state of setup could have changed from
* FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
* to check for that. If that happened we copied data
- * from user space in vain but it's unlikely. */
- /* For sure we are not in FFS_NO_SETUP since this is
+ * from user space in vain but it's unlikely.
+ *
+ * For sure we are not in FFS_NO_SETUP since this is
* the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
* transition can be performed and it's protected by
- * mutex. */
-
+ * mutex.
+ */
if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
ret = -EIDRM;
done_spin:
kfree(data);
break;
-
default:
ret = -EBADFD;
break;
}
-
mutex_unlock(&ffs->mutex);
return ret;
}
-
-
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
{
- /* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
- * to release them. */
-
+ /*
+ * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
+ * to release them.
+ */
struct usb_functionfs_event events[n];
unsigned i = 0;
? -EFAULT : sizeof events;
}
-
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t len, loff_t *ptr)
{
if (unlikely(ret < 0))
return ret;
-
/* Check state */
if (ffs->state != FFS_ACTIVE) {
ret = -EBADFD;
goto done_mutex;
}
-
- /* We're called from user space, we can use _irq rather then
- * _irqsave */
+ /*
+ * We're called from user space, we can use _irq rather then
+ * _irqsave
+ */
spin_lock_irq(&ffs->ev.waitq.lock);
switch (FFS_SETUP_STATE(ffs)) {
break;
}
- if (unlikely(wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, ffs->ev.count))) {
+ if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
+ ffs->ev.count)) {
ret = -EINTR;
break;
}
return __ffs_ep0_read_events(ffs, buf,
min(n, (size_t)ffs->ev.count));
-
case FFS_SETUP_PENDING:
if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
spin_unlock_irq(&ffs->ev.waitq.lock);
return ret;
}
-
-
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = inode->i_private;
return 0;
}
-
static int ffs_ep0_release(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = file->private_data;
return 0;
}
-
static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
{
struct ffs_data *ffs = file->private_data;
return ret;
}
-
static const struct file_operations ffs_ep0_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
/* "Normal" endpoints operations ********************************************/
-
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
ENTER();
}
}
-
static ssize_t ffs_epfile_io(struct file *file,
char __user *buf, size_t len, int read)
{
goto error;
}
- if (unlikely(wait_event_interruptible
- (epfile->wait, (ep = epfile->ep)))) {
+ if (wait_event_interruptible(epfile->wait,
+ (ep = epfile->ep))) {
ret = -EINTR;
goto error;
}
if (unlikely(ret))
goto error;
- /* We're called from user space, we can use _irq rather then
- * _irqsave */
+ /*
+ * We're called from user space, we can use _irq rather then
+ * _irqsave
+ */
spin_lock_irq(&epfile->ffs->eps_lock);
- /* While we were acquiring mutex endpoint got disabled
- * or changed? */
+ /*
+ * While we were acquiring mutex endpoint got disabled
+ * or changed?
+ */
} while (unlikely(epfile->ep != ep));
/* Halt */
return ret;
}
-
static ssize_t
ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
loff_t *ptr)
return 0;
}
-
static long ffs_epfile_ioctl(struct file *file, unsigned code,
unsigned long value)
{
return ret;
}
-
static const struct file_operations ffs_epfile_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
};
-
/* File system and super block operations ***********************************/
/*
- * Mounting the filesystem creates a controller file, used first for
+ * Mounting the file system creates a controller file, used first for
* function configuration then later for event monitoring.
*/
-
static struct inode *__must_check
ffs_sb_make_inode(struct super_block *sb, void *data,
const struct file_operations *fops,
return inode;
}
-
/* Create "regular" file */
-
static struct inode *ffs_sb_create_file(struct super_block *sb,
const char *name, void *data,
const struct file_operations *fops,
return inode;
}
-
/* Super block */
-
static const struct super_operations ffs_sb_operations = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
ENTER();
- /* Initialize data */
+ /* Initialise data */
ffs = ffs_data_new();
if (unlikely(!ffs))
goto enomem0;
return -ENOMEM;
}
-
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
{
ENTER();
/* Value limit */
eq = strchr(opts, '=');
if (unlikely(!eq)) {
- FERR("'=' missing in %s", opts);
+ pr_err("'=' missing in %s\n", opts);
return -EINVAL;
}
*eq = 0;
/* Parse value */
value = simple_strtoul(eq + 1, &end, 0);
if (unlikely(*end != ',' && *end != 0)) {
- FERR("%s: invalid value: %s", opts, eq + 1);
+ pr_err("%s: invalid value: %s\n", opts, eq + 1);
return -EINVAL;
}
default:
invalid:
- FERR("%s: invalid option", opts);
+ pr_err("%s: invalid option\n", opts);
return -EINVAL;
}
return 0;
}
-
/* "mount -t functionfs dev_name /dev/function" ends up here */
static struct dentry *
};
-
/* Driver's main init/cleanup functions *************************************/
-
static int functionfs_init(void)
{
int ret;
ret = register_filesystem(&ffs_fs_type);
if (likely(!ret))
- FINFO("file system registered");
+ pr_info("file system registered\n");
else
- FERR("failed registering file system (%d)", ret);
+ pr_err("failed registering file system (%d)\n", ret);
return ret;
}
{
ENTER();
- FINFO("unloading");
+ pr_info("unloading\n");
unregister_filesystem(&ffs_fs_type);
}
-
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
static void ffs_data_reset(struct ffs_data *ffs);
-
static void ffs_data_get(struct ffs_data *ffs)
{
ENTER();
ENTER();
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
- FINFO("%s(): freeing", __func__);
+ pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
BUG_ON(mutex_is_locked(&ffs->mutex) ||
spin_is_locked(&ffs->ev.waitq.lock) ||
}
}
-
-
static void ffs_data_closed(struct ffs_data *ffs)
{
ENTER();
ffs_data_put(ffs);
}
-
static struct ffs_data *ffs_data_new(void)
{
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
return ffs;
}
-
static void ffs_data_clear(struct ffs_data *ffs)
{
ENTER();
kfree(ffs->stringtabs);
}
-
static void ffs_data_reset(struct ffs_data *ffs)
{
ENTER();
return 0;
}
-
static void functionfs_unbind(struct ffs_data *ffs)
{
ENTER();
}
}
-
static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
return 0;
}
-
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
kfree(epfiles);
}
-
static int functionfs_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct ffs_data *ffs)
func->function.bind = ffs_func_bind;
func->function.unbind = ffs_func_unbind;
func->function.set_alt = ffs_func_set_alt;
- /*func->function.get_alt = ffs_func_get_alt;*/
func->function.disable = ffs_func_disable;
func->function.setup = ffs_func_setup;
func->function.suspend = ffs_func_suspend;
ffs_data_put(func->ffs);
kfree(func->eps);
- /* eps and interfaces_nums are allocated in the same chunk so
+ /*
+ * eps and interfaces_nums are allocated in the same chunk so
* only one free is required. Descriptors are also allocated
- * in the same chunk. */
+ * in the same chunk.
+ */
kfree(func);
}
-
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
/* Parsing and building descriptors and strings *****************************/
-
- /* This validates if data pointed by data is a valid USB descriptor as
+ /*
+ * This validates if data pointed by data is a valid USB descriptor as
* well as record how many interfaces, endpoints and strings are
- * required by given configuration. Returns address afther the
- * descriptor or NULL if data is invalid. */
+ * required by given configuration. Returns address after the
+ * descriptor or NULL if data is invalid.
+ */
enum ffs_entity_type {
FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
/* At least two bytes are required: length and type */
if (len < 2) {
- FVDBG("descriptor too short");
+ pr_vdebug("descriptor too short\n");
return -EINVAL;
}
/* If we have at least as many bytes as the descriptor takes? */
length = _ds->bLength;
if (len < length) {
- FVDBG("descriptor longer then available data");
+ pr_vdebug("descriptor longer then available data\n");
return -EINVAL;
}
#define __entity_check_STRING(val) (val)
#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
#define __entity(type, val) do { \
- FVDBG("entity " #type "(%02x)", (val)); \
+ pr_vdebug("entity " #type "(%02x)\n", (val)); \
if (unlikely(!__entity_check_ ##type(val))) { \
- FVDBG("invalid entity's value"); \
+ pr_vdebug("invalid entity's value\n"); \
return -EINVAL; \
} \
ret = entity(FFS_ ##type, &val, _ds, priv); \
if (unlikely(ret < 0)) { \
- FDBG("entity " #type "(%02x); ret = %d", \
- (val), ret); \
+ pr_debug("entity " #type "(%02x); ret = %d\n", \
+ (val), ret); \
return ret; \
} \
} while (0)
case USB_DT_STRING:
case USB_DT_DEVICE_QUALIFIER:
/* function can't have any of those */
- FVDBG("descriptor reserved for gadget: %d", _ds->bDescriptorType);
+ pr_vdebug("descriptor reserved for gadget: %d\n",
+ _ds->bDescriptorType);
return -EINVAL;
case USB_DT_INTERFACE: {
struct usb_interface_descriptor *ds = (void *)_ds;
- FVDBG("interface descriptor");
+ pr_vdebug("interface descriptor\n");
if (length != sizeof *ds)
goto inv_length;
case USB_DT_ENDPOINT: {
struct usb_endpoint_descriptor *ds = (void *)_ds;
- FVDBG("endpoint descriptor");
+ pr_vdebug("endpoint descriptor\n");
if (length != USB_DT_ENDPOINT_SIZE &&
length != USB_DT_ENDPOINT_AUDIO_SIZE)
goto inv_length;
case USB_DT_INTERFACE_ASSOCIATION: {
struct usb_interface_assoc_descriptor *ds = (void *)_ds;
- FVDBG("interface association descriptor");
+ pr_vdebug("interface association descriptor\n");
if (length != sizeof *ds)
goto inv_length;
if (ds->iFunction)
case USB_DT_SECURITY:
case USB_DT_CS_RADIO_CONTROL:
/* TODO */
- FVDBG("unimplemented descriptor: %d", _ds->bDescriptorType);
+ pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
return -EINVAL;
default:
/* We should never be here */
- FVDBG("unknown descriptor: %d", _ds->bDescriptorType);
+ pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
return -EINVAL;
- inv_length:
- FVDBG("invalid length: %d (descriptor %d)",
- _ds->bLength, _ds->bDescriptorType);
+ inv_length:
+ pr_vdebug("invalid length: %d (descriptor %d)\n",
+ _ds->bLength, _ds->bDescriptorType);
return -EINVAL;
}
return length;
}
-
static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ffs_entity_callback entity, void *priv)
{
if (num == count)
data = NULL;
- /* Record "descriptor" entitny */
+ /* Record "descriptor" entity */
ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
if (unlikely(ret < 0)) {
- FDBG("entity DESCRIPTOR(%02lx); ret = %d", num, ret);
+ pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
+ num, ret);
return ret;
}
ret = ffs_do_desc(data, len, entity, priv);
if (unlikely(ret < 0)) {
- FDBG("%s returns %d", __func__, ret);
+ pr_debug("%s returns %d\n", __func__, ret);
return ret;
}
}
}
-
static int __ffs_data_do_entity(enum ffs_entity_type type,
u8 *valuep, struct usb_descriptor_header *desc,
void *priv)
break;
case FFS_INTERFACE:
- /* Interfaces are indexed from zero so if we
+ /*
+ * Interfaces are indexed from zero so if we
* encountered interface "n" then there are at least
- * "n+1" interfaces. */
+ * "n+1" interfaces.
+ */
if (*valuep >= ffs->interfaces_count)
ffs->interfaces_count = *valuep + 1;
break;
case FFS_STRING:
- /* Strings are indexed from 1 (0 is magic ;) reserved
- * for languages list or some such) */
+ /*
+ * Strings are indexed from 1 (0 is magic ;) reserved
+ * for languages list or some such)
+ */
if (*valuep > ffs->strings_count)
ffs->strings_count = *valuep;
break;
return 0;
}
-
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{
return ret;
}
-
-
static int __ffs_data_got_strings(struct ffs_data *ffs,
char *const _data, size_t len)
{
if (unlikely(str_count < needed_count))
goto error;
- /* If we don't need any strings just return and free all
- * memory */
+ /*
+ * If we don't need any strings just return and free all
+ * memory.
+ */
if (!needed_count) {
kfree(_data);
return 0;
}
- /* Allocate */
+ /* Allocate everything in one chunk so there's less maintenance. */
{
- /* Allocate everything in one chunk so there's less
- * maintanance. */
struct {
struct usb_gadget_strings *stringtabs[lang_count + 1];
struct usb_gadget_strings stringtab[lang_count];
if (unlikely(length == len))
goto error_free;
- /* user may provide more strings then we need,
- * if that's the case we simply ingore the
- * rest */
+ /*
+ * User may provide more strings then we need,
+ * if that's the case we simply ignore the
+ * rest
+ */
if (likely(needed)) {
- /* s->id will be set while adding
+ /*
+ * s->id will be set while adding
* function to configuration so for
- * now just leave garbage here. */
+ * now just leave garbage here.
+ */
s->s = data;
--needed;
++s;
}
-
-
/* Events handling and management *******************************************/
static void __ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type rem_type1, rem_type2 = type;
int neg = 0;
- /* Abort any unhandled setup */
- /* We do not need to worry about some cmpxchg() changing value
+ /*
+ * Abort any unhandled setup
+ *
+ * We do not need to worry about some cmpxchg() changing value
* of ffs->setup_state without holding the lock because when
* state is FFS_SETUP_PENDING cmpxchg() in several places in
- * the source does nothing. */
+ * the source does nothing.
+ */
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELED;
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
- /* FALL THGOUTH */
+ /* FALL THROUGH */
case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_SETUP:
rem_type1 = type;
- /* discard all similar events */
+ /* Discard all similar events */
break;
case FUNCTIONFS_BIND:
case FUNCTIONFS_UNBIND:
case FUNCTIONFS_DISABLE:
case FUNCTIONFS_ENABLE:
- /* discard everything other then power management. */
+ /* Discard everything other then power management. */
rem_type1 = FUNCTIONFS_SUSPEND;
rem_type2 = FUNCTIONFS_RESUME;
neg = 1;
if ((*ev == rem_type1 || *ev == rem_type2) == neg)
*out++ = *ev;
else
- FVDBG("purging event %d", *ev);
+ pr_vdebug("purging event %d\n", *ev);
ffs->ev.count = out - ffs->ev.types;
}
- FVDBG("adding event %d", type);
+ pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
}
struct ffs_function *func = priv;
struct ffs_ep *ffs_ep;
- /* If hs_descriptors is not NULL then we are reading hs
- * descriptors now */
+ /*
+ * If hs_descriptors is not NULL then we are reading hs
+ * descriptors now
+ */
const int isHS = func->function.hs_descriptors != NULL;
unsigned idx;
ffs_ep = func->eps + idx;
if (unlikely(ffs_ep->descs[isHS])) {
- FVDBG("two %sspeed descriptors for EP %d",
- isHS ? "high" : "full",
- ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ pr_vdebug("two %sspeed descriptors for EP %d\n",
+ isHS ? "high" : "full",
+ ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
return -EINVAL;
}
ffs_ep->descs[isHS] = ds;
struct usb_request *req;
struct usb_ep *ep;
- FVDBG("autoconfig");
+ pr_vdebug("autoconfig\n");
ep = usb_ep_autoconfig(func->gadget, ds);
if (unlikely(!ep))
return -ENOTSUPP;
- ep->driver_data = func->eps + idx;;
+ ep->driver_data = func->eps + idx;
req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (unlikely(!req))
return 0;
}
-
static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
break;
case FFS_ENDPOINT:
- /* USB_DT_ENDPOINT are handled in
- * __ffs_func_bind_do_descs(). */
+ /*
+ * USB_DT_ENDPOINT are handled in
+ * __ffs_func_bind_do_descs().
+ */
if (desc->bDescriptorType == USB_DT_ENDPOINT)
return 0;
break;
}
- FVDBG("%02x -> %02x", *valuep, newValue);
+ pr_vdebug("%02x -> %02x\n", *valuep, newValue);
*valuep = newValue;
return 0;
}
func->eps = data->eps;
func->interfaces_nums = data->inums;
- /* Go throught all the endpoint descriptors and allocate
+ /*
+ * Go through all the endpoint descriptors and allocate
* endpoints first, so that later we can rewrite the endpoint
- * numbers without worying that it may be described later on. */
+ * numbers without worrying that it may be described later on.
+ */
if (likely(full)) {
func->function.descriptors = data->fs_descs;
ret = ffs_do_descs(ffs->fs_descs_count,
__ffs_func_bind_do_descs, func);
}
- /* Now handle interface numbers allocation and interface and
- * enpoint numbers rewritting. We can do that in one go
- * now. */
+ /*
+ * Now handle interface numbers allocation and interface and
+ * endpoint numbers rewriting. We can do that in one go
+ * now.
+ */
ret = ffs_do_descs(ffs->fs_descs_count +
(high ? ffs->hs_descs_count : 0),
data->raw_descs, sizeof data->raw_descs,
ffs_func_free(func);
}
-
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
ENTER();
- FVDBG("creq->bRequestType = %02x", creq->bRequestType);
- FVDBG("creq->bRequest = %02x", creq->bRequest);
- FVDBG("creq->wValue = %04x", le16_to_cpu(creq->wValue));
- FVDBG("creq->wIndex = %04x", le16_to_cpu(creq->wIndex));
- FVDBG("creq->wLength = %04x", le16_to_cpu(creq->wLength));
+ pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
+ pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
+ pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
+ pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex));
+ pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength));
- /* Most requests directed to interface go throught here
+ /*
+ * Most requests directed to interface go through here
* (notable exceptions are set/get interface) so we need to
* handle them. All other either handled by composite or
* passed to usb_configuration->setup() (if one is set). No
* matter, we will handle requests directed to endpoint here
* as well (as it's straightforward) but what to do with any
- * other request? */
-
+ * other request?
+ */
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
}
-
- /* Enpoint and interface numbers reverse mapping ****************************/
+ /* Endpoint and interface numbers reverse mapping ***************************/
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
{
: mutex_lock_interruptible(mutex);
}
-
static char *ffs_prepare_buffer(const char * __user buf, size_t len)
{
char *data;
return ERR_PTR(-EFAULT);
}
- FVDBG("Buffer from user space:");
+ pr_vdebug("Buffer from user space:\n");
ffs_dump_mem("", data, len);
return data;
size += out->maxpacket - 1;
size -= size % out->maxpacket;
+ if (dev->port_usb->is_fixed)
+ size = max(size, dev->port_usb->fixed_out_len);
+
skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
DBG(dev, "no rx skb\n");
req->context = skb;
req->complete = tx_complete;
+ /* NCM requires no zlp if transfer is dwNtbInMaxSize */
+ if (dev->port_usb->is_fixed &&
+ length == dev->port_usb->fixed_in_len &&
+ (length % in->maxpacket) == 0)
+ req->zero = 0;
+ else
+ req->zero = 1;
+
/* use zlp framing on tx for strict CDC-Ether conformance,
* though any robust network rx path ignores extra padding.
* and some hardware doesn't like to write zlps.
*/
- req->zero = 1;
- if (!dev->zlp && (length % in->maxpacket) == 0)
+ if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
length++;
req->length = length;
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- netif_stop_queue(net);
the_dev = dev;
}
bool "Support for Freescale on-chip EHCI USB controller"
depends on USB_EHCI_HCD && FSL_SOC
select USB_EHCI_ROOT_HUB_TT
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
---help---
Variation of ARC USB block used in some Freescale chips.
---help---
Variation of ARC USB block used in some Freescale chips.
+ config USB_EHCI_HCD_OMAP
+ bool "EHCI support for OMAP3 and later chips"
+ depends on USB_EHCI_HCD && ARCH_OMAP
+ default y
+ --- help ---
+ Enables support for the on-chip EHCI controller on
+ OMAP3 and later chips.
+
+ config USB_EHCI_MSM
+ bool "Support for MSM on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && ARCH_MSM
+ select USB_EHCI_ROOT_HUB_TT
+ select USB_MSM_OTG_72K
+ ---help---
+ Enables support for the USB Host controller present on the
+ Qualcomm chipsets. Root Hub has inbuilt TT.
+ This driver depends on OTG driver for PHY initialization,
+ clock management, powering up VBUS, and power management.
+
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
depends on USB_EHCI_HCD && PPC_OF
int ret = 0;
if (!buf->output_buf)
- buf->output_buf = (char *)vmalloc(buf->alloc_size);
+ buf->output_buf = vmalloc(buf->alloc_size);
if (!buf->output_buf) {
ret = -ENOMEM;
&debug_registers_fops))
goto file_error;
- if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
+ if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
&debug_lpm_fops))
goto file_error;
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+ /* for ASPM quirk of ISOC on AMD SB800 */
+ static struct pci_dev *amd_nb_dev;
+
/*-------------------------------------------------------------------------*/
#include "ehci.h"
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
+ if (amd_nb_dev) {
+ pci_dev_put(amd_nb_dev);
+ amd_nb_dev = NULL;
+ }
+
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
tmp && tmp != qh;
tmp = tmp->qh_next.qh)
continue;
- /* periodic qh self-unlinks on empty */
- if (!tmp)
- goto nogood;
- unlink_async (ehci, qh);
+ /* periodic qh self-unlinks on empty, and a COMPLETING qh
+ * may already be unlinked.
+ */
+ if (tmp)
+ unlink_async(ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
}
/* else FALL THROUGH */
default:
-nogood:
/* caller was supposed to have unlinked any requests;
* that's not our job. just leak this memory.
*/
#define PLATFORM_DRIVER ehci_mxc_driver
#endif
+ #ifdef CONFIG_CPU_SUBTYPE_SH7786
+ #include "ehci-sh.c"
+ #define PLATFORM_DRIVER ehci_hcd_sh_driver
+ #endif
+
#ifdef CONFIG_SOC_AU1200
#include "ehci-au1xxx.c"
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
- #ifdef CONFIG_ARCH_OMAP3
+ #ifdef CONFIG_USB_EHCI_HCD_OMAP
#include "ehci-omap.c"
#define PLATFORM_DRIVER ehci_hcd_omap_driver
#endif
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
+ #ifdef CONFIG_ARCH_VT8500
+ #include "ehci-vt8500.c"
+ #define PLATFORM_DRIVER vt8500_ehci_driver
+ #endif
+
+ #ifdef CONFIG_PLAT_SPEAR
+ #include "ehci-spear.c"
+ #define PLATFORM_DRIVER spear_ehci_hcd_driver
+ #endif
+
+ #ifdef CONFIG_USB_EHCI_MSM
+ #include "ehci-msm.c"
+ #define PLATFORM_DRIVER ehci_msm_driver
+ #endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
static int ehci_mxc_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct device *dev = hcd->self.controller;
+ struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
int retval;
/* EHCI registers start at offset 0x100 */
ehci_reset(ehci);
+ /* set up the PORTSCx register */
+ ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
+
+ /* is this really needed? */
+ msleep(10);
+
ehci_port_power(ehci, 0);
return 0;
}
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_mxc_drv_probe(struct platform_device *pdev)
struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd;
struct resource *res;
- int irq, ret, temp;
+ int irq, ret;
struct ehci_mxc_priv *priv;
struct device *dev = &pdev->dev;
clk_enable(priv->ahbclk);
}
- /* set up the PORTSCx register */
- ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
- mdelay(10);
-
/* setup specific usb hw */
ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
if (ret < 0)
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
+ /* defined here to avoid adding to pci_ids.h for single instance use */
+ #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
+
/*-------------------------------------------------------------------------*/
/* called after powerup, by probe or system-pm "wakeup" */
return 0;
}
+ static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci)
+ {
+ struct pci_dev *amd_smbus_dev;
+ u8 rev = 0;
+
+ amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
+ if (!amd_smbus_dev)
+ return 0;
+
+ pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+ if (rev < 0x40) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+ return 0;
+ }
+
+ if (!amd_nb_dev)
+ amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
+ if (!amd_nb_dev)
+ ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
+
+ ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n");
+
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+
+ return 1;
+ }
+
/* called during probe() after chip reset completes */
static int ehci_pci_setup(struct usb_hcd *hcd)
{
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ if (ehci_quirk_amd_SB800(ehci))
+ ehci->amd_l1_fix = 1;
+
retval = ehci_halt(ehci);
if (retval)
return retval;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+ (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+ /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
+ */
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+ "dummy qh workaround\n");
+ }
+
/* data structure init */
retval = ehci_init(hcd);
if (retval)
ehci_info(ehci, "disable lpm for langwell/penwell\n");
ehci->has_lpm = 0;
}
+ if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
+ hcd->has_tt = 1;
+ tdi_reset(ehci);
+ }
break;
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;
+
+ /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+ * fetching device descriptors unless LPM is disabled.
+ * There are also intermittent problems enumerating
+ * devices with PPCD enabled.
+ */
+ case 0x0d9d:
+ ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+ ehci->has_lpm = 0;
+ ehci->has_ppcd = 0;
+ ehci->command &= ~CMD_PPCEE;
+ break;
}
break;
case PCI_VENDOR_ID_VIA:
*/
*prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
- *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+
+ if (!ehci->use_dummy_qh ||
+ *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
+ != EHCI_LIST_END(ehci))
+ *hw_p = *shadow_next_periodic(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+ else
+ *hw_p = ehci->dummy->qh_dma;
}
/* how many of the uframe's 125 usecs are allocated? */
*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
+ #define AB_REG_BAR_LOW 0xe0
+ #define AB_REG_BAR_HIGH 0xe1
+ #define AB_INDX(addr) ((addr) + 0x00)
+ #define AB_DATA(addr) ((addr) + 0x04)
+ #define NB_PCIE_INDX_ADDR 0xe0
+ #define NB_PCIE_INDX_DATA 0xe4
+ #define NB_PIF0_PWRDOWN_0 0x01100012
+ #define NB_PIF0_PWRDOWN_1 0x01100013
+
+ static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable)
+ {
+ u32 addr, addr_low, addr_high, val;
+
+ outb_p(AB_REG_BAR_LOW, 0xcd6);
+ addr_low = inb_p(0xcd7);
+ outb_p(AB_REG_BAR_HIGH, 0xcd6);
+ addr_high = inb_p(0xcd7);
+ addr = addr_high << 8 | addr_low;
+ outl_p(0x30, AB_INDX(addr));
+ outl_p(0x40, AB_DATA(addr));
+ outl_p(0x34, AB_INDX(addr));
+ val = inl_p(AB_DATA(addr));
+
+ if (disable) {
+ val &= ~0x8;
+ val |= (1 << 4) | (1 << 9);
+ } else {
+ val |= 0x8;
+ val &= ~((1 << 4) | (1 << 9));
+ }
+ outl_p(val, AB_DATA(addr));
+
+ if (amd_nb_dev) {
+ addr = NB_PIF0_PWRDOWN_0;
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
+ pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
+ if (disable)
+ val &= ~(0x3f << 7);
+ else
+ val |= 0x3f << 7;
+
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
+
+ addr = NB_PIF0_PWRDOWN_1;
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr);
+ pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val);
+ if (disable)
+ val &= ~(0x3f << 7);
+ else
+ val |= 0x3f << 7;
+
+ pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val);
+ }
+
+ return;
+ }
+
/* fit urb's itds into the selected schedule slot; activate as needed */
static int
itd_link_urb (
urb->interval,
next_uframe >> 3, next_uframe & 0x7);
}
+
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 1);
+ }
+
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill iTDs uframe by uframe */
(void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 0);
+ }
+
if (unlikely(list_is_singular(&stream->td_list))) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
(next_uframe >> 3) & (ehci->periodic_size - 1),
stream->interval, hc32_to_cpu(ehci, stream->splits));
}
+
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 1);
+ }
+
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
/* fill sITDs frame by frame */
(void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
+ if (ehci->amd_l1_fix == 1)
+ ehci_quirk_amd_L1(ehci, 0);
+ }
+
if (list_is_singular(&stream->td_list)) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
* pointer for much longer, if at all.
*/
*q_p = q.itd->itd_next;
- *hw_p = q.itd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.itd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.itd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
* URB completion.
*/
*q_p = q.sitd->sitd_next;
- *hw_p = q.sitd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.sitd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.sitd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
/* async schedule support */
struct ehci_qh *async;
+ struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
unsigned scanning : 1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
+ unsigned amd_l1_fix:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
+ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
#include <linux/poll.h>
#include <linux/compat.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
return length;
}
+ /*
+ * This is the look-ahead pass in case of 'C Zi', when actual_length cannot
+ * be used to determine the length of the whole contiguous buffer.
+ */
+ static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp,
+ struct urb *urb, unsigned int ndesc)
+ {
+ struct usb_iso_packet_descriptor *fp;
+ unsigned int length;
+
+ length = 0;
+ fp = urb->iso_frame_desc;
+ while (ndesc-- != 0) {
+ if (fp->actual_length != 0) {
+ if (fp->offset + fp->actual_length > length)
+ length = fp->offset + fp->actual_length;
+ }
+ fp++;
+ }
+ return length;
+ }
+
static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
{
/*
* Find the maximum allowable length, then allocate space.
*/
+ urb_length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ length = urb_length;
+
if (usb_endpoint_xfer_isoc(epd)) {
if (urb->number_of_packets < 0) {
ndesc = 0;
} else {
ndesc = urb->number_of_packets;
}
+ if (ev_type == 'C' && usb_urb_dir_in(urb))
+ length = mon_bin_collate_isodesc(rp, urb, ndesc);
} else {
ndesc = 0;
}
lendesc = ndesc*sizeof(struct mon_bin_isodesc);
- urb_length = (ev_type == 'S') ?
- urb->transfer_buffer_length : urb->actual_length;
- length = urb_length;
+ /* not an issue unless there's a subtle bug in a HCD somewhere */
+ if (length >= urb->transfer_buffer_length)
+ length = urb->transfer_buffer_length;
if (length >= rp->b_size/5)
length = rp->b_size/5;
#include <linux/list.h>
#include <linux/gpio.h>
#include <linux/io.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "musb_core.h"
#include "blackfin.h"
+ struct bfin_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ };
+ #define glue_to_musb(g) platform_get_drvdata(g->musb)
+
/*
* Load an endpoint's FIFO
*/
}
/* Start sampling ID pin, when plug is removed from MUSB */
- if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
- || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
+ || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+ (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
}
DBG(4, "state is %s\n", otg_state_string(musb));
}
- void musb_platform_enable(struct musb *musb)
+ static void bfin_musb_enable(struct musb *musb)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
}
- void musb_platform_disable(struct musb *musb)
+ static void bfin_musb_disable(struct musb *musb)
{
}
- static void bfin_set_vbus(struct musb *musb, int is_on)
+ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
{
int value = musb->config->gpio_vrsel_active;
if (!is_on)
musb_readb(musb->mregs, MUSB_DEVCTL));
}
- static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
+ static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
- void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+ static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
{
if (!is_otg_enabled(musb) && is_host_enabled(musb))
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
}
- int musb_platform_get_vbus_status(struct musb *musb)
+ static int bfin_musb_get_vbus_status(struct musb *musb)
{
return 0;
}
- int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
{
return -EIO;
}
- int __init musb_platform_init(struct musb *musb, void *board_data)
+ static void bfin_musb_reg_init(struct musb *musb)
{
-
- /*
- * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
- * and OTG HOST modes, while rev 1.1 and greater require PE7 to
- * be low for DEVICE mode and high for HOST mode. We set it high
- * here because we are in host mode
- */
-
- if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
- printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
- musb->config->gpio_vrsel);
- return -ENODEV;
- }
- gpio_direction_output(musb->config->gpio_vrsel, 0);
-
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
- gpio_free(musb->config->gpio_vrsel);
- return -ENODEV;
- }
-
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
}
/* Configure PLL oscillator register */
- bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ bfin_write_USB_PLLOSC_CTRL(0x3080 |
+ ((480/musb->config->clkin) << 1));
SSYNC();
bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
SSYNC();
+ }
+
+ static int bfin_musb_init(struct musb *musb)
+ {
+
+ /*
+ * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
+ * and OTG HOST modes, while rev 1.1 and greater require PE7 to
+ * be low for DEVICE mode and high for HOST mode. We set it high
+ * here because we are in host mode
+ */
+
+ if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
+ printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
+ musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+ gpio_direction_output(musb->config->gpio_vrsel, 0);
+
+ usb_nop_xceiv_register();
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv) {
+ gpio_free(musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+
+ bfin_musb_reg_init(musb);
if (is_host_enabled(musb)) {
- musb->board_set_vbus = bfin_set_vbus;
setup_timer(&musb_conn_timer,
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
- musb->xceiv->set_power = bfin_set_power;
+ musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt;
return 0;
}
- int musb_platform_exit(struct musb *musb)
+ static int bfin_musb_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
usb_nop_xceiv_unregister();
return 0;
}
+
+ static const struct musb_platform_ops bfin_ops = {
+ .init = bfin_musb_init,
+ .exit = bfin_musb_exit,
+
+ .enable = bfin_musb_enable,
+ .disable = bfin_musb_disable,
+
+ .set_mode = bfin_musb_set_mode,
+ .try_idle = bfin_musb_try_idle,
+
+ .vbus_status = bfin_musb_vbus_status,
+ .set_vbus = bfin_musb_set_vbus,
+ };
+
+ static u64 bfin_dmamask = DMA_BIT_MASK(32);
+
+ static int __init bfin_probe(struct platform_device *pdev)
+ {
+ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct platform_device *musb;
+ struct bfin_glue *glue;
+
+ int ret = -ENOMEM;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "failed to allocate glue context\n");
+ goto err0;
+ }
+
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(&pdev->dev, "failed to allocate musb device\n");
+ goto err1;
+ }
+
+ musb->dev.parent = &pdev->dev;
+ musb->dev.dma_mask = &bfin_dmamask;
+ musb->dev.coherent_dma_mask = bfin_dmamask;
+
+ glue->dev = &pdev->dev;
+ glue->musb = musb;
+
+ pdata->platform_ops = &bfin_ops;
+
+ platform_set_drvdata(pdev, glue);
+
+ ret = platform_device_add_resources(musb, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto err2;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform_data\n");
+ goto err2;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register musb device\n");
+ goto err2;
+ }
+
+ return 0;
+
+ err2:
+ platform_device_put(musb);
+
+ err1:
+ kfree(glue);
+
+ err0:
+ return ret;
+ }
+
+ static int __exit bfin_remove(struct platform_device *pdev)
+ {
+ struct bfin_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+ kfree(glue);
+
+ return 0;
+ }
+
+ #ifdef CONFIG_PM
+ static int bfin_suspend(struct device *dev)
+ {
+ struct bfin_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ if (is_host_active(musb))
+ /*
+ * During hibernate gpio_vrsel will change from high to low
+ * low which will generate wakeup event resume the system
+ * immediately. Set it to 0 before hibernate to avoid this
+ * wakeup event.
+ */
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+
+ return 0;
+ }
+
+ static int bfin_resume(struct device *dev)
+ {
+ struct bfin_glue *glue = dev_get_drvdata(dev);
+ struct musb *musb = glue_to_musb(glue);
+
+ bfin_musb_reg_init(musb);
+
+ return 0;
+ }
+
+ static struct dev_pm_ops bfin_pm_ops = {
+ .suspend = bfin_suspend,
+ .resume = bfin_resume,
+ };
+
+ #define DEV_PM_OPS &bfin_pm_op,
+ #else
+ #define DEV_PM_OPS NULL
+ #endif
+
+ static struct platform_driver bfin_driver = {
+ .remove = __exit_p(bfin_remove),
+ .driver = {
+ .name = "musb-bfin",
+ .pm = DEV_PM_OPS,
+ },
+ };
+
+ MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
+ MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
+ MODULE_LICENSE("GPL v2");
+
+ static int __init bfin_init(void)
+ {
+ return platform_driver_probe(&bfin_driver, bfin_probe);
+ }
+ subsys_initcall(bfin_init);
+
+ static void __exit bfin_exit(void)
+ {
+ platform_driver_unregister(&bfin_driver);
+ }
+ module_exit(bfin_exit);
#include <linux/platform_device.h>
#include <linux/io.h>
- #ifdef CONFIG_ARM
- #include <mach/hardware.h>
- #include <mach/memory.h>
- #include <asm/mach-types.h>
- #endif
-
#include "musb_core.h"
-
- #ifdef CONFIG_ARCH_DAVINCI
- #include "davinci.h"
- #endif
-
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
- #define MUSB_DRIVER_NAME "musb_hdrc"
+ #define MUSB_DRIVER_NAME "musb-hdrc"
const char musb_driver_name[] = MUSB_DRIVER_NAME;
MODULE_DESCRIPTION(DRIVER_INFO);
/*-------------------------------------------------------------------------*/
- #if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
+ #if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
/*
* Load an endpoint's FIFO
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
- musb_set_vbus(musb, 0);
+ musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
if (int_usb & MUSB_INTR_SESSREQ) {
void __iomem *mbase = musb->mregs;
- if (devctl & MUSB_DEVCTL_BDEVICE) {
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+ && (devctl & MUSB_DEVCTL_BDEVICE)) {
DBG(3, "SessReq while on B state\n");
return IRQ_HANDLED;
}
musb->ep0_stage = MUSB_EP0_START;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
- musb_set_vbus(musb, 1);
+ musb_platform_set_vbus(musb, 1);
handled = IRQ_HANDLED;
}
/* go through A_WAIT_VFALL then start a new session */
if (!ignore)
- musb_set_vbus(musb, 0);
+ musb_platform_set_vbus(musb, 0);
handled = IRQ_HANDLED;
}
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
musb_generic_disable(musb);
- if (musb->clock)
- clk_put(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
+ if (!is_otg_enabled(musb) && is_host_enabled(musb))
+ usb_remove_hcd(musb_to_hcd(musb));
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ musb_platform_exit(musb);
+
/* FIXME power down */
}
* We don't currently use dynamic fifo setup capability to do anything
* more than selecting one of a bunch of predefined configurations.
*/
- #if defined(CONFIG_USB_TUSB6010) || \
- defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
- || defined(CONFIG_ARCH_OMAP4)
+ #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \
+ || defined(CONFIG_USB_MUSB_AM35X)
static ushort __initdata fifo_mode = 4;
+ #elif defined(CONFIG_USB_MUSB_UX500)
+ static ushort __initdata fifo_mode = 5;
#else
static ushort __initdata fifo_mode = 2;
#endif
struct musb_hw_ep *hw_ep = musb->endpoints + i;
hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
- #ifdef CONFIG_USB_TUSB6010
+ #ifdef CONFIG_USB_MUSB_TUSB6010
hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
hw_ep->fifo_sync_va =
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
+ defined(CONFIG_ARCH_U5500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
}
musb->controller = dev;
+
return musb;
}
spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
- musb->set_clock = plat->set_clock;
musb->min_power = plat->min_power;
-
- /* Clock usage is chip-specific ... functional clock (DaVinci,
- * OMAP2430), or PHY ref (some TUSB6010 boards). All this core
- * code does is make sure a clock handle is available; platform
- * code manages it during start/stop and suspend/resume.
- */
- if (plat->clock) {
- musb->clock = clk_get(dev, plat->clock);
- if (IS_ERR(musb->clock)) {
- status = PTR_ERR(musb->clock);
- musb->clock = NULL;
- goto fail1;
- }
- }
+ musb->ops = plat->platform_ops;
/* The musb_platform_init() call:
* - adjusts musb->mregs and musb->isr if needed,
* - may initialize an integrated tranceiver
* - initializes musb->xceiv, usually by otg_get_transceiver()
- * - activates clocks.
* - stops powering VBUS
- * - assigns musb->board_set_vbus if host mode is enabled
*
* There are various transciever configurations. Blackfin,
* DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
* isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
musb->isr = generic_interrupt;
- status = musb_platform_init(musb, plat->board_data);
+ status = musb_platform_init(musb);
if (status < 0)
- goto fail2;
+ goto fail1;
if (!musb->isr) {
status = -ENODEV;
* Otherwise, wait till the gadget driver hooks up.
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
MUSB_HST_MODE(musb);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ hcd->self.uses_pio_for_control = 1;
DBG(1, "%s mode, status %d, devctl %02x %c\n",
"HOST", status,
musb_readb(musb->mregs, MUSB_DEVCTL),
device_init_wakeup(dev, 0);
musb_platform_exit(musb);
- fail2:
- if (musb->clock)
- clk_put(musb->clock);
-
fail1:
dev_err(musb->controller,
"musb_init_controller failed with status %d\n", status);
static int __init musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- int irq = platform_get_irq(pdev, 0);
+ int irq = platform_get_irq_byname(pdev, "mc");
int status;
struct resource *iomem;
void __iomem *base;
*/
musb_exit_debugfs(musb);
musb_shutdown(pdev);
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- if (musb->board_mode == MUSB_HOST)
- usb_remove_hcd(musb_to_hcd(musb));
-#endif
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
- musb_platform_exit(musb);
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_free(musb);
iounmap(ctrl_base);
#ifdef CONFIG_PM
- static struct musb_context_registers musb_context;
-
- void musb_save_context(struct musb *musb)
+ static void musb_save_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *epio;
if (is_host_enabled(musb)) {
- musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
- musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
- musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
+ musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
+ musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+ musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
}
- musb_context.power = musb_readb(musb_base, MUSB_POWER);
- musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
- musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
- musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
- musb_context.index = musb_readb(musb_base, MUSB_INDEX);
- musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+ musb->context.power = musb_readb(musb_base, MUSB_POWER);
+ musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+ musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+ musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+ musb->context.index = musb_readb(musb_base, MUSB_INDEX);
+ musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
- musb_context.index_regs[i].txmaxp =
+ musb->context.index_regs[i].txmaxp =
musb_readw(epio, MUSB_TXMAXP);
- musb_context.index_regs[i].txcsr =
+ musb->context.index_regs[i].txcsr =
musb_readw(epio, MUSB_TXCSR);
- musb_context.index_regs[i].rxmaxp =
+ musb->context.index_regs[i].rxmaxp =
musb_readw(epio, MUSB_RXMAXP);
- musb_context.index_regs[i].rxcsr =
+ musb->context.index_regs[i].rxcsr =
musb_readw(epio, MUSB_RXCSR);
if (musb->dyn_fifo) {
- musb_context.index_regs[i].txfifoadd =
+ musb->context.index_regs[i].txfifoadd =
musb_read_txfifoadd(musb_base);
- musb_context.index_regs[i].rxfifoadd =
+ musb->context.index_regs[i].rxfifoadd =
musb_read_rxfifoadd(musb_base);
- musb_context.index_regs[i].txfifosz =
+ musb->context.index_regs[i].txfifosz =
musb_read_txfifosz(musb_base);
- musb_context.index_regs[i].rxfifosz =
+ musb->context.index_regs[i].rxfifosz =
musb_read_rxfifosz(musb_base);
}
if (is_host_enabled(musb)) {
- musb_context.index_regs[i].txtype =
+ musb->context.index_regs[i].txtype =
musb_readb(epio, MUSB_TXTYPE);
- musb_context.index_regs[i].txinterval =
+ musb->context.index_regs[i].txinterval =
musb_readb(epio, MUSB_TXINTERVAL);
- musb_context.index_regs[i].rxtype =
+ musb->context.index_regs[i].rxtype =
musb_readb(epio, MUSB_RXTYPE);
- musb_context.index_regs[i].rxinterval =
+ musb->context.index_regs[i].rxinterval =
musb_readb(epio, MUSB_RXINTERVAL);
- musb_context.index_regs[i].txfunaddr =
+ musb->context.index_regs[i].txfunaddr =
musb_read_txfunaddr(musb_base, i);
- musb_context.index_regs[i].txhubaddr =
+ musb->context.index_regs[i].txhubaddr =
musb_read_txhubaddr(musb_base, i);
- musb_context.index_regs[i].txhubport =
+ musb->context.index_regs[i].txhubport =
musb_read_txhubport(musb_base, i);
- musb_context.index_regs[i].rxfunaddr =
+ musb->context.index_regs[i].rxfunaddr =
musb_read_rxfunaddr(musb_base, i);
- musb_context.index_regs[i].rxhubaddr =
+ musb->context.index_regs[i].rxhubaddr =
musb_read_rxhubaddr(musb_base, i);
- musb_context.index_regs[i].rxhubport =
+ musb->context.index_regs[i].rxhubport =
musb_read_rxhubport(musb_base, i);
}
}
-
- musb_platform_save_context(musb, &musb_context);
}
- void musb_restore_context(struct musb *musb)
+ static void musb_restore_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
- musb_platform_restore_context(musb, &musb_context);
-
if (is_host_enabled(musb)) {
- musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
- musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
- musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl);
+ musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
+ musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
+ musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
}
- musb_writeb(musb_base, MUSB_POWER, musb_context.power);
- musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
- musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
- musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
- musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
+ musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+ musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
+ musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
+ musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
+ musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
for (i = 0; i < musb->config->num_eps; ++i) {
epio = musb->endpoints[i].regs;
musb_writew(epio, MUSB_TXMAXP,
- musb_context.index_regs[i].txmaxp);
+ musb->context.index_regs[i].txmaxp);
musb_writew(epio, MUSB_TXCSR,
- musb_context.index_regs[i].txcsr);
+ musb->context.index_regs[i].txcsr);
musb_writew(epio, MUSB_RXMAXP,
- musb_context.index_regs[i].rxmaxp);
+ musb->context.index_regs[i].rxmaxp);
musb_writew(epio, MUSB_RXCSR,
- musb_context.index_regs[i].rxcsr);
+ musb->context.index_regs[i].rxcsr);
if (musb->dyn_fifo) {
musb_write_txfifosz(musb_base,
- musb_context.index_regs[i].txfifosz);
+ musb->context.index_regs[i].txfifosz);
musb_write_rxfifosz(musb_base,
- musb_context.index_regs[i].rxfifosz);
+ musb->context.index_regs[i].rxfifosz);
musb_write_txfifoadd(musb_base,
- musb_context.index_regs[i].txfifoadd);
+ musb->context.index_regs[i].txfifoadd);
musb_write_rxfifoadd(musb_base,
- musb_context.index_regs[i].rxfifoadd);
+ musb->context.index_regs[i].rxfifoadd);
}
if (is_host_enabled(musb)) {
musb_writeb(epio, MUSB_TXTYPE,
- musb_context.index_regs[i].txtype);
+ musb->context.index_regs[i].txtype);
musb_writeb(epio, MUSB_TXINTERVAL,
- musb_context.index_regs[i].txinterval);
+ musb->context.index_regs[i].txinterval);
musb_writeb(epio, MUSB_RXTYPE,
- musb_context.index_regs[i].rxtype);
+ musb->context.index_regs[i].rxtype);
musb_writeb(epio, MUSB_RXINTERVAL,
- musb_context.index_regs[i].rxinterval);
+ musb->context.index_regs[i].rxinterval);
musb_write_txfunaddr(musb_base, i,
- musb_context.index_regs[i].txfunaddr);
+ musb->context.index_regs[i].txfunaddr);
musb_write_txhubaddr(musb_base, i,
- musb_context.index_regs[i].txhubaddr);
+ musb->context.index_regs[i].txhubaddr);
musb_write_txhubport(musb_base, i,
- musb_context.index_regs[i].txhubport);
+ musb->context.index_regs[i].txhubport);
ep_target_regs =
musb_read_target_reg_base(i, musb_base);
musb_write_rxfunaddr(ep_target_regs,
- musb_context.index_regs[i].rxfunaddr);
+ musb->context.index_regs[i].rxfunaddr);
musb_write_rxhubaddr(ep_target_regs,
- musb_context.index_regs[i].rxhubaddr);
+ musb->context.index_regs[i].rxhubaddr);
musb_write_rxhubport(ep_target_regs,
- musb_context.index_regs[i].rxhubport);
+ musb->context.index_regs[i].rxhubport);
}
}
}
unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) {
musb_save_context(musb);
- if (musb->set_clock)
- musb->set_clock(musb->clock, 0);
- else
- clk_disable(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
- if (musb->set_clock)
- musb->set_clock(musb->clock, 1);
- else
- clk_enable(musb->clock);
-
musb_restore_context(musb);
/* for static cmos like DaVinci, register values were preserved
/* ----------------------------------------------------------------------- */
+/* Maps the buffer to dma */
+
+static inline void map_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ request->request.dma = dma_map_single(
+ musb->controller,
+ request->request.buf,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 1;
+ } else {
+ dma_sync_single_for_device(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 0;
+ }
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ DBG(20, "not unmapping a never mapped buffer\n");
+ return;
+ }
+ if (request->mapped) {
+ dma_unmap_single(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->mapped = 0;
+ } else {
+ dma_sync_single_for_cpu(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ }
+}
+
/*
* Immediately complete a request.
*
ep->busy = 1;
spin_unlock(&musb->lock);
- if (is_dma_capable()) {
- if (req->mapped) {
- dma_unmap_single(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->request.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else if (req->request.dma != DMA_ADDR_INVALID)
- dma_sync_single_for_cpu(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
+ if (is_dma_capable() && ep->dma)
+ unmap_dma_buffer(req, musb);
if (request->status == 0)
DBG(5, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
#endif
if (!use_dma) {
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails
+ */
+ if (is_dma_capable() && musb_ep->dma)
+ unmap_dma_buffer(req, musb);
+
musb_write_fifo(musb_ep->hw_ep, fifo_count,
(u8 *) (request->buf + request->actual));
request->actual += fifo_count;
*/
csr |= MUSB_RXCSR_DMAENAB;
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
- csr |= MUSB_RXCSR_AUTOCLEAR;
#ifdef USE_MODE1
+ csr |= MUSB_RXCSR_AUTOCLEAR;
/* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then
*/
musb_writew(epio, MUSB_RXCSR,
csr | MUSB_RXCSR_DMAMODE);
+#else
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
#endif
musb_writew(epio, MUSB_RXCSR, csr);
return;
}
#endif
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails. This buffer is mapped if the
+ * channel allocation is successful
+ */
+ if (is_dma_capable() && musb_ep->dma) {
+ unmap_dma_buffer(req, musb);
+
+ /*
+ * Clear DMAENAB and AUTOCLEAR for the
+ * PIO mode transfer
+ */
+ csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
(request->buf + request->actual));
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
- if ((dma->desired_mode == 0)
+ if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) {
/* ack the read! */
/* incomplete, and not short? wait for next IN packet */
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
- == musb_ep->packet_sz))
+ == musb_ep->packet_sz)) {
+ /* In double buffer case, continue to unload fifo if
+ * there is Rx packet in FIFO.
+ **/
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+ hw_ep->rx_double_buffered)
+ goto exit;
return;
+ }
#endif
musb_g_giveback(musb_ep, request, 0);
if (!request)
return;
}
-
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+exit:
+#endif
/* Analyze request */
rxstate(musb, to_musb_request(request));
}
* likewise high bandwidth periodic tx
*/
/* Set TXMAXP with the FIFO size of the endpoint
- * to disable double buffering mode. Currently, It seems that double
- * buffering has problem if musb RTL revision number < 2.0.
+ * to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
- else
- musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
/* Set RXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
- else
- musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
struct musb_request *request = NULL;
request = kzalloc(sizeof *request, gfp_flags);
- if (request) {
- INIT_LIST_HEAD(&request->request.list);
- request->request.dma = DMA_ADDR_INVALID;
- request->epnum = musb_ep->current_epnum;
- request->ep = musb_ep;
+ if (!request) {
+ DBG(4, "not enough memory\n");
+ return NULL;
}
+ INIT_LIST_HEAD(&request->request.list);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->epnum = musb_ep->current_epnum;
+ request->ep = musb_ep;
+
return &request->request;
}
request->epnum = musb_ep->current_epnum;
request->tx = musb_ep->is_in;
- if (is_dma_capable() && musb_ep->dma) {
- if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
- musb->controller,
- request->request.buf,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 1;
- } else {
- dma_sync_single_for_device(musb->controller,
- request->request.dma,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 0;
- }
- } else if (!req->buf) {
- return -ENODATA;
- } else
+ if (is_dma_capable() && musb_ep->dma)
+ map_dma_buffer(request, musb);
+ else
request->mapped = 0;
spin_lock_irqsave(&musb->lock, lockflags);
musb_platform_try_idle(musb, 0);
status = device_register(&musb->g.dev);
- if (status != 0)
+ if (status != 0) {
+ put_device(&musb->g.dev);
the_gadget = NULL;
+ }
return status;
}
spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
DBG(3, "OTG startup...\n");
/* REVISIT: funcall to other code, which also
musb->gadget_driver = NULL;
musb->g.dev.driver = NULL;
spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ hcd->self.uses_pio_for_control = 1;
}
}
}
#define MUSB_TESTMODE 0x0F /* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
- #ifdef CONFIG_USB_TUSB6010
+ #ifdef CONFIG_USB_MUSB_TUSB6010
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
#else
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(0x100 + (0x10*(_epnum)) + (_offset))
- #ifdef CONFIG_USB_TUSB6010
+ #ifdef CONFIG_USB_MUSB_TUSB6010
/* TUSB6010 EP0 configuration register is special */
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
(0x10 + _offset)
return 0;
}
-static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
{
+ return 0;
}
#endif /* CONFIG_BLACKFIN */
dma_addr_t dma_addr, u32 len)
{
struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ struct musb *musb = controller->private_data;
DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
musb_channel->epnum,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * It ends up masking the last two bits of the address
+ * programmed in DMA_ADDR.
+ *
+ * Fail such DMA transfers, so that the backup PIO mode
+ * can carry out the transfer
+ */
+ if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4))
+ return false;
+
channel->actual_len = 0;
musb_channel->start_addr = dma_addr;
musb_channel->len = len;
struct musb_dma_controller *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
- int irq = platform_get_irq(pdev, 1);
+ int irq = platform_get_irq_byname(pdev, "dma");
if (irq == 0) {
dev_err(dev, "No DMA interrupt line!\n");
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
.set_termios = usb_wwan_set_termios,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
+ .ioctl = usb_wwan_ioctl,
.attach = usb_wwan_startup,
.disconnect = usb_wwan_disconnect,
.release = usb_wwan_release,
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
};
+ /*
+ * Also used for the Read Ready and Write Ready IUs since they have the
+ * same first four bytes
+ */
struct sense_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__be16 status_qual;
__u8 status;
- __u8 service_response;
- __u8 rsvd8[6];
+ __u8 rsvd7[7];
__be16 len;
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
};
enum {
- ALLOC_SENSE_URB = (1 << 0),
- SUBMIT_SENSE_URB = (1 << 1),
+ ALLOC_STATUS_URB = (1 << 0),
+ SUBMIT_STATUS_URB = (1 << 1),
ALLOC_DATA_IN_URB = (1 << 2),
SUBMIT_DATA_IN_URB = (1 << 3),
ALLOC_DATA_OUT_URB = (1 << 4),
unsigned int state;
unsigned int stream;
struct urb *cmd_urb;
- struct urb *sense_urb;
+ struct urb *status_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
struct list_head list;
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
- uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_KERNEL);
+ uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
}
}
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err;
- cmdinfo->state = direction | SUBMIT_SENSE_URB;
+ cmdinfo->state = direction | SUBMIT_STATUS_URB;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
spin_lock(&uas_work_lock);
if (!urb)
goto out;
- iu = kmalloc(sizeof(*iu), gfp);
+ iu = kzalloc(sizeof(*iu), gfp);
if (!iu)
goto free;
if (len < 0)
len = 0;
len = ALIGN(len, 4);
- iu = kmalloc(sizeof(*iu) + len, gfp);
+ iu = kzalloc(sizeof(*iu) + len, gfp);
if (!iu)
goto free;
iu->iu_id = IU_ID_COMMAND;
iu->tag = cpu_to_be16(stream_id);
- if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER))
- iu->prio_attr = UAS_ORDERED_TAG;
- else
- iu->prio_attr = UAS_SIMPLE_TAG;
+ iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
{
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
- if (cmdinfo->state & ALLOC_SENSE_URB) {
- cmdinfo->sense_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
- cmdinfo->stream);
- if (!cmdinfo->sense_urb)
+ if (cmdinfo->state & ALLOC_STATUS_URB) {
+ cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
+ cmdinfo->stream);
+ if (!cmdinfo->status_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
- cmdinfo->state &= ~ALLOC_SENSE_URB;
+ cmdinfo->state &= ~ALLOC_STATUS_URB;
}
- if (cmdinfo->state & SUBMIT_SENSE_URB) {
- if (usb_submit_urb(cmdinfo->sense_urb, gfp)) {
+ if (cmdinfo->state & SUBMIT_STATUS_URB) {
+ if (usb_submit_urb(cmdinfo->status_urb, gfp)) {
scmd_printk(KERN_INFO, cmnd,
"sense urb submission failure\n");
return SCSI_MLQUEUE_DEVICE_BUSY;
}
- cmdinfo->state &= ~SUBMIT_SENSE_URB;
+ cmdinfo->state &= ~SUBMIT_STATUS_URB;
}
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
return 0;
}
-static int uas_queuecommand(struct scsi_cmnd *cmnd,
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmnd->device;
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
- if (!cmdinfo->sense_urb && sdev->current_cmnd)
+ if (!cmdinfo->status_urb && sdev->current_cmnd)
return SCSI_MLQUEUE_DEVICE_BUSY;
if (blk_rq_tagged(cmnd->request)) {
cmnd->scsi_done = done;
- cmdinfo->state = ALLOC_SENSE_URB | SUBMIT_SENSE_URB |
+ cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB |
ALLOC_CMD_URB | SUBMIT_CMD_URB;
switch (cmnd->sc_data_direction) {
err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
if (err) {
/* If we did nothing, give up now */
- if (cmdinfo->state & SUBMIT_SENSE_URB) {
- usb_free_urb(cmdinfo->sense_urb);
+ if (cmdinfo->state & SUBMIT_STATUS_URB) {
+ usb_free_urb(cmdinfo->status_urb);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
spin_lock(&uas_work_lock);
return 0;
}
+static DEF_SCSI_QCMD(uas_queuecommand)
+
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
{
struct scsi_device *sdev = cmnd->device;
};
MODULE_DEVICE_TABLE(usb, uas_usb_ids);
+ static int uas_is_interface(struct usb_host_interface *intf)
+ {
+ return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
+ intf->desc.bInterfaceProtocol == USB_PR_UAS);
+ }
+
+ static int uas_switch_interface(struct usb_device *udev,
+ struct usb_interface *intf)
+ {
+ int i;
+
+ if (uas_is_interface(intf->cur_altsetting))
+ return 0;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ struct usb_host_interface *alt = &intf->altsetting[i];
+ if (alt == intf->cur_altsetting)
+ continue;
+ if (uas_is_interface(alt))
+ return usb_set_interface(udev,
+ alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return -ENODEV;
+ }
+
static void uas_configure_endpoints(struct uas_dev_info *devinfo)
{
struct usb_host_endpoint *eps[4] = { };
struct uas_dev_info *devinfo;
struct usb_device *udev = interface_to_usbdev(intf);
- if (id->bInterfaceProtocol == 0x50) {
- int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
- /* XXX: Shouldn't assume that 1 is the alternative we want */
- int ret = usb_set_interface(udev, ifnum, 1);
- if (ret)
- return -ENODEV;
- }
+ if (uas_switch_interface(udev, intf))
+ return -ENODEV;
devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
if (!devinfo)
#include <linux/completion.h> /* for struct completion */
#include <linux/sched.h> /* for current && schedule_timeout */
#include <linux/mutex.h> /* for struct mutex */
+ #include <linux/pm_runtime.h> /* for runtime PM */
struct usb_device;
struct usb_driver;
int busnum; /* Bus number (in order of reg) */
const char *bus_name; /* stable id (PCI slot_name etc) */
u8 uses_dma; /* Does the host controller use DMA? */
+ u8 uses_pio_for_control; /*
+ * Does the host controller use PIO
+ * for control transfers?
+ */
u8 otg_port; /* 0, or number of OTG/HNP port */
unsigned is_b_host:1; /* true during some HNP roleswitches */
unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
* @quirks: quirks of the whole device
* @urbnum: number of URBs submitted for the whole device
* @active_duration: total time device is not suspended
- * @last_busy: time of last use
- * @autosuspend_delay: in jiffies
* @connect_time: time device was first connected
* @do_remote_wakeup: remote wakeup should be enabled
* @reset_resume: needs reset instead of resume
unsigned long active_duration;
#ifdef CONFIG_PM
- unsigned long last_busy;
- int autosuspend_delay;
unsigned long connect_time;
unsigned do_remote_wakeup:1;
static inline void usb_mark_last_busy(struct usb_device *udev)
{
- udev->last_busy = jiffies;
+ pm_runtime_mark_last_busy(&udev->dev);
}
#else
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.
- * @ioctl: Used for drivers that want to talk to userspace through
+ * @unlocked_ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem.
* Inventra (Multidrop) Highspeed Dual-Role Controllers: (M)HDRC.
*
* Board initialization should put one of these into dev->platform_data,
- * probably on some platform_device named "musb_hdrc". It encapsulates
+ * probably on some platform_device named "musb-hdrc". It encapsulates
* key configuration differences between boards.
*/
/* A GPIO controlling VRSEL in Blackfin */
unsigned int gpio_vrsel;
unsigned int gpio_vrsel_active;
+ /* musb CLKIN in Blackfin in MHZ */
+ unsigned char clkin;
#endif
};
/* Power the device on or off */
int (*set_power)(int state);
- /* Turn device clock on or off */
- int (*set_clock)(struct clk *clock, int is_on);
-
/* MUSB configuration-specific details */
struct musb_hdrc_config *config;
/* Architecture specific board data */
void *board_data;
+
+ /* Platform specific struct musb_ops pointer */
+ const void *platform_ops;
};