/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "common.h"
/*
*** HARDWARE LIMITATION ***
*
* 1) renesas_usbhs has a limited number of controllable devices.
* it can control only 9 devices in generally.
* see DEVADDn / DCPMAXP / PIPEMAXP.
*
* 2) renesas_usbhs pipe number is limited.
* the pipe will be re-used for each devices.
* so, software should control DATA0/1 sequence of each devices.
*/
/*
* image of mod_host
*
* +--------+
* | udev 0 | --> it is used when set address
* +--------+
*
* +--------+ pipes are reused for each uep.
* | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when
* +--------+ | | target device was changed
* +- [uep 1 (bulk)] --|---+ +--------------+
* | +--------------> | pipe0 (dcp) |
* +- [uep 2 (bulk)] --|---|---+ +--------------+
* | | | | pipe1 (isoc) |
* +--------+ | | | +--------------+
* | udev 2 |-+- [uep 0 (dcp) ] --+ +-- |------> | pipe2 (bulk) |
* +--------+ | | | | +--------------+
* +- [uep 1 (int) ] --|-+ | +------> | pipe3 (bulk) |
* | | | | +--------------+
* +--------+ | +-|---|------> | pipe4 (int) |
* | udev 3 |-+- [uep 0 (dcp) ] --+ | | +--------------+
* +--------+ | | | | .... |
* +- [uep 1 (bulk)] ------+ | | .... |
* | |
* +- [uep 2 (bulk)]-----------+
*/
/*
* struct
*/
struct usbhsh_pipe_info {
unsigned int usr_cnt; /* see usbhsh_endpoint_alloc() */
};
struct usbhsh_request {
struct urb *urb;
struct usbhs_pkt pkt;
struct list_head ureq_link; /* see hpriv :: ureq_link_xxx */
};
struct usbhsh_device {
struct usb_device *usbv;
struct list_head ep_list_head; /* list of usbhsh_ep */
};
struct usbhsh_ep {
struct usbhs_pipe *pipe;
struct usbhsh_device *udev; /* attached udev */
struct list_head ep_list; /* list to usbhsh_device */
int maxp;
};
#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
#define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */
struct usbhsh_hpriv {
struct usbhs_mod mod;
struct usbhs_pipe *dcp;
struct usbhsh_device udev[USBHSH_DEVICE_MAX];
struct usbhsh_pipe_info *pipe_info;
int pipe_size;
u32 port_stat; /* USB_PORT_STAT_xxx */
struct completion *done;
/* see usbhsh_req_alloc/free */
struct list_head ureq_link_active;
struct list_head ureq_link_free;
};
static const char usbhsh_hcd_name[] = "renesas_usbhs host";
/*
* macro
*/
#define usbhsh_priv_to_hpriv(priv) \
container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
#define __usbhsh_for_each_hpipe(start, pos, h, i) \
for (i = start, pos = (h)->hpipe + i; \
i < (h)->hpipe_size; \
i++, pos = (h)->hpipe + i)
#define usbhsh_for_each_hpipe(pos, hpriv, i) \
__usbhsh_for_each_hpipe(1, pos, hpriv, i)
#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i) \
__usbhsh_for_each_hpipe(0, pos, hpriv, i)
#define __usbhsh_for_each_udev(start, pos, h, i) \
for (i = start, pos = (h)->udev + i; \
i < USBHSH_DEVICE_MAX; \
i++, pos = (h)->udev + i)
#define usbhsh_for_each_udev(pos, hpriv, i) \
__usbhsh_for_each_udev(1, pos, hpriv, i)
#define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \
__usbhsh_for_each_udev(0, pos, hpriv, i)
#define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv)
#define usbhsh_hcd_to_dev(h) ((h)->self.controller)
#define usbhsh_hpriv_to_priv(h) ((h)->mod.priv)
#define usbhs