mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	usb: renesas_usbhs: Add Renesas USBHS common code
Renesas SuperH has USBHS IP which can switch Host / Function. This driver is designed so that Host / Function may dynamically change. This patch add usb/renesas_usbhs and common code for SuperH USBHS. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
		
							parent
							
								
									a6360dd37e
								
							
						
					
					
						commit
						f1407d5c66
					
				
					 11 changed files with 2145 additions and 0 deletions
				
			
		| 
						 | 
					@ -67,6 +67,7 @@ obj-$(CONFIG_UWB)		+= uwb/
 | 
				
			||||||
obj-$(CONFIG_USB_OTG_UTILS)	+= usb/otg/
 | 
					obj-$(CONFIG_USB_OTG_UTILS)	+= usb/otg/
 | 
				
			||||||
obj-$(CONFIG_USB)		+= usb/
 | 
					obj-$(CONFIG_USB)		+= usb/
 | 
				
			||||||
obj-$(CONFIG_USB_MUSB_HDRC)	+= usb/musb/
 | 
					obj-$(CONFIG_USB_MUSB_HDRC)	+= usb/musb/
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_RENESAS_USBHS)	+= usb/renesas_usbhs/
 | 
				
			||||||
obj-$(CONFIG_PCI)		+= usb/
 | 
					obj-$(CONFIG_PCI)		+= usb/
 | 
				
			||||||
obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 | 
					obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 | 
				
			||||||
obj-$(CONFIG_SERIO)		+= input/serio/
 | 
					obj-$(CONFIG_SERIO)		+= input/serio/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,6 +115,8 @@ source "drivers/usb/host/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/musb/Kconfig"
 | 
					source "drivers/usb/musb/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "drivers/usb/renesas_usbhs/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/class/Kconfig"
 | 
					source "drivers/usb/class/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/storage/Kconfig"
 | 
					source "drivers/usb/storage/Kconfig"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								drivers/usb/renesas_usbhs/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								drivers/usb/renesas_usbhs/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Renesas USB Controller Drivers
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_RENESAS_USBHS
 | 
				
			||||||
 | 
						tristate 'Renesas USBHS controller'
 | 
				
			||||||
 | 
						default n
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						   Renesas USBHS is a discrete USB host and peripheral controller chip
 | 
				
			||||||
 | 
						   that supports both full and high speed USB 2.0 data transfers.
 | 
				
			||||||
 | 
						   It has nine or more configurable endpoints, and endpoint zero.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						   Say "y" to link the driver statically, or "m" to build a
 | 
				
			||||||
 | 
						   dynamically linked module called "renesas_usbhs" and force all
 | 
				
			||||||
 | 
						   gadget drivers to also be dynamically linked.
 | 
				
			||||||
							
								
								
									
										7
									
								
								drivers/usb/renesas_usbhs/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								drivers/usb/renesas_usbhs/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# for Renesas USB
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					renesas_usbhs-y			:= common.o mod.o pipe.o
 | 
				
			||||||
							
								
								
									
										394
									
								
								drivers/usb/renesas_usbhs/common.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								drivers/usb/renesas_usbhs/common.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,394 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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/module.h>
 | 
				
			||||||
 | 
					#include <linux/pm_runtime.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/sysfs.h>
 | 
				
			||||||
 | 
					#include "./common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * platform call back
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * renesas usb support platform callback function.
 | 
				
			||||||
 | 
					 * Below macro call it.
 | 
				
			||||||
 | 
					 * if platform doesn't have callback, it return 0 (no error)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbhs_platform_call(priv, func, args...)\
 | 
				
			||||||
 | 
						(!(priv) ? -ENODEV :			\
 | 
				
			||||||
 | 
						 !((priv)->pfunc->func) ? 0 :		\
 | 
				
			||||||
 | 
						 (priv)->pfunc->func(args))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		common functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					u16 usbhs_read(struct usbhs_priv *priv, u32 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ioread16(priv->base + reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						iowrite16(data, priv->base + reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 val = usbhs_read(priv, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val &= ~mask;
 | 
				
			||||||
 | 
						val |= data & mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, reg, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		syscfg functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 mask = DCFM | DRPD | DPRPU;
 | 
				
			||||||
 | 
						u16 val  = DCFM | DRPD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * if enable
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * - select Host mode
 | 
				
			||||||
 | 
						 * - D+ Line/D- Line Pull-down
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 mask = DCFM | DRPD | DPRPU;
 | 
				
			||||||
 | 
						u16 val  = DPRPU;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * if enable
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * - select Function mode
 | 
				
			||||||
 | 
						 * - D+ Line Pull-up
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		frame functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_frame_get_num(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return usbhs_read(priv, FRMNUM) & FRNM_MASK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		local functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct usbhs_priv *usbhsc_pdev_to_priv(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev_get_drvdata(&pdev->dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usbhsc_bus_ctrl(struct usbhs_priv *priv, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int wait = usbhs_get_dparam(priv, buswait_bwait);
 | 
				
			||||||
 | 
						u16 data = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable) {
 | 
				
			||||||
 | 
							/* set bus wait if platform have */
 | 
				
			||||||
 | 
							if (wait)
 | 
				
			||||||
 | 
								usbhs_bset(priv, BUSWAIT, 0x000F, wait);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						usbhs_write(priv, DVSTCTR, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		platform default param
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static u32 usbhsc_default_pipe_type[] = {
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_CONTROL,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_ISOC,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_ISOC,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_BULK,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_BULK,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_BULK,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_INT,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_INT,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_INT,
 | 
				
			||||||
 | 
							USB_ENDPOINT_XFER_INT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		driver callback functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsc_notify_hotplug(struct work_struct *work)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = container_of(work,
 | 
				
			||||||
 | 
										       struct usbhs_priv,
 | 
				
			||||||
 | 
										       notify_hotplug_work);
 | 
				
			||||||
 | 
						struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 | 
				
			||||||
 | 
						struct usbhs_mod *mod = usbhs_mod_get_current(priv);
 | 
				
			||||||
 | 
						int id;
 | 
				
			||||||
 | 
						int enable;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * get vbus status from platform
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						enable = usbhs_platform_call(priv, get_vbus, pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * get id from platform
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						id = usbhs_platform_call(priv, get_id, pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable && !mod) {
 | 
				
			||||||
 | 
							ret = usbhs_mod_change(priv, id);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dev_dbg(&pdev->dev, "%s enable\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* enable PM */
 | 
				
			||||||
 | 
							pm_runtime_get_sync(&pdev->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* USB on */
 | 
				
			||||||
 | 
							usbhs_sys_clock_ctrl(priv, enable);
 | 
				
			||||||
 | 
							usbhsc_bus_ctrl(priv, enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* module start */
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, start, priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else if (!enable && mod) {
 | 
				
			||||||
 | 
							dev_dbg(&pdev->dev, "%s disable\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* module stop */
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, stop, priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* USB off */
 | 
				
			||||||
 | 
							usbhsc_bus_ctrl(priv, enable);
 | 
				
			||||||
 | 
							usbhs_sys_clock_ctrl(priv, enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* disable PM */
 | 
				
			||||||
 | 
							pm_runtime_put_sync(&pdev->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							usbhs_mod_change(priv, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* reset phy for next connection */
 | 
				
			||||||
 | 
							usbhs_platform_call(priv, phy_reset, pdev);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsc_pdev_to_priv(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This functions will be called in interrupt.
 | 
				
			||||||
 | 
						 * To make sure safety context,
 | 
				
			||||||
 | 
						 * use workqueue for usbhs_notify_hotplug
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						schedule_work(&priv->notify_hotplug_work);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		platform functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int __devinit usbhs_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
 | 
				
			||||||
 | 
						struct renesas_usbhs_driver_callback *dfunc;
 | 
				
			||||||
 | 
						struct usbhs_priv *priv;
 | 
				
			||||||
 | 
						struct resource *res;
 | 
				
			||||||
 | 
						unsigned int irq;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check platform information */
 | 
				
			||||||
 | 
						if (!info ||
 | 
				
			||||||
 | 
						    !info->platform_callback.get_id ||
 | 
				
			||||||
 | 
						    !info->platform_callback.get_vbus) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "no platform information\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* platform data */
 | 
				
			||||||
 | 
						res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
 | 
						irq = platform_get_irq(pdev, 0);
 | 
				
			||||||
 | 
						if (!res || (int)irq <= 0) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* usb private data */
 | 
				
			||||||
 | 
						priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!priv) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "Could not allocate priv\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->base = ioremap_nocache(res->start, resource_size(res));
 | 
				
			||||||
 | 
						if (!priv->base) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "ioremap error.\n");
 | 
				
			||||||
 | 
							ret = -ENOMEM;
 | 
				
			||||||
 | 
							goto probe_end_kfree;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * care platform info
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						priv->pfunc	= &info->platform_callback;
 | 
				
			||||||
 | 
						priv->dparam	= &info->driver_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set driver callback functions for platform */
 | 
				
			||||||
 | 
						dfunc			= &info->driver_callback;
 | 
				
			||||||
 | 
						dfunc->notify_hotplug	= usbhsc_drvcllbck_notify_hotplug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set default param if platform doesn't have */
 | 
				
			||||||
 | 
						if (!priv->dparam->pipe_type) {
 | 
				
			||||||
 | 
							priv->dparam->pipe_type = usbhsc_default_pipe_type;
 | 
				
			||||||
 | 
							priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * priv settings
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						priv->irq	= irq;
 | 
				
			||||||
 | 
						priv->pdev	= pdev;
 | 
				
			||||||
 | 
						INIT_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
 | 
				
			||||||
 | 
						spin_lock_init(usbhs_priv_to_lock(priv));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* call pipe and module init */
 | 
				
			||||||
 | 
						ret = usbhs_pipe_probe(priv);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto probe_end_mod_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhs_mod_probe(priv);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto probe_end_iounmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* dev_set_drvdata should be called after usbhs_mod_init */
 | 
				
			||||||
 | 
						dev_set_drvdata(&pdev->dev, priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * deviece reset here because
 | 
				
			||||||
 | 
						 * USB device might be used in boot loader.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_sys_clock_ctrl(priv, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * platform call
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * USB phy setup might depend on CPU/Board.
 | 
				
			||||||
 | 
						 * If platform has its callback functions,
 | 
				
			||||||
 | 
						 * call it here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ret = usbhs_platform_call(priv, hardware_init, pdev);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "platform prove failed.\n");
 | 
				
			||||||
 | 
							goto probe_end_pipe_exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reset phy for connection */
 | 
				
			||||||
 | 
						usbhs_platform_call(priv, phy_reset, pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * manual call notify_hotplug for cold plug
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pm_runtime_enable(&pdev->dev);
 | 
				
			||||||
 | 
						ret = usbhsc_drvcllbck_notify_hotplug(pdev);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto probe_end_call_remove;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_info(&pdev->dev, "probed\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					probe_end_call_remove:
 | 
				
			||||||
 | 
						usbhs_platform_call(priv, hardware_exit, pdev);
 | 
				
			||||||
 | 
					probe_end_pipe_exit:
 | 
				
			||||||
 | 
						usbhs_pipe_remove(priv);
 | 
				
			||||||
 | 
					probe_end_mod_exit:
 | 
				
			||||||
 | 
						usbhs_mod_remove(priv);
 | 
				
			||||||
 | 
					probe_end_iounmap:
 | 
				
			||||||
 | 
						iounmap(priv->base);
 | 
				
			||||||
 | 
					probe_end_kfree:
 | 
				
			||||||
 | 
						kfree(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_info(&pdev->dev, "probe failed\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __devexit usbhs_remove(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsc_pdev_to_priv(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(&pdev->dev, "usb remove\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pm_runtime_disable(&pdev->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsc_bus_ctrl(priv, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_platform_call(priv, hardware_exit, pdev);
 | 
				
			||||||
 | 
						usbhs_pipe_remove(priv);
 | 
				
			||||||
 | 
						usbhs_mod_remove(priv);
 | 
				
			||||||
 | 
						iounmap(priv->base);
 | 
				
			||||||
 | 
						kfree(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver renesas_usbhs_driver = {
 | 
				
			||||||
 | 
						.driver		= {
 | 
				
			||||||
 | 
							.name	= "renesas_usbhs",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.probe		= usbhs_probe,
 | 
				
			||||||
 | 
						.remove		= __devexit_p(usbhs_remove),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init usbhs_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return platform_driver_register(&renesas_usbhs_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit usbhs_exit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						platform_driver_unregister(&renesas_usbhs_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_init(usbhs_init);
 | 
				
			||||||
 | 
					module_exit(usbhs_exit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Renesas USB driver");
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 | 
				
			||||||
							
								
								
									
										225
									
								
								drivers/usb/renesas_usbhs/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								drivers/usb/renesas_usbhs/common.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,225 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef RENESAS_USB_DRIVER_H
 | 
				
			||||||
 | 
					#define RENESAS_USB_DRIVER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/usb/renesas_usbhs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "./mod.h"
 | 
				
			||||||
 | 
					#include "./pipe.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *		register define
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define SYSCFG		0x0000
 | 
				
			||||||
 | 
					#define BUSWAIT		0x0002
 | 
				
			||||||
 | 
					#define DVSTCTR		0x0008
 | 
				
			||||||
 | 
					#define CFIFO		0x0014
 | 
				
			||||||
 | 
					#define CFIFOSEL	0x0020
 | 
				
			||||||
 | 
					#define CFIFOCTR	0x0022
 | 
				
			||||||
 | 
					#define INTENB0		0x0030
 | 
				
			||||||
 | 
					#define INTENB1		0x0032
 | 
				
			||||||
 | 
					#define BRDYENB		0x0036
 | 
				
			||||||
 | 
					#define NRDYENB		0x0038
 | 
				
			||||||
 | 
					#define BEMPENB		0x003A
 | 
				
			||||||
 | 
					#define INTSTS0		0x0040
 | 
				
			||||||
 | 
					#define INTSTS1		0x0042
 | 
				
			||||||
 | 
					#define BRDYSTS		0x0046
 | 
				
			||||||
 | 
					#define NRDYSTS		0x0048
 | 
				
			||||||
 | 
					#define BEMPSTS		0x004A
 | 
				
			||||||
 | 
					#define FRMNUM		0x004C
 | 
				
			||||||
 | 
					#define USBREQ		0x0054	/* USB request type register */
 | 
				
			||||||
 | 
					#define USBVAL		0x0056	/* USB request value register */
 | 
				
			||||||
 | 
					#define USBINDX		0x0058	/* USB request index register */
 | 
				
			||||||
 | 
					#define USBLENG		0x005A	/* USB request length register */
 | 
				
			||||||
 | 
					#define DCPCFG		0x005C
 | 
				
			||||||
 | 
					#define DCPMAXP		0x005E
 | 
				
			||||||
 | 
					#define DCPCTR		0x0060
 | 
				
			||||||
 | 
					#define PIPESEL		0x0064
 | 
				
			||||||
 | 
					#define PIPECFG		0x0068
 | 
				
			||||||
 | 
					#define PIPEBUF		0x006A
 | 
				
			||||||
 | 
					#define PIPEMAXP	0x006C
 | 
				
			||||||
 | 
					#define PIPEPERI	0x006E
 | 
				
			||||||
 | 
					#define PIPEnCTR	0x0070
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* SYSCFG */
 | 
				
			||||||
 | 
					#define SCKE	(1 << 10)	/* USB Module Clock Enable */
 | 
				
			||||||
 | 
					#define HSE	(1 << 7)	/* High-Speed Operation Enable */
 | 
				
			||||||
 | 
					#define DCFM	(1 << 6)	/* Controller Function Select */
 | 
				
			||||||
 | 
					#define DRPD	(1 << 5)	/* D+ Line/D- Line Resistance Control */
 | 
				
			||||||
 | 
					#define DPRPU	(1 << 4)	/* D+ Line Resistance Control */
 | 
				
			||||||
 | 
					#define USBE	(1 << 0)	/* USB Module Operation Enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* DVSTCTR */
 | 
				
			||||||
 | 
					#define EXTLP	(1 << 10)	/* Controls the EXTLP pin output state */
 | 
				
			||||||
 | 
					#define PWEN	(1 << 9)	/* Controls the PWEN pin output state */
 | 
				
			||||||
 | 
					#define RHST	(0x7)		/* Reset Handshake */
 | 
				
			||||||
 | 
					#define  RHST_LOW_SPEED  1	/* Low-speed connection */
 | 
				
			||||||
 | 
					#define  RHST_FULL_SPEED 2	/* Full-speed connection */
 | 
				
			||||||
 | 
					#define  RHST_HIGH_SPEED 3	/* High-speed connection */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CFIFOSEL */
 | 
				
			||||||
 | 
					#define MBW_32	(0x2 << 10)	/* CFIFO Port Access Bit Width */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CFIFOCTR */
 | 
				
			||||||
 | 
					#define BVAL	(1 << 15)	/* Buffer Memory Enable Flag */
 | 
				
			||||||
 | 
					#define BCLR	(1 << 14)	/* CPU buffer clear */
 | 
				
			||||||
 | 
					#define FRDY	(1 << 13)	/* FIFO Port Ready */
 | 
				
			||||||
 | 
					#define DTLN_MASK (0x0FFF)	/* Receive Data Length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTENB0 */
 | 
				
			||||||
 | 
					#define VBSE	(1 << 15)	/* Enable IRQ VBUS_0 and VBUSIN_0 */
 | 
				
			||||||
 | 
					#define RSME	(1 << 14)	/* Enable IRQ Resume */
 | 
				
			||||||
 | 
					#define SOFE	(1 << 13)	/* Enable IRQ Frame Number Update */
 | 
				
			||||||
 | 
					#define DVSE	(1 << 12)	/* Enable IRQ Device State Transition */
 | 
				
			||||||
 | 
					#define CTRE	(1 << 11)	/* Enable IRQ Control Stage Transition */
 | 
				
			||||||
 | 
					#define BEMPE	(1 << 10)	/* Enable IRQ Buffer Empty */
 | 
				
			||||||
 | 
					#define NRDYE	(1 << 9)	/* Enable IRQ Buffer Not Ready Response */
 | 
				
			||||||
 | 
					#define BRDYE	(1 << 8)	/* Enable IRQ Buffer Ready */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTENB1 */
 | 
				
			||||||
 | 
					#define BCHGE	(1 << 14)	/* USB Bus Change Interrupt Enable */
 | 
				
			||||||
 | 
					#define DTCHE	(1 << 12)	/* Disconnection Detect Interrupt Enable */
 | 
				
			||||||
 | 
					#define ATTCHE	(1 << 11)	/* Connection Detect Interrupt Enable */
 | 
				
			||||||
 | 
					#define EOFERRE	(1 << 6)	/* EOF Error Detect Interrupt Enable */
 | 
				
			||||||
 | 
					#define SIGNE	(1 << 5)	/* Setup Transaction Error Interrupt Enable */
 | 
				
			||||||
 | 
					#define SACKE	(1 << 4)	/* Setup Transaction ACK Interrupt Enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTSTS0 */
 | 
				
			||||||
 | 
					#define DVST	(1 << 12)	/* Device State Transition Interrupt Status */
 | 
				
			||||||
 | 
					#define CTRT	(1 << 11)	/* Control Stage Interrupt Status */
 | 
				
			||||||
 | 
					#define BEMP	(1 << 10)	/* Buffer Empty Interrupt Status */
 | 
				
			||||||
 | 
					#define BRDY	(1 << 8)	/* Buffer Ready Interrupt Status */
 | 
				
			||||||
 | 
					#define VBSTS	(1 << 7)	/* VBUS_0 and VBUSIN_0 Input Status */
 | 
				
			||||||
 | 
					#define VALID	(1 << 3)	/* USB Request Receive */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DVSQ_MASK		(0x3 << 4)	/* Device State */
 | 
				
			||||||
 | 
					#define  POWER_STATE		(0 << 4)
 | 
				
			||||||
 | 
					#define  DEFAULT_STATE		(1 << 4)
 | 
				
			||||||
 | 
					#define  ADDRESS_STATE		(2 << 4)
 | 
				
			||||||
 | 
					#define  CONFIGURATION_STATE	(3 << 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CTSQ_MASK		(0x7)	/* Control Transfer Stage */
 | 
				
			||||||
 | 
					#define  IDLE_SETUP_STAGE	0	/* Idle stage or setup stage */
 | 
				
			||||||
 | 
					#define  READ_DATA_STAGE	1	/* Control read data stage */
 | 
				
			||||||
 | 
					#define  READ_STATUS_STAGE	2	/* Control read status stage */
 | 
				
			||||||
 | 
					#define  WRITE_DATA_STAGE	3	/* Control write data stage */
 | 
				
			||||||
 | 
					#define  WRITE_STATUS_STAGE	4	/* Control write status stage */
 | 
				
			||||||
 | 
					#define  NODATA_STATUS_STAGE	5	/* Control write NoData status stage */
 | 
				
			||||||
 | 
					#define  SEQUENCE_ERROR		6	/* Control transfer sequence error */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PIPECFG */
 | 
				
			||||||
 | 
					/* DCPCFG */
 | 
				
			||||||
 | 
					#define TYPE_NONE	(0 << 14)	/* Transfer Type */
 | 
				
			||||||
 | 
					#define TYPE_BULK	(1 << 14)
 | 
				
			||||||
 | 
					#define TYPE_INT	(2 << 14)
 | 
				
			||||||
 | 
					#define TYPE_ISO	(3 << 14)
 | 
				
			||||||
 | 
					#define DBLB		(1 << 9)	/* Double Buffer Mode */
 | 
				
			||||||
 | 
					#define SHTNAK		(1 << 7)	/* Pipe Disable in Transfer End */
 | 
				
			||||||
 | 
					#define DIR_OUT		(1 << 4)	/* Transfer Direction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PIPEMAXP */
 | 
				
			||||||
 | 
					/* DCPMAXP */
 | 
				
			||||||
 | 
					#define DEVSEL_MASK	(0xF << 12)	/* Device Select */
 | 
				
			||||||
 | 
					#define DCP_MAXP_MASK	(0x7F)
 | 
				
			||||||
 | 
					#define PIPE_MAXP_MASK	(0x7FF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PIPEBUF */
 | 
				
			||||||
 | 
					#define BUFSIZE_SHIFT	10
 | 
				
			||||||
 | 
					#define BUFSIZE_MASK	(0x1F << BUFSIZE_SHIFT)
 | 
				
			||||||
 | 
					#define BUFNMB_MASK	(0xFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PIPEnCTR */
 | 
				
			||||||
 | 
					/* DCPCTR */
 | 
				
			||||||
 | 
					#define BSTS		(1 << 15)	/* Buffer Status */
 | 
				
			||||||
 | 
					#define CSSTS		(1 << 12)	/* CSSTS Status */
 | 
				
			||||||
 | 
					#define SQCLR		(1 << 8)	/* Toggle Bit Clear */
 | 
				
			||||||
 | 
					#define	ACLRM		(1 << 9)	/* Buffer Auto-Clear Mode */
 | 
				
			||||||
 | 
					#define PBUSY		(1 << 5)	/* Pipe Busy */
 | 
				
			||||||
 | 
					#define PID_MASK	(0x3)		/* Response PID */
 | 
				
			||||||
 | 
					#define  PID_NAK	0
 | 
				
			||||||
 | 
					#define  PID_BUF	1
 | 
				
			||||||
 | 
					#define  PID_STALL10	2
 | 
				
			||||||
 | 
					#define  PID_STALL11	3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CCPL		(1 << 2)	/* Control Transfer End Enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* FRMNUM */
 | 
				
			||||||
 | 
					#define FRNM_MASK	(0x7FF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		struct
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_priv {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void __iomem *base;
 | 
				
			||||||
 | 
						unsigned int irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct renesas_usbhs_platform_callback	*pfunc;
 | 
				
			||||||
 | 
						struct renesas_usbhs_driver_param	*dparam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct work_struct notify_hotplug_work;
 | 
				
			||||||
 | 
						struct platform_device *pdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spinlock_t		lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * module control
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct usbhs_mod_info mod_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * pipe control
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct usbhs_pipe_info pipe_info;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * common
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					u16 usbhs_read(struct usbhs_priv *priv, u32 reg);
 | 
				
			||||||
 | 
					void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data);
 | 
				
			||||||
 | 
					void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * sysconfig
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable);
 | 
				
			||||||
 | 
					void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable);
 | 
				
			||||||
 | 
					void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable);
 | 
				
			||||||
 | 
					void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
 | 
				
			||||||
 | 
					void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * frame
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_frame_get_num(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbhs_get_dparam(priv, param)	(priv->dparam->param)
 | 
				
			||||||
 | 
					#define usbhs_priv_to_pdev(priv)	(priv->pdev)
 | 
				
			||||||
 | 
					#define usbhs_priv_to_dev(priv)		(&priv->pdev->dev)
 | 
				
			||||||
 | 
					#define usbhs_priv_to_lock(priv)	(&priv->lock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* RENESAS_USB_DRIVER_H */
 | 
				
			||||||
							
								
								
									
										261
									
								
								drivers/usb/renesas_usbhs/mod.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								drivers/usb/renesas_usbhs/mod.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,261 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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/interrupt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "./common.h"
 | 
				
			||||||
 | 
					#include "./mod.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		host / gadget functions
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * renesas_usbhs host/gadget can register itself by below functions.
 | 
				
			||||||
 | 
					 * these functions are called when probe
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info->mod[id]	= mod;
 | 
				
			||||||
 | 
						mod->priv	= priv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 | 
				
			||||||
 | 
						struct usbhs_mod *ret = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (id) {
 | 
				
			||||||
 | 
						case USBHS_HOST:
 | 
				
			||||||
 | 
						case USBHS_GADGET:
 | 
				
			||||||
 | 
							ret = info->mod[id];
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mod)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return info->mod[USBHS_HOST] == mod;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return info->curt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_mod_change(struct usbhs_priv *priv, int id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 | 
				
			||||||
 | 
						struct usbhs_mod *mod = NULL;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* id < 0 mean no current */
 | 
				
			||||||
 | 
						switch (id) {
 | 
				
			||||||
 | 
						case USBHS_HOST:
 | 
				
			||||||
 | 
						case USBHS_GADGET:
 | 
				
			||||||
 | 
							mod = info->mod[id];
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						info->curt = mod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t usbhs_interrupt(int irq, void *data);
 | 
				
			||||||
 | 
					int usbhs_mod_probe(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* irq settings */
 | 
				
			||||||
 | 
						ret = request_irq(priv->irq, usbhs_interrupt,
 | 
				
			||||||
 | 
								  IRQF_DISABLED, dev_name(dev), priv);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							dev_err(dev, "irq request err\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_mod_remove(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						free_irq(priv->irq, priv);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		status functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (irq_state->dvstctr & RHST) {
 | 
				
			||||||
 | 
						case RHST_LOW_SPEED:
 | 
				
			||||||
 | 
							return USB_SPEED_LOW;
 | 
				
			||||||
 | 
						case RHST_FULL_SPEED:
 | 
				
			||||||
 | 
							return USB_SPEED_FULL;
 | 
				
			||||||
 | 
						case RHST_HIGH_SPEED:
 | 
				
			||||||
 | 
							return USB_SPEED_HIGH;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return USB_SPEED_UNKNOWN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int state = irq_state->intsts0 & DVSQ_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (state) {
 | 
				
			||||||
 | 
						case POWER_STATE:
 | 
				
			||||||
 | 
						case DEFAULT_STATE:
 | 
				
			||||||
 | 
						case ADDRESS_STATE:
 | 
				
			||||||
 | 
						case CONFIGURATION_STATE:
 | 
				
			||||||
 | 
							return state;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * return value
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * IDLE_SETUP_STAGE
 | 
				
			||||||
 | 
						 * READ_DATA_STAGE
 | 
				
			||||||
 | 
						 * READ_STATUS_STAGE
 | 
				
			||||||
 | 
						 * WRITE_DATA_STAGE
 | 
				
			||||||
 | 
						 * WRITE_STATUS_STAGE
 | 
				
			||||||
 | 
						 * NODATA_STATUS_STAGE
 | 
				
			||||||
 | 
						 * SEQUENCE_ERROR
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						return (int)irq_state->intsts0 & CTSQ_MASK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
									      struct usbhs_irq_state *state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_mod *mod = usbhs_mod_get_current(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->intsts0 = usbhs_read(priv, INTSTS0);
 | 
				
			||||||
 | 
						state->intsts1 = usbhs_read(priv, INTSTS1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->brdysts = usbhs_read(priv, BRDYSTS);
 | 
				
			||||||
 | 
						state->nrdysts = usbhs_read(priv, NRDYSTS);
 | 
				
			||||||
 | 
						state->bempsts = usbhs_read(priv, BEMPSTS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->dvstctr = usbhs_read(priv, DVSTCTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mask */
 | 
				
			||||||
 | 
						state->bempsts &= mod->irq_bempsts;
 | 
				
			||||||
 | 
						state->brdysts &= mod->irq_brdysts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		interrupt
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */
 | 
				
			||||||
 | 
					#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */
 | 
				
			||||||
 | 
					static irqreturn_t usbhs_interrupt(int irq, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = data;
 | 
				
			||||||
 | 
						struct usbhs_irq_state irq_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_status_get_each_irq(priv, &irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * clear interrupt
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * The hardware is _very_ picky to clear interrupt bit.
 | 
				
			||||||
 | 
						 * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 *	"Operation"
 | 
				
			||||||
 | 
						 *	 - "Control Transfer (DCP)"
 | 
				
			||||||
 | 
						 *	   - Function :: VALID bit should 0
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
 | 
				
			||||||
 | 
						usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, BRDYSTS, 0);
 | 
				
			||||||
 | 
						usbhs_write(priv, NRDYSTS, 0);
 | 
				
			||||||
 | 
						usbhs_write(priv, BEMPSTS, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * call irq callback functions
 | 
				
			||||||
 | 
						 * see also
 | 
				
			||||||
 | 
						 *	usbhs_irq_setting_update
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (irq_state.intsts0 & DVST)
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq_state.intsts0 & CTRT)
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq_state.intsts0 & BEMP)
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, irq_empty, priv, &irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq_state.intsts0 & BRDY)
 | 
				
			||||||
 | 
							usbhs_mod_call(priv, irq_ready, priv, &irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 intenb0 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, INTENB0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, BEMPENB, 0);
 | 
				
			||||||
 | 
						usbhs_write(priv, BRDYENB, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * see also
 | 
				
			||||||
 | 
						 *	usbhs_interrupt
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * it don't enable DVSE (intenb0) here
 | 
				
			||||||
 | 
						 * but "mod->irq_dev_state" will be called.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mod->irq_ctrl_stage)
 | 
				
			||||||
 | 
							intenb0 |= CTRE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mod->irq_empty && mod->irq_bempsts) {
 | 
				
			||||||
 | 
							usbhs_write(priv, BEMPENB, mod->irq_bempsts);
 | 
				
			||||||
 | 
							intenb0 |= BEMPE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mod->irq_ready && mod->irq_brdysts) {
 | 
				
			||||||
 | 
							usbhs_write(priv, BRDYENB, mod->irq_brdysts);
 | 
				
			||||||
 | 
							intenb0 |= BRDYE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, INTENB0, intenb0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										106
									
								
								drivers/usb/renesas_usbhs/mod.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								drivers/usb/renesas_usbhs/mod.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,106 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef RENESAS_USB_MOD_H
 | 
				
			||||||
 | 
					#define RENESAS_USB_MOD_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/usb/renesas_usbhs.h>
 | 
				
			||||||
 | 
					#include "./common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *	struct
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_irq_state {
 | 
				
			||||||
 | 
						u16 intsts0;
 | 
				
			||||||
 | 
						u16 intsts1;
 | 
				
			||||||
 | 
						u16 brdysts;
 | 
				
			||||||
 | 
						u16 nrdysts;
 | 
				
			||||||
 | 
						u16 bempsts;
 | 
				
			||||||
 | 
						u16 dvstctr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_mod {
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * entry point from common.c
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int (*start)(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
						int (*stop)(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* INTSTS0 :: DVST (DVSQ) */
 | 
				
			||||||
 | 
						int (*irq_dev_state)(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
								     struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* INTSTS0 :: CTRT (CTSQ) */
 | 
				
			||||||
 | 
						int (*irq_ctrl_stage)(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
								      struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* INTSTS0 :: BEMP */
 | 
				
			||||||
 | 
						/* BEMPSTS */
 | 
				
			||||||
 | 
						int (*irq_empty)(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
								 struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
						u16 irq_bempsts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* INTSTS0 :: BRDY */
 | 
				
			||||||
 | 
						/* BRDYSTS */
 | 
				
			||||||
 | 
						int (*irq_ready)(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
								 struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
						u16 irq_brdysts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct usbhs_priv *priv;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_mod_info {
 | 
				
			||||||
 | 
						struct usbhs_mod *mod[USBHS_MAX];
 | 
				
			||||||
 | 
						struct usbhs_mod *curt; /* current mod */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		for host/gadget module
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id);
 | 
				
			||||||
 | 
					struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *usb, int id);
 | 
				
			||||||
 | 
					int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod);
 | 
				
			||||||
 | 
					int usbhs_mod_change(struct usbhs_priv *priv, int id);
 | 
				
			||||||
 | 
					int usbhs_mod_probe(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					void usbhs_mod_remove(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		status functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
					int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
					int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		callback functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhs_mod_call(priv, func, param...)		\
 | 
				
			||||||
 | 
						({						\
 | 
				
			||||||
 | 
							struct usbhs_mod *mod;			\
 | 
				
			||||||
 | 
							mod = usbhs_mod_get_current(priv);	\
 | 
				
			||||||
 | 
							!mod		? -ENODEV :		\
 | 
				
			||||||
 | 
							!mod->func	? 0 :			\
 | 
				
			||||||
 | 
							 mod->func(param);			\
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* RENESAS_USB_MOD_H */
 | 
				
			||||||
							
								
								
									
										880
									
								
								drivers/usb/renesas_usbhs/pipe.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										880
									
								
								drivers/usb/renesas_usbhs/pipe.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,880 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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/delay.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include "./common.h"
 | 
				
			||||||
 | 
					#include "./pipe.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		macros
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbhsp_priv_to_pipeinfo(pr)	(&(pr)->pipe_info)
 | 
				
			||||||
 | 
					#define usbhsp_pipe_to_priv(p)		((p)->priv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhsp_addr_offset(p)	((usbhs_pipe_number(p) - 1) * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhsp_is_dcp(p)	((p)->priv->pipe_info.pipe == (p))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhsp_flags_set(p, f)	((p)->flags |=  USBHS_PIPE_FLAGS_##f)
 | 
				
			||||||
 | 
					#define usbhsp_flags_clr(p, f)	((p)->flags &= ~USBHS_PIPE_FLAGS_##f)
 | 
				
			||||||
 | 
					#define usbhsp_flags_has(p, f)	((p)->flags &   USBHS_PIPE_FLAGS_##f)
 | 
				
			||||||
 | 
					#define usbhsp_flags_init(p)	do {(p)->flags = 0; } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhsp_type(p)		((p)->pipe_type)
 | 
				
			||||||
 | 
					#define usbhsp_type_is(p, t)	((p)->pipe_type == t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * for debug
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static char *usbhsp_pipe_name[] = {
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_CONTROL]	= "DCP",
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_BULK]	= "BULK",
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_INT]		= "INT",
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_ISOC]	= "ISO",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		usb request functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = usbhs_read(priv, USBREQ);
 | 
				
			||||||
 | 
						req->bRequest		= (val >> 8) & 0xFF;
 | 
				
			||||||
 | 
						req->bRequestType	= (val >> 0) & 0xFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req->wValue	= usbhs_read(priv, USBVAL);
 | 
				
			||||||
 | 
						req->wIndex	= usbhs_read(priv, USBINDX);
 | 
				
			||||||
 | 
						req->wLength	= usbhs_read(priv, USBLENG);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usbhs_write(priv, USBREQ,  (req->bRequest << 8) | req->bRequestType);
 | 
				
			||||||
 | 
						usbhs_write(priv, USBVAL,  req->wValue);
 | 
				
			||||||
 | 
						usbhs_write(priv, USBINDX, req->wIndex);
 | 
				
			||||||
 | 
						usbhs_write(priv, USBLENG, req->wLength);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		DCPCTR/PIPEnCTR functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						int offset = usbhsp_addr_offset(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							usbhs_bset(priv, DCPCTR, mask, val);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							usbhs_bset(priv, PIPEnCTR + offset, mask, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						int offset = usbhsp_addr_offset(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							return usbhs_read(priv, DCPCTR);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return usbhs_read(priv, PIPEnCTR + offset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		DCP/PIPE functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe,
 | 
				
			||||||
 | 
									  u16 dcp_reg, u16 pipe_reg,
 | 
				
			||||||
 | 
									  u16 mask, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							usbhs_bset(priv, dcp_reg, mask, val);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							usbhs_bset(priv, pipe_reg, mask, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe,
 | 
				
			||||||
 | 
									 u16 dcp_reg, u16 pipe_reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							return usbhs_read(priv, dcp_reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return usbhs_read(priv, pipe_reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		DCPCFG/PIPECFG functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		PIPEBUF
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		DCPMAXP/PIPEMAXP
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 usbhsp_pipe_maxp_get(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return __usbhsp_pipe_xxx_get(pipe, DCPMAXP, PIPEMAXP);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		pipe control functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbhsp_pipe_select(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * On pipe, this is necessary before
 | 
				
			||||||
 | 
						 * accesses to below registers.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * PIPESEL	: usbhsp_pipe_select
 | 
				
			||||||
 | 
						 * PIPECFG	: usbhsp_pipe_cfg_xxx
 | 
				
			||||||
 | 
						 * PIPEBUF	: usbhsp_pipe_buf_xxx
 | 
				
			||||||
 | 
						 * PIPEMAXP	: usbhsp_pipe_maxp_xxx
 | 
				
			||||||
 | 
						 * PIPEPERI
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * if pipe is dcp, no pipe is selected.
 | 
				
			||||||
 | 
						 * it is no problem, because dcp have its register
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						int timeout = 1024;
 | 
				
			||||||
 | 
						u16 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * make sure....
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is
 | 
				
			||||||
 | 
						 * specified by the CURPIPE bits.
 | 
				
			||||||
 | 
						 * When changing the setting of this bit after changing
 | 
				
			||||||
 | 
						 * the PID bits for the selected pipe from BUF to NAK,
 | 
				
			||||||
 | 
						 * check that CSSTS = 0 and PBUSY = 0.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * CURPIPE bit = 0
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * see also
 | 
				
			||||||
 | 
						 *  "Operation"
 | 
				
			||||||
 | 
						 *  - "Pipe Control"
 | 
				
			||||||
 | 
						 *   - "Pipe Control Registers Switching Procedure"
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_write(priv, CFIFOSEL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							val  = usbhsp_pipectrl_get(pipe);
 | 
				
			||||||
 | 
							val &= CSSTS | PID_MASK;
 | 
				
			||||||
 | 
							if (!val)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							udelay(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} while (timeout--);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * force NAK
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						timeout = 1024;
 | 
				
			||||||
 | 
						usbhs_fifo_disable(pipe);
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							val  = usbhsp_pipectrl_get(pipe);
 | 
				
			||||||
 | 
							val &= PBUSY;
 | 
				
			||||||
 | 
							if (!val)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} while (timeout--);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_err(dev, "pipe barrier failed\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EBUSY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsp_pipe_is_accessible(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = usbhsp_pipectrl_get(pipe);
 | 
				
			||||||
 | 
						if (val & BSTS)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EBUSY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		PID ctrl
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 pid = usbhsp_pipectrl_get(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pid &= PID_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 * "Pipe n Control Register" - "PID"
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (pid) {
 | 
				
			||||||
 | 
						case PID_STALL11:
 | 
				
			||||||
 | 
							usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10);
 | 
				
			||||||
 | 
							/* fall-through */
 | 
				
			||||||
 | 
						case PID_STALL10:
 | 
				
			||||||
 | 
							usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_fifo_disable(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* see "Pipe n Control Register" - "PID" */
 | 
				
			||||||
 | 
						__usbhsp_pid_try_nak_if_stall(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_fifo_enable(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* see "Pipe n Control Register" - "PID" */
 | 
				
			||||||
 | 
						__usbhsp_pid_try_nak_if_stall(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_fifo_stall(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 pid = usbhsp_pipectrl_get(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pid &= PID_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 * "Pipe n Control Register" - "PID"
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (pid) {
 | 
				
			||||||
 | 
						case PID_NAK:
 | 
				
			||||||
 | 
							usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PID_BUF:
 | 
				
			||||||
 | 
							usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		CFIFO ctrl
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_fifo_send_terminator(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usbhsp_fifo_clear(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_write(priv, CFIFOCTR, BCLR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsp_fifo_barrier(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int timeout = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							/* The FIFO port is accessible */
 | 
				
			||||||
 | 
							if (usbhs_read(priv, CFIFOCTR) & FRDY)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							udelay(10);
 | 
				
			||||||
 | 
						} while (timeout--);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EBUSY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsp_fifo_rcv_len(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int usbhsp_fifo_select(struct usbhs_pipe *pipe, int write)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						int timeout = 1024;
 | 
				
			||||||
 | 
						u16 mask = ((1 << 5) | 0xF);		/* mask of ISEL | CURPIPE */
 | 
				
			||||||
 | 
						u16 base = usbhs_pipe_number(pipe);	/* CURPIPE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							base |= (1 == write) << 5;	/* ISEL */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* "base" will be used below  */
 | 
				
			||||||
 | 
						usbhs_write(priv, CFIFOSEL, base | MBW_32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check ISEL and CURPIPE value */
 | 
				
			||||||
 | 
						while (timeout--) {
 | 
				
			||||||
 | 
							if (base == (mask & usbhs_read(priv, CFIFOSEL)))
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							udelay(10);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_err(dev, "fifo select error\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhsp_fifo_select(pipe, 1);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_fifo_clear(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						void __iomem *addr = priv->base + CFIFO;
 | 
				
			||||||
 | 
						int maxp = usbhs_pipe_get_maxpacket(pipe);
 | 
				
			||||||
 | 
						int total_len;
 | 
				
			||||||
 | 
						int i, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhsp_pipe_is_accessible(pipe);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhs_fifo_prepare_write(pipe);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhsp_fifo_barrier(priv);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = min(len, maxp);
 | 
				
			||||||
 | 
						total_len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * FIXME
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * 32-bit access only
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (len >= 4 &&
 | 
				
			||||||
 | 
						    !((unsigned long)buf & 0x03)) {
 | 
				
			||||||
 | 
							iowrite32_rep(addr, buf, len / 4);
 | 
				
			||||||
 | 
							len %= 4;
 | 
				
			||||||
 | 
							buf += total_len - len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the rest operation */
 | 
				
			||||||
 | 
						for (i = 0; i < len; i++)
 | 
				
			||||||
 | 
							iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (total_len < maxp)
 | 
				
			||||||
 | 
							usbhs_fifo_send_terminator(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return total_len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * select pipe and enable it to prepare packet receive
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ret = usbhsp_fifo_select(pipe, 0);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_fifo_enable(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						void __iomem *addr = priv->base + CFIFO;
 | 
				
			||||||
 | 
						int rcv_len;
 | 
				
			||||||
 | 
						int i, ret;
 | 
				
			||||||
 | 
						int total_len;
 | 
				
			||||||
 | 
						u32 data = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhsp_fifo_select(pipe, 0);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = usbhsp_fifo_barrier(priv);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcv_len = usbhsp_fifo_rcv_len(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Buffer clear if Zero-Length packet
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (0 == rcv_len) {
 | 
				
			||||||
 | 
							usbhsp_fifo_clear(pipe);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = min(rcv_len, len);
 | 
				
			||||||
 | 
						total_len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * FIXME
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * 32-bit access only
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (len >= 4 &&
 | 
				
			||||||
 | 
						    !((unsigned long)buf & 0x03)) {
 | 
				
			||||||
 | 
							ioread32_rep(addr, buf, len / 4);
 | 
				
			||||||
 | 
							len %= 4;
 | 
				
			||||||
 | 
							buf += rcv_len - len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the rest operation */
 | 
				
			||||||
 | 
						for (i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							if (!(i & 0x03))
 | 
				
			||||||
 | 
								data = ioread32(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return total_len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		pipe setup
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * only ISO / BULK pipe can use double buffer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) ||
 | 
				
			||||||
 | 
						    usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
 | 
				
			||||||
 | 
									const struct usb_endpoint_descriptor *desc,
 | 
				
			||||||
 | 
									int is_host)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 type = 0;
 | 
				
			||||||
 | 
						u16 bfre = 0;
 | 
				
			||||||
 | 
						u16 dblb = 0;
 | 
				
			||||||
 | 
						u16 cntmd = 0;
 | 
				
			||||||
 | 
						u16 dir = 0;
 | 
				
			||||||
 | 
						u16 epnum = 0;
 | 
				
			||||||
 | 
						u16 shtnak = 0;
 | 
				
			||||||
 | 
						u16 type_array[] = {
 | 
				
			||||||
 | 
							[USB_ENDPOINT_XFER_BULK] = TYPE_BULK,
 | 
				
			||||||
 | 
							[USB_ENDPOINT_XFER_INT]  = TYPE_INT,
 | 
				
			||||||
 | 
							[USB_ENDPOINT_XFER_ISOC] = TYPE_ISO,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int is_double = usbhsp_possible_double_buffer(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usbhsp_is_dcp(pipe))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * PIPECFG
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 *  - "Register Descriptions" - "PIPECFG" register
 | 
				
			||||||
 | 
						 *  - "Features"  - "Pipe configuration"
 | 
				
			||||||
 | 
						 *  - "Operation" - "Pipe Control"
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TYPE */
 | 
				
			||||||
 | 
						type = type_array[usbhsp_type(pipe)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* BFRE */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
 | 
				
			||||||
 | 
						    usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
 | 
				
			||||||
 | 
							bfre = 0; /* FIXME */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* DBLB */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
 | 
				
			||||||
 | 
						    usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
 | 
				
			||||||
 | 
							dblb = (is_double) ? DBLB : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* CNTMD */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
 | 
				
			||||||
 | 
							cntmd = 0; /* FIXME */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* DIR */
 | 
				
			||||||
 | 
						if (usb_endpoint_dir_in(desc))
 | 
				
			||||||
 | 
							usbhsp_flags_set(pipe, IS_DIR_IN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((is_host  && usb_endpoint_dir_out(desc)) ||
 | 
				
			||||||
 | 
						    (!is_host && usb_endpoint_dir_in(desc)))
 | 
				
			||||||
 | 
							dir |= DIR_OUT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* SHTNAK */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) &&
 | 
				
			||||||
 | 
						    !dir)
 | 
				
			||||||
 | 
							shtnak = SHTNAK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* EPNUM */
 | 
				
			||||||
 | 
						epnum = 0xF & usb_endpoint_num(desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return	type	|
 | 
				
			||||||
 | 
							bfre	|
 | 
				
			||||||
 | 
							dblb	|
 | 
				
			||||||
 | 
							cntmd	|
 | 
				
			||||||
 | 
							dir	|
 | 
				
			||||||
 | 
							shtnak	|
 | 
				
			||||||
 | 
							epnum;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 usbhsp_setup_pipemaxp(struct usbhs_pipe *pipe,
 | 
				
			||||||
 | 
									 const struct usb_endpoint_descriptor *desc,
 | 
				
			||||||
 | 
									 int is_host)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* host should set DEVSEL */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reutn MXPS */
 | 
				
			||||||
 | 
						return PIPE_MAXP_MASK & le16_to_cpu(desc->wMaxPacketSize);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
 | 
				
			||||||
 | 
									 const struct usb_endpoint_descriptor *desc,
 | 
				
			||||||
 | 
									 int is_host)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe);
 | 
				
			||||||
 | 
						struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv);
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						int pipe_num = usbhs_pipe_number(pipe);
 | 
				
			||||||
 | 
						int is_double = usbhsp_possible_double_buffer(pipe);
 | 
				
			||||||
 | 
						u16 buff_size;
 | 
				
			||||||
 | 
						u16 bufnmb;
 | 
				
			||||||
 | 
						u16 bufnmb_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * PIPEBUF
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 *  - "Register Descriptions" - "PIPEBUF" register
 | 
				
			||||||
 | 
						 *  - "Features"  - "Pipe configuration"
 | 
				
			||||||
 | 
						 *  - "Operation" - "FIFO Buffer Memory"
 | 
				
			||||||
 | 
						 *  - "Operation" - "Pipe Control"
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * ex) if pipe6 - pipe9 are USB_ENDPOINT_XFER_INT (SH7724)
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * BUFNMB:	PIPE
 | 
				
			||||||
 | 
						 * 0:		pipe0 (DCP 256byte)
 | 
				
			||||||
 | 
						 * 1:		-
 | 
				
			||||||
 | 
						 * 2:		-
 | 
				
			||||||
 | 
						 * 3:		-
 | 
				
			||||||
 | 
						 * 4:		pipe6 (INT 64byte)
 | 
				
			||||||
 | 
						 * 5:		pipe7 (INT 64byte)
 | 
				
			||||||
 | 
						 * 6:		pipe8 (INT 64byte)
 | 
				
			||||||
 | 
						 * 7:		pipe9 (INT 64byte)
 | 
				
			||||||
 | 
						 * 8 - xx:	free (for BULK, ISOC)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * FIXME
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * it doesn't have good buffer allocator
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * DCP : 256 byte
 | 
				
			||||||
 | 
						 * BULK: 512 byte
 | 
				
			||||||
 | 
						 * INT :  64 byte
 | 
				
			||||||
 | 
						 * ISOC: 512 byte
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_CONTROL))
 | 
				
			||||||
 | 
							buff_size = 256;
 | 
				
			||||||
 | 
						else if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT))
 | 
				
			||||||
 | 
							buff_size = 64;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							buff_size = 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* change buff_size to register value */
 | 
				
			||||||
 | 
						bufnmb_cnt = (buff_size / 64) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* BUFNMB has been reserved for INT pipe
 | 
				
			||||||
 | 
						 * see above */
 | 
				
			||||||
 | 
						if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT)) {
 | 
				
			||||||
 | 
							bufnmb = pipe_num - 2;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							bufnmb = info->bufnmb_last;
 | 
				
			||||||
 | 
							info->bufnmb_last += bufnmb_cnt + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * double buffer
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (is_double)
 | 
				
			||||||
 | 
								info->bufnmb_last += bufnmb_cnt + 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n",
 | 
				
			||||||
 | 
							pipe_num, buff_size, bufnmb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return	(0x1f & bufnmb_cnt)	<< 10 |
 | 
				
			||||||
 | 
							(0xff & bufnmb)		<<  0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		pipe control
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 mask = usbhsp_is_dcp(pipe) ? DCP_MAXP_MASK : PIPE_MAXP_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_pipe_select(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (int)(usbhsp_pipe_maxp_get(pipe) & mask);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return usbhsp_flags_has(pipe, IS_DIR_IN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, SQCLR, SQCLR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_pipe *pos, *pipe;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * find target pipe
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pipe = NULL;
 | 
				
			||||||
 | 
						usbhs_for_each_pipe_with_dcp(pos, priv, i) {
 | 
				
			||||||
 | 
							if (!usbhsp_type_is(pos, type))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (usbhsp_flags_has(pos, IS_USED))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pipe = pos;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pipe)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * initialize pipe flags
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhsp_flags_init(pipe);
 | 
				
			||||||
 | 
						usbhsp_flags_set(pipe, IS_USED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pipe;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_pipe_init(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv);
 | 
				
			||||||
 | 
						struct usbhs_pipe *pipe;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * FIXME
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * driver needs good allocator.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * find first free buffer area (BULK, ISOC)
 | 
				
			||||||
 | 
						 * (DCP, INT area is fixed)
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * buffer number 0 - 3 have been reserved for DCP
 | 
				
			||||||
 | 
						 * see
 | 
				
			||||||
 | 
						 *	usbhsp_to_bufnmb
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						info->bufnmb_last = 4;
 | 
				
			||||||
 | 
						usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
 | 
				
			||||||
 | 
							if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT))
 | 
				
			||||||
 | 
								info->bufnmb_last++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							usbhsp_flags_init(pipe);
 | 
				
			||||||
 | 
							pipe->mod_private = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
									     const struct usb_endpoint_descriptor *desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						struct usbhs_mod *mod = usbhs_mod_get_current(priv);
 | 
				
			||||||
 | 
						struct usbhs_pipe *pipe;
 | 
				
			||||||
 | 
						int is_host = usbhs_mod_is_host(priv, mod);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u16 pipecfg, pipebuf, pipemaxp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipe = usbhsp_get_pipe(priv, usb_endpoint_type(desc));
 | 
				
			||||||
 | 
						if (!pipe)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_fifo_disable(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* make sure pipe is not busy */
 | 
				
			||||||
 | 
						ret = usbhsp_pipe_barrier(pipe);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipecfg  = usbhsp_setup_pipecfg(pipe,  desc, is_host);
 | 
				
			||||||
 | 
						pipebuf  = usbhsp_setup_pipebuff(pipe, desc, is_host);
 | 
				
			||||||
 | 
						pipemaxp = usbhsp_setup_pipemaxp(pipe, desc, is_host);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* buffer clear
 | 
				
			||||||
 | 
						 * see PIPECFG :: BFRE */
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, ACLRM, ACLRM);
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, ACLRM, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_pipe_select(pipe);
 | 
				
			||||||
 | 
						usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg);
 | 
				
			||||||
 | 
						usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf);
 | 
				
			||||||
 | 
						usbhsp_pipe_maxp_set(pipe, 0xFFFF, pipemaxp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_pipe_clear_sequence(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(dev, "enable pipe %d : %s (%s)\n",
 | 
				
			||||||
 | 
							usbhs_pipe_number(pipe),
 | 
				
			||||||
 | 
							usbhsp_pipe_name[usb_endpoint_type(desc)],
 | 
				
			||||||
 | 
							usbhs_pipe_is_dir_in(pipe) ? "in" : "out");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pipe;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		dcp control
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_pipe *pipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL);
 | 
				
			||||||
 | 
						if (!pipe)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * dcpcfg  : default
 | 
				
			||||||
 | 
						 * dcpmaxp : default
 | 
				
			||||||
 | 
						 * pipebuf : nothing to do
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhsp_pipe_select(pipe);
 | 
				
			||||||
 | 
						usbhs_pipe_clear_sequence(pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pipe;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WARN_ON(!usbhsp_is_dcp(pipe));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbhs_fifo_enable(pipe);
 | 
				
			||||||
 | 
						usbhsp_pipectrl_set(pipe, CCPL, CCPL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *		pipe module function
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_pipe_probe(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv);
 | 
				
			||||||
 | 
						struct usbhs_pipe *pipe;
 | 
				
			||||||
 | 
						struct device *dev = usbhs_priv_to_dev(priv);
 | 
				
			||||||
 | 
						u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
 | 
				
			||||||
 | 
						int pipe_size = usbhs_get_dparam(priv, pipe_size);
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This driver expects 1st pipe is DCP */
 | 
				
			||||||
 | 
						if (pipe_type[0] != USB_ENDPOINT_XFER_CONTROL) {
 | 
				
			||||||
 | 
							dev_err(dev, "1st PIPE is not DCP\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!info->pipe) {
 | 
				
			||||||
 | 
							dev_err(dev, "Could not allocate pipe\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info->size = pipe_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * init pipe
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
 | 
				
			||||||
 | 
							pipe->priv = priv;
 | 
				
			||||||
 | 
							usbhsp_type(pipe) = pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dev_dbg(dev, "pipe %x\t: %s\n",
 | 
				
			||||||
 | 
								i, usbhsp_pipe_name[pipe_type[i]]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_pipe_remove(struct usbhs_priv *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(info->pipe);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										105
									
								
								drivers/usb/renesas_usbhs/pipe.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								drivers/usb/renesas_usbhs/pipe.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,105 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef RENESAS_USB_PIPE_H
 | 
				
			||||||
 | 
					#define RENESAS_USB_PIPE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "./common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *	struct
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_pipe {
 | 
				
			||||||
 | 
						u32 pipe_type;	/* USB_ENDPOINT_XFER_xxx */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct usbhs_priv *priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 flags;
 | 
				
			||||||
 | 
					#define USBHS_PIPE_FLAGS_IS_USED		(1 << 0)
 | 
				
			||||||
 | 
					#define USBHS_PIPE_FLAGS_IS_DIR_IN		(1 << 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *mod_private;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbhs_pipe_info {
 | 
				
			||||||
 | 
						struct usbhs_pipe *pipe;
 | 
				
			||||||
 | 
						int size;	/* array size of "pipe" */
 | 
				
			||||||
 | 
						int bufnmb_last;	/* FIXME : driver needs good allocator */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * pipe list
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define __usbhs_for_each_pipe(start, pos, info, i)	\
 | 
				
			||||||
 | 
						for (i = start, pos = (info)->pipe;		\
 | 
				
			||||||
 | 
						     i < (info)->size;				\
 | 
				
			||||||
 | 
						     i++, pos = (info)->pipe + i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhs_for_each_pipe(pos, priv, i)			\
 | 
				
			||||||
 | 
						__usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhs_for_each_pipe_with_dcp(pos, priv, i)		\
 | 
				
			||||||
 | 
						__usbhs_for_each_pipe(0, pos, &((priv)->pipe_info), i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * pipe module probe / remove
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_pipe_probe(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					void usbhs_pipe_remove(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * cfifo
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len);
 | 
				
			||||||
 | 
					int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len);
 | 
				
			||||||
 | 
					int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_fifo_enable(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					void usbhs_fifo_disable(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					void usbhs_fifo_stall(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usbhs_fifo_send_terminator(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * usb request
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
 | 
				
			||||||
 | 
					void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * pipe control
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_pipe
 | 
				
			||||||
 | 
					*usbhs_pipe_malloc(struct usbhs_priv *priv,
 | 
				
			||||||
 | 
							   const struct usb_endpoint_descriptor *desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					void usbhs_pipe_init(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define usbhs_pipe_number(p)	(((u32)(p) - (u32)(p)->priv->pipe_info.pipe) / \
 | 
				
			||||||
 | 
									 sizeof(struct usbhs_pipe))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * dcp control
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv);
 | 
				
			||||||
 | 
					void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* RENESAS_USB_PIPE_H */
 | 
				
			||||||
							
								
								
									
										149
									
								
								include/linux/usb/renesas_usbhs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								include/linux/usb/renesas_usbhs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,149 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Renesas USB
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef RENESAS_USB_H
 | 
				
			||||||
 | 
					#define RENESAS_USB_H
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/usb/ch9.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * module type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * it will be return value from get_id
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						USBHS_HOST = 0,
 | 
				
			||||||
 | 
						USBHS_GADGET,
 | 
				
			||||||
 | 
						USBHS_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * callback functions table for driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * These functions are called from platform for driver.
 | 
				
			||||||
 | 
					 * Callback function's pointer will be set before
 | 
				
			||||||
 | 
					 * renesas_usbhs_platform_callback :: hardware_init was called
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct renesas_usbhs_driver_callback {
 | 
				
			||||||
 | 
						int (*notify_hotplug)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * callback functions for platform
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * These functions are called from driver for platform
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct renesas_usbhs_platform_callback {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Hardware init function for platform.
 | 
				
			||||||
 | 
						 * it is called when driver was probed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int (*hardware_init)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Hardware exit function for platform.
 | 
				
			||||||
 | 
						 * it is called when driver was removed
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*hardware_exit)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Phy reset for platform
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*phy_reset)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * get USB ID function
 | 
				
			||||||
 | 
						 *  - USBHS_HOST
 | 
				
			||||||
 | 
						 *  - USBHS_GADGET
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int (*get_id)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * get VBUS status function.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int (*get_vbus)(struct platform_device *pdev);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * parameters for renesas usbhs
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * some register needs USB chip specific parameters.
 | 
				
			||||||
 | 
					 * This struct show it to driver
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct renesas_usbhs_driver_param {
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * pipe settings
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						u32 *pipe_type; /* array of USB_ENDPOINT_XFER_xxx (from ep0) */
 | 
				
			||||||
 | 
						int pipe_size; /* pipe_type array size */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * for BUSWAIT :: BWAIT
 | 
				
			||||||
 | 
						 * */
 | 
				
			||||||
 | 
						int buswait_bwait;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * option:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * platform information for renesas_usbhs driver.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct renesas_usbhs_platform_info {
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * platform set these functions before
 | 
				
			||||||
 | 
						 * call platform_add_devices if needed
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct renesas_usbhs_platform_callback	platform_callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * driver set these callback functions pointer.
 | 
				
			||||||
 | 
						 * platform can use it on callback functions
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct renesas_usbhs_driver_callback	driver_callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * option:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * driver use these param for some register
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct renesas_usbhs_driver_param	driver_param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * macro for platform
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define renesas_usbhs_get_info(pdev)\
 | 
				
			||||||
 | 
						((struct renesas_usbhs_platform_info *)(pdev)->dev.platform_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define renesas_usbhs_call_notify_hotplug(pdev)				\
 | 
				
			||||||
 | 
						({								\
 | 
				
			||||||
 | 
							struct renesas_usbhs_driver_callback *dc;		\
 | 
				
			||||||
 | 
							dc = &(renesas_usbhs_get_info(pdev)->driver_callback);	\
 | 
				
			||||||
 | 
							if (dc)							\
 | 
				
			||||||
 | 
								dc->notify_hotplug(pdev);			\
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					#endif /* RENESAS_USB_H */
 | 
				
			||||||
		Loading…
	
		Reference in a new issue