diff options
Diffstat (limited to 'drivers/usb/host/ehci-exynos.c')
| -rw-r--r-- | drivers/usb/host/ehci-exynos.c | 92 | 
1 files changed, 85 insertions, 7 deletions
| diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 9f0ed06a8..3ca4c5c33 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -21,13 +21,71 @@   */  #include <common.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <malloc.h>  #include <usb.h>  #include <asm/arch/cpu.h>  #include <asm/arch/ehci.h>  #include <asm/arch/system.h>  #include <asm/arch/power.h> +#include <asm-generic/errno.h> +#include <linux/compat.h>  #include "ehci.h" +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +/** + * Contains pointers to register base addresses + * for the usb controller. + */ +struct exynos_ehci { +	struct exynos_usb_phy *usb; +	unsigned int *hcd; +}; + +static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos) +{ +	unsigned int node; +	int depth; + +	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI); +	if (node <= 0) { +		debug("EHCI: Can't get device node for ehci\n"); +		return -ENODEV; +	} + +	/* +	 * Get the base address for EHCI controller from the device node +	 */ +	exynos->hcd = (unsigned int *)fdtdec_get_addr(blob, node, "reg"); +	if (exynos->hcd == NULL) { +		debug("Can't get the EHCI register address\n"); +		return -ENXIO; +	} + +	depth = 0; +	node = fdtdec_next_compatible_subnode(blob, node, +					COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth); +	if (node <= 0) { +		debug("EHCI: Can't get device node for usb-phy controller\n"); +		return -ENODEV; +	} + +	/* +	 * Get the base address for usbphy from the device node +	 */ +	exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node, +								"reg"); +	if (exynos->usb == NULL) { +		debug("Can't get the usbphy register address\n"); +		return -ENXIO; +	} + +	return 0; +} +  /* Setup the EHCI host controller. */  static void setup_usb_phy(struct exynos_usb_phy *usb)  { @@ -86,12 +144,20 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)   */  int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)  { -	struct exynos_usb_phy *usb; +	struct exynos_ehci *exynos = NULL; + +	exynos = (struct exynos_ehci *) +			kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL); +	if (!exynos) { +		debug("failed to allocate exynos ehci context\n"); +		return -ENOMEM; +	} + +	exynos_usb_parse_dt(gd->fdt_blob, exynos); -	usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); -	setup_usb_phy(usb); +	setup_usb_phy(exynos->usb); -	*hccr = (struct ehci_hccr *)samsung_get_base_usb_ehci(); +	*hccr = (struct ehci_hccr *)(exynos->hcd);  	*hcor = (struct ehci_hcor *)((uint32_t) *hccr  				+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); @@ -99,6 +165,8 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)  		(uint32_t)*hccr, (uint32_t)*hcor,  		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); +	kfree(exynos); +  	return 0;  } @@ -108,10 +176,20 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)   */  int ehci_hcd_stop(int index)  { -	struct exynos_usb_phy *usb; +	struct exynos_ehci *exynos = NULL; + +	exynos = (struct exynos_ehci *) +			kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL); +	if (!exynos) { +		debug("failed to allocate exynos ehci context\n"); +		return -ENOMEM; +	} + +	exynos_usb_parse_dt(gd->fdt_blob, exynos); + +	reset_usb_phy(exynos->usb); -	usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); -	reset_usb_phy(usb); +	kfree(exynos);  	return 0;  } |