⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hal_pci.c

📁 philips公司ISP1362 USB OTG控制芯片的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
 * This function is called from PCI Driver as an removal function
 * in the absence of PCI device or a de-registration of driver.
 * This functions checks the registerd drivers (HCD, DCD, OTG) and calls
 * the corresponding removal functions. Also initializes the local variables
 * to zero.
 */
static void __devexit
isp1362_pci_remove (struct pci_dev *dev)
{
	struct isp1362_dev	*loc_dev;
	int			index;

	func_debug(("isp1362_pci_remove(dev=%p)\n",dev))

	/* For each controller check whether driver is registerd
         * or not. If registerd call the removal function if it is
	 * present
	 */
	for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;index++) {
		loc_dev = &isp1362_loc_dev[index];
		if(loc_dev->driver) {
			loc_dev->driver->remove(loc_dev);
			loc_dev->driver = NULL;
			return;
		}
	}

	/* Clear the local variables
	 */
	hal_data.io_usage = 0;
	hal_data.irq_usage = 0;

	return;
} /* End of isp1362_pci_remove */


/* PCI suspend function of ISP1362
 * This function is called from PCI Driver.
 * This functions checks the registerd drivers (HCD, DCD, OTG) and calls
 * the corresponding suspend functions if present. 
 */
static int isp1362_pci_suspend (struct pci_dev *dev, __u32 state) 
{
	struct isp1362_dev	*loc_dev;
	int			index;

	func_debug(("isp1362_pci_suspend(dev=%p, state = %x)\n",dev, state))


	loc_dev = (struct isp1362_dev *)pci_get_drvdata(dev);

	/* For each controller check whether driver is registerd
         * or not. If registerd call the suspend function if it is
	 * present
	 */
	for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;(index++,loc_dev++)) {
		if(loc_dev->driver && loc_dev->driver->suspend) {
			loc_dev->driver->suspend(loc_dev);
		}
	}

	return 0;
} /* End of isp1362_pci_suspend */

/* PCI resume function of ISP1362
 * This function is called from PCI Driver.
 * This functions checks the registerd drivers (HCD, DCD, OTG) and calls
 * the corresponding resume functions if present. 
 */
static int isp1362_pci_resume (struct pci_dev *dev)
{
	struct isp1362_dev	*loc_dev;
	int			index;

	func_debug(("isp1362_pci_resume(dev=%p)\n",dev))


	loc_dev = (struct isp1362_dev *)pci_get_drvdata(dev);

	/* For each controller check whether driver is registerd
         * or not. If registerd call the resume function if it is
	 * present
	 */
	for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;(index++,loc_dev++)) {
		if(loc_dev->driver && loc_dev->driver->resume) {
			loc_dev->driver->resume(loc_dev);
		}
	}

	return 0;

} /* End of isp1362_pci_resume */




/*--------------------------------------------------------------*
 *         Top Drivers (HCD, DCD, OTG) interface functions
 *--------------------------------------------------------------*/

/*--------------------------------------------------------------*
 *            hardware register initialization
 *--------------------------------------------------------------*/
/* This fuction initializes the ISP1362 device hardware configuration
 * register for PCI interface.
 */
void 	isp1362_set_hw_config(struct isp1362_dev *dev)
{
	__u32		hw_cnfg;
#ifndef CONFIG_USB_OTG
	struct isp1362_dev *otg_dev = &isp1362_loc_dev[ISP1362_OTG];
#endif /* CONFIG_USB_OTG */

	func_debug(("isp1362_set_hw_config(dev=%p)\n",dev))

	switch(dev->index) {

		case ISP1362_HC:
			isp1362_reg_read16(dev, HC_HW_CNFG_REG,hw_cnfg);

			/* Enable HC interrupt Pin
			 * Use only one interrupt for HC and DC
			 * Connect the 15K pulldown registers on port1&2
			 * Level triggering, Active low polarity
			 */
			hw_cnfg |= (HC_INT_PIN_ENABLE | HC_ONE_INT);
			hw_cnfg |= (HC_CONNECT_PLDN_15K_DS2 | HC_CONNECT_PLDN_15K_DS1);

#ifdef CONFIG_USB_PHCD_DMA
			hw_cnfg |= (HC_DREQ_OUT_POLARITY | HC_DATA_BUS_16BIT_WIDTH);
#endif /* CONFIG_USB_PHCD_DMA */

			isp1362_reg_write16(dev,(HC_HW_CNFG_REG|0x80),hw_cnfg);

#ifndef CONFIG_USB_OTG
			/* COnfigure the OTG port as the default Host port 
			 * Always drive the VBUS and detect D+ SRP */
			hw_cnfg = (OTG_DRV_VBUS|OTG_A_SEL_SRP|OTG_A_SRP_DET_EN);
			isp1362_reg_write16(otg_dev,(OTG_CONTROL_REG|0x80),hw_cnfg);
#endif	/* CONFIG_USB_OTG */
		break;

		case ISP1362_DC:
			isp1362_reg_read16(dev, DC_HW_CNFG_REG, hw_cnfg);
			 /* No Clock Division, Clock is always running
			  * Level triggering, Active low polarity
			  */
			hw_cnfg &= ~(DC_CLK_DIV);	/* No clock division */
			hw_cnfg |= (DC_CLK_RUN);	/* Clock is always running */
			isp1362_reg_write16(dev,(DC_HW_CNFG_REG&0xFE),hw_cnfg);

#ifndef CONFIG_USB_OTG
			/* COnfigure the OTG port as the default device port */
			hw_cnfg = (OTG_LOC_CONN|OTG_SEL_HC_DC);
			hw_cnfg &= (~OTG_A_RDIS_LCON_EN);
			hw_cnfg &= (~OTG_LOC_PULLDN_DP);
			isp1362_reg_write16(otg_dev,(OTG_CONTROL_REG|0x80),hw_cnfg);
#endif	/* CONFIG_USB_OTG */

		break;

		default:
		break;
	}

} /* End of isp1362_set_hw_config() */

