/*
 *  linux/drivers/usb/usb-ohci-s3c2400.c
 *
 *	This code was taken from usb-ohci-sa1111.c and adapted
 *	for the s3c2400 microprocessor.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/usb.h>

#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>

#include "usb-ohci.h"

extern int hc_add_ohci(struct pci_dev *dev, int irq, void *membase,
		unsigned long flags, ohci_t **ohci, const char *name,
		const char *slot_name);
extern void hc_remove_ohci(ohci_t *ohci);

static ohci_t *s3c2400_ohci;

static int __init s3c2400_ohci_init(void)
{
	int ret;

	/*
	 * Request memory resources.
	 */
	if (!request_mem_region(USBHOSTBASE, USBHOSTSIZE, "usb-ohci"))
		return -EBUSY;

	/*
	 * Set the 48 MHz UPLL clocking. Values are taken from 
	 * "PLL value selection guide", 6-23, s3c2400_UM.pdf.
	 */
	rUPLLCON = ((40 << 12) + (1 << 4) + 2);
	rMISCCR |= 0x8; /* 1 = use pads related USB for USB host */

	/*
	 * Enable USB host block.
	 */
	rCLKCON |= CLKCON_USBH;

	/*
	 * Initialise the generic OHCI driver.
	 */
	ret = hc_add_ohci((struct pci_dev *)1, IRQ_USBH, (void *)USBHOSTBASE,
			0, &s3c2400_ohci, "usb-ohci", "s3c2400");

	if (ret) {
		/* Initialization failed */
		rCLKCON &= ~CLKCON_USBH;
		release_mem_region(USBHOSTBASE, USBHOSTSIZE);
	}
	
	return ret;
}

static void __exit s3c2400_ohci_exit(void)
{
	hc_remove_ohci(s3c2400_ohci);

	/*
	 * Disable USB host block.
	 */
	rCLKCON &= ~CLKCON_USBH;
	
	/*
	 * Release memory resources.
	 */
	release_mem_region(USBHOSTBASE, USBHOSTSIZE);
}

module_init(s3c2400_ohci_init);
module_exit(s3c2400_ohci_exit);