/*--------------------------------------------------------------*
 *            IO PORT Management Functions
 *--------------------------------------------------------------*/

/* This fuction checks whether the IO region is free for use or not
 * The IO region is specified in the dev structure fields.
 * Since OTG uses same IO ports as Host Controller and OTG driver
 * depends on HCD, by the time OTG is loaded HCD has already been loaded
 * and if HC is using IO resources, we say OTG can access the IO resources
 * for HCD and DCD we use system call check_region()
 */
int	isp1362_check_io_region(struct isp1362_dev *dev)
{
	func_debug(("isp1362_check_io_region(dev=%p)\n",dev))

	/* If OTG driver, check the IO resources of HCD
	 */
	if(dev->index == ISP1362_OTG) {
		if(isp1362_loc_dev[ISP1362_HC].io_res) return 0;
		else return -EBUSY;
		
	}
	return check_region(dev->io_base, dev->io_len);
} /* End of isp1362_check_io_region */

/* This fuction assigns IO region to the driver
 * The IO region is specified in the "dev" structure fields.
 * Since OTG uses same IO ports as Host Controller and OTG driver
 * depends on HCD, for OTG driver the HCD io resources are returned
 * for HCD and DCD we use system call request_region()
 */
struct resource*	isp1362_request_io_region(struct isp1362_dev	*dev)
{
	func_debug(("isp1362_request_io_region(dev=%p)\n",dev))

	hal_data.io_usage++;

	if(dev->index == ISP1362_OTG) {
		/* If OTG return the HCD io resources */
		dev->io_res = isp1362_loc_dev[ISP1362_HC].io_res;
	} else {
		/* Store the IO resources */
		dev->io_res = request_region(dev->io_base, dev->io_len, isp1362_driver_name);
	}

	return dev->io_res;
} /* End of isp1362_request_io_region */

/* This fuction releases IO region for the driver
 * The IO region is specified in the "dev" structure fields.
 * Since OTG uses same IO ports as Host Controller and OTG driver
 * depends on HCD, for OTG driver nothing is done
 * for HCD and DCD we use system call release_region()
 */
void isp1362_release_io_region(struct isp1362_dev *dev)
{
	func_debug(("isp1362_release_io_region(dev=%p)\n",dev))
	hal_data.io_usage--;
	dev->io_res = NULL;
	if(dev->index == ISP1362_OTG)	return;

	return release_region(dev->io_base, dev->io_len);	
} /* End of isp1362_release_io_region */

/*--------------------------------------------------------------*
 *            Interrupt Management Functions
 *--------------------------------------------------------------*/

/* This function registers the ISR of driver with this driver.
 * Since there is only one interrupt line, when the first driver
 * is registerd, will call the system function request_irq. The PLX
 * bridge needs enabling of interrupt in the interrupt control register to 
 * pass the local interrupts to the PCI (cpu).
 * For later registrations will just update the variables. On ISR, this driver
 * will look for registered handlers and calls the corresponding driver's
 * ISR "handler" function with "isr_data" as parameter.
 */
int isp1362_request_irq(void (*handler)(struct isp1362_dev *, void *),
                       struct isp1362_dev *dev, void *isr_data) 
{
	int result = 0;
	__u16	intcsr;

	func_debug(("isp1362_request_irq(handler=%p,dev=%p,isr_data=%p)\n",handler,dev,isr_data))
	if(!(hal_data.irq_usage)) {
		/* If this is the first request 
		 */
   		result= request_irq(dev->irq,isp1362_pci_isr,
				SA_SHIRQ, isp1362_driver_name, 
				(void*)isp1362_loc_dev);
	}

	hal_data.irq_usage++;

	if(result >= 0) {
		if(hal_data.irq_usage == 1) {

			/* If this is the first request 
			 */
			intcsr = inb(pci_io_base + PLX_INT_CSR_REG+1);
			intcsr |= 0x09;
			outb(intcsr,(pci_io_base + PLX_INT_CSR_REG+1));
			func_debug(("Enabling PLX bridge local/cpu interrupts\n"))
		}
		dev->handler = handler;
		dev->isr_data = isr_data;
	}
	return result;
} /* End of isp1362_request_irq */

/* This function de-registers the ISR of driver with this driver.
 * Since there is only one interrupt line, when the last driver
 * is de-registerd, will call the system function free_irq. The PLX
 * bridge needs disabling of interrupt in the interrupt control register to 
 * block the local interrupts to the PCI (cpu).
 */
void isp1362_free_irq(struct isp1362_dev *dev, void *isr_data)
{
	__u16	intcsr;

	func_debug(("isp1362_free_irq(dev=%p,isr_data=%p)\n",dev,isr_data))

	hal_data.irq_usage--;

	if(!hal_data.irq_usage) {
		/* If this is the last free request
		 */
		free_irq(dev->irq,isp1362_loc_dev);
		intcsr = inb(pci_io_base + PLX_INT_CSR_REG+1);
		intcsr &= 0xF6;
		outb(intcsr,(pci_io_base + PLX_INT_CSR_REG+1));
		detail_debug(("disabling PLX bridge local/PCI interrupts"))
	}
		
} /* isp1362_free_irq */




/*--------------------------------------------------------------*
 *            Driver Registration Functions
 *--------------------------------------------------------------*/

/* This function is used by top driver (OTG, HCD, DCD) to register
 * their communication functions (probe, remove, suspend, resume) using
 * the drv data structure.
 * This function will call the probe function of the driver if the ISP1362
 * corresponding to the driver is enabled
 */
int	isp1362_register_driver(struct isp1362_driver *drv) 
{

	struct isp1362_dev	*dev;
	int	result;

	func_debug(("isp1362_register_driver(drv=%p)\n",drv))

	if(!drv) return -EINVAL;

	dev = &isp1362_loc_dev[drv->index];

	if(dev->active) result = drv->probe(dev);
	else result = -ENODEV;

	if(result >= 0 ) {
		isp1362_printk(KERN_INFO __FILE__ ": Registered Driver %s\n",drv->name);
		dev->driver = drv;
	}

	return result;
} /* End of isp1362_register_driver */

/* This function is used by top driver (OTG, HCD, DCD) to de-register
 * their communication functions (probe, remove, suspend, resume) using
 * the drv data structure.
 * This function will check whether the driver is registered or not and
 * call the remove function of the driver if registered
 */
void	isp1362_unregister_driver(struct isp1362_driver *drv)
{
	struct isp1362_dev	*dev;

	func_debug(("isp1362_unregister_driver(drv=%p)\n",drv))

	dev = &isp1362_loc_dev[drv->index];
	if(dev->driver == drv) {
		/* driver registered is same as the requestig driver */
		drv->remove(dev);
#ifndef CONFIG_USB_OTG
		if(drv->index == ISP1362_HC || drv->index == ISP1362_DC) {
			/* SET OTG Cofiguration to default */
			isp1362_reg_write16((&isp1362_loc_dev[ISP1362_OTG]),(OTG_CONTROL_REG|0x80),(OTG_SEL_HC_DC|OTG_LOC_PULLDN_DM|OTG_LOC_PULLDN_DP));
		}
#endif /* CONFIG_USB_OTG */
		dev->driver = NULL;
		isp1362_printk(KERN_INFO __FILE__ ": De-registered Driver %s\n",drv->name);
		return;
	}
} /* End of isp1362_unregister_driver */






/*--------------------------------------------------------------*
 *                 Module Management Functions
 *--------------------------------------------------------------*/

/* This  is the module initialization function. It registers to 
 * PCI driver for a PLX PCI bridge device. And also resets the
 * internal data structures before registering to PCI driver.
 */
static int __init isp1362_pci_module_init (void) 
{

	int	result = 0;

	func_debug(("isp1362_pci_module_init(void)\n"))

	memset(isp1362_loc_dev,0,sizeof(isp1362_loc_dev));

	if((result = pci_module_init(&isp1362_pci_driver)) < 0) {
		isp1362_printk(KERN_INFO __FILE__ ": %s Iinitialization Failed (error = %d)\n",isp1362_driver_name,result);
		return result;
	}

	isp1362_printk(KERN_INFO __FILE__ ": %s Initialization Success \n",isp1362_driver_name);
	return result;
}

/* This  is the module eleanup function. It de-registers from 
 * PCI driver and resets the internal data structures.
 */
static void __exit isp1362_pci_module_cleanup (void) 
{

	func_debug(("isp1362_pci_module_cleanup(void)\n"))
	pci_unregister_driver (&isp1362_pci_driver);
	memset(isp1362_loc_dev,0,sizeof(isp1362_loc_dev));
}  

module_init (isp1362_pci_module_init);
module_exit (isp1362_pci_module_cleanup);

MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -