diff options
-rw-r--r-- | drivers/usb/gadget/s3c-hsotg.c | 167 |
1 files changed, 100 insertions, 67 deletions
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index ca9041634c04..84793a0ee506 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
@@ -128,8 +128,6 @@ struct s3c_hsotg_ep { | |||
128 | char name[10]; | 128 | char name[10]; |
129 | }; | 129 | }; |
130 | 130 | ||
131 | #define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */ | ||
132 | |||
133 | /** | 131 | /** |
134 | * struct s3c_hsotg - driver state. | 132 | * struct s3c_hsotg - driver state. |
135 | * @dev: The parent device supplied to the probe function | 133 | * @dev: The parent device supplied to the probe function |
@@ -140,6 +138,7 @@ struct s3c_hsotg_ep { | |||
140 | * @irq: The IRQ number we are using | 138 | * @irq: The IRQ number we are using |
141 | * @supplies: Definition of USB power supplies | 139 | * @supplies: Definition of USB power supplies |
142 | * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. | 140 | * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. |
141 | * @num_of_eps: Number of available EPs (excluding EP0) | ||
143 | * @debug_root: root directrory for debugfs. | 142 | * @debug_root: root directrory for debugfs. |
144 | * @debug_file: main status file for debugfs. | 143 | * @debug_file: main status file for debugfs. |
145 | * @debug_fifo: FIFO status file for debugfs. | 144 | * @debug_fifo: FIFO status file for debugfs. |
@@ -164,6 +163,7 @@ struct s3c_hsotg { | |||
164 | struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; | 163 | struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; |
165 | 164 | ||
166 | unsigned int dedicated_fifos:1; | 165 | unsigned int dedicated_fifos:1; |
166 | unsigned char num_of_eps; | ||
167 | 167 | ||
168 | struct dentry *debug_root; | 168 | struct dentry *debug_root; |
169 | struct dentry *debug_file; | 169 | struct dentry *debug_file; |
@@ -177,7 +177,7 @@ struct s3c_hsotg { | |||
177 | struct usb_gadget gadget; | 177 | struct usb_gadget gadget; |
178 | unsigned int setup; | 178 | unsigned int setup; |
179 | unsigned long last_rst; | 179 | unsigned long last_rst; |
180 | struct s3c_hsotg_ep eps[]; | 180 | struct s3c_hsotg_ep *eps; |
181 | }; | 181 | }; |
182 | 182 | ||
183 | /** | 183 | /** |
@@ -952,7 +952,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, | |||
952 | if (windex >= 0x100) | 952 | if (windex >= 0x100) |
953 | return NULL; | 953 | return NULL; |
954 | 954 | ||
955 | if (idx > S3C_HSOTG_EPS) | 955 | if (idx > hsotg->num_of_eps) |
956 | return NULL; | 956 | return NULL; |
957 | 957 | ||
958 | if (idx && ep->dir_in != dir) | 958 | if (idx && ep->dir_in != dir) |
@@ -2036,7 +2036,7 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) | |||
2036 | if (ep0_mps) { | 2036 | if (ep0_mps) { |
2037 | int i; | 2037 | int i; |
2038 | s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); | 2038 | s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); |
2039 | for (i = 1; i < S3C_HSOTG_EPS; i++) | 2039 | for (i = 1; i < hsotg->num_of_eps; i++) |
2040 | s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); | 2040 | s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); |
2041 | } | 2041 | } |
2042 | 2042 | ||
@@ -2099,7 +2099,7 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) | |||
2099 | { | 2099 | { |
2100 | unsigned ep; | 2100 | unsigned ep; |
2101 | 2101 | ||
2102 | for (ep = 0; ep < S3C_HSOTG_EPS; ep++) | 2102 | for (ep = 0; ep < hsotg->num_of_eps; ep++) |
2103 | kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); | 2103 | kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); |
2104 | 2104 | ||
2105 | call_gadget(hsotg, disconnect); | 2105 | call_gadget(hsotg, disconnect); |
@@ -2117,7 +2117,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) | |||
2117 | 2117 | ||
2118 | /* look through for any more data to transmit */ | 2118 | /* look through for any more data to transmit */ |
2119 | 2119 | ||
2120 | for (epno = 0; epno < S3C_HSOTG_EPS; epno++) { | 2120 | for (epno = 0; epno < hsotg->num_of_eps; epno++) { |
2121 | ep = &hsotg->eps[epno]; | 2121 | ep = &hsotg->eps[epno]; |
2122 | 2122 | ||
2123 | if (!ep->dir_in) | 2123 | if (!ep->dir_in) |
@@ -2783,6 +2783,45 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) | |||
2783 | hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); | 2783 | hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); |
2784 | } | 2784 | } |
2785 | 2785 | ||
2786 | static void s3c_hsotg_init(struct s3c_hsotg *hsotg) | ||
2787 | { | ||
2788 | /* unmask subset of endpoint interrupts */ | ||
2789 | |||
2790 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | | ||
2791 | S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, | ||
2792 | hsotg->regs + S3C_DIEPMSK); | ||
2793 | |||
2794 | writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | | ||
2795 | S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, | ||
2796 | hsotg->regs + S3C_DOEPMSK); | ||
2797 | |||
2798 | writel(0, hsotg->regs + S3C_DAINTMSK); | ||
2799 | |||
2800 | /* Be in disconnected state until gadget is registered */ | ||
2801 | __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); | ||
2802 | |||
2803 | if (0) { | ||
2804 | /* post global nak until we're ready */ | ||
2805 | writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, | ||
2806 | hsotg->regs + S3C_DCTL); | ||
2807 | } | ||
2808 | |||
2809 | /* setup fifos */ | ||
2810 | |||
2811 | dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", | ||
2812 | readl(hsotg->regs + S3C_GRXFSIZ), | ||
2813 | readl(hsotg->regs + S3C_GNPTXFSIZ)); | ||
2814 | |||
2815 | s3c_hsotg_init_fifo(hsotg); | ||
2816 | |||
2817 | /* set the PLL on, remove the HNP/SRP and set the PHY */ | ||
2818 | writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), | ||
2819 | hsotg->regs + S3C_GUSBCFG); | ||
2820 | |||
2821 | writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, | ||
2822 | hsotg->regs + S3C_GAHBCFG); | ||
2823 | } | ||
2824 | |||
2786 | static int s3c_hsotg_start(struct usb_gadget_driver *driver, | 2825 | static int s3c_hsotg_start(struct usb_gadget_driver *driver, |
2787 | int (*bind)(struct usb_gadget *)) | 2826 | int (*bind)(struct usb_gadget *)) |
2788 | { | 2827 | { |
@@ -2853,7 +2892,7 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver) | |||
2853 | return -EINVAL; | 2892 | return -EINVAL; |
2854 | 2893 | ||
2855 | /* all endpoints should be shutdown */ | 2894 | /* all endpoints should be shutdown */ |
2856 | for (ep = 0; ep < S3C_HSOTG_EPS; ep++) | 2895 | for (ep = 0; ep < hsotg->num_of_eps; ep++) |
2857 | s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); | 2896 | s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); |
2858 | 2897 | ||
2859 | call_gadget(hsotg, disconnect); | 2898 | call_gadget(hsotg, disconnect); |
@@ -2944,53 +2983,28 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, | |||
2944 | } | 2983 | } |
2945 | } | 2984 | } |
2946 | 2985 | ||
2947 | static void s3c_hsotg_init(struct s3c_hsotg *hsotg) | 2986 | /** |
2987 | * s3c_hsotg_hw_cfg - read HW configuration registers | ||
2988 | * @param: The device state | ||
2989 | * | ||
2990 | * Read the USB core HW configuration registers | ||
2991 | */ | ||
2992 | static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) | ||
2948 | { | 2993 | { |
2949 | u32 cfg4; | 2994 | u32 cfg2, cfg4; |
2950 | 2995 | /* check hardware configuration */ | |
2951 | /* unmask subset of endpoint interrupts */ | ||
2952 | |||
2953 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | | ||
2954 | S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, | ||
2955 | hsotg->regs + S3C_DIEPMSK); | ||
2956 | |||
2957 | writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | | ||
2958 | S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, | ||
2959 | hsotg->regs + S3C_DOEPMSK); | ||
2960 | |||
2961 | writel(0, hsotg->regs + S3C_DAINTMSK); | ||
2962 | |||
2963 | /* Be in disconnected state until gadget is registered */ | ||
2964 | __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); | ||
2965 | |||
2966 | if (0) { | ||
2967 | /* post global nak until we're ready */ | ||
2968 | writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, | ||
2969 | hsotg->regs + S3C_DCTL); | ||
2970 | } | ||
2971 | |||
2972 | /* setup fifos */ | ||
2973 | |||
2974 | dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", | ||
2975 | readl(hsotg->regs + S3C_GRXFSIZ), | ||
2976 | readl(hsotg->regs + S3C_GNPTXFSIZ)); | ||
2977 | |||
2978 | s3c_hsotg_init_fifo(hsotg); | ||
2979 | |||
2980 | /* set the PLL on, remove the HNP/SRP and set the PHY */ | ||
2981 | writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), | ||
2982 | hsotg->regs + S3C_GUSBCFG); | ||
2983 | 2996 | ||
2984 | writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, | 2997 | cfg2 = readl(hsotg->regs + 0x48); |
2985 | hsotg->regs + S3C_GAHBCFG); | 2998 | hsotg->num_of_eps = (cfg2 >> 10) & 0xF; |
2986 | 2999 | ||
2987 | /* check hardware configuration */ | 3000 | dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); |
2988 | 3001 | ||
2989 | cfg4 = readl(hsotg->regs + 0x50); | 3002 | cfg4 = readl(hsotg->regs + 0x50); |
2990 | hsotg->dedicated_fifos = (cfg4 >> 25) & 1; | 3003 | hsotg->dedicated_fifos = (cfg4 >> 25) & 1; |
2991 | 3004 | ||
2992 | dev_info(hsotg->dev, "%s fifos\n", | 3005 | dev_info(hsotg->dev, "%s fifos\n", |
2993 | hsotg->dedicated_fifos ? "dedicated" : "shared"); | 3006 | hsotg->dedicated_fifos ? "dedicated" : "shared"); |
3007 | |||
2994 | } | 3008 | } |
2995 | 3009 | ||
2996 | static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) | 3010 | static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) |
@@ -3284,7 +3298,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) | |||
3284 | 3298 | ||
3285 | /* create one file for each endpoint */ | 3299 | /* create one file for each endpoint */ |
3286 | 3300 | ||
3287 | for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { | 3301 | for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { |
3288 | struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; | 3302 | struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; |
3289 | 3303 | ||
3290 | ep->debugfs = debugfs_create_file(ep->name, 0444, | 3304 | ep->debugfs = debugfs_create_file(ep->name, 0444, |
@@ -3306,7 +3320,7 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) | |||
3306 | { | 3320 | { |
3307 | unsigned epidx; | 3321 | unsigned epidx; |
3308 | 3322 | ||
3309 | for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { | 3323 | for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { |
3310 | struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; | 3324 | struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; |
3311 | debugfs_remove(ep->debugfs); | 3325 | debugfs_remove(ep->debugfs); |
3312 | } | 3326 | } |
@@ -3320,6 +3334,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
3320 | { | 3334 | { |
3321 | struct s3c_hsotg_plat *plat = pdev->dev.platform_data; | 3335 | struct s3c_hsotg_plat *plat = pdev->dev.platform_data; |
3322 | struct device *dev = &pdev->dev; | 3336 | struct device *dev = &pdev->dev; |
3337 | struct s3c_hsotg_ep *eps; | ||
3323 | struct s3c_hsotg *hsotg; | 3338 | struct s3c_hsotg *hsotg; |
3324 | struct resource *res; | 3339 | struct resource *res; |
3325 | int epnum; | 3340 | int epnum; |
@@ -3332,9 +3347,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
3332 | return -EINVAL; | 3347 | return -EINVAL; |
3333 | } | 3348 | } |
3334 | 3349 | ||
3335 | hsotg = kzalloc(sizeof(struct s3c_hsotg) + | 3350 | hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL); |
3336 | sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS, | ||
3337 | GFP_KERNEL); | ||
3338 | if (!hsotg) { | 3351 | if (!hsotg) { |
3339 | dev_err(dev, "cannot get memory\n"); | 3352 | dev_err(dev, "cannot get memory\n"); |
3340 | return -ENOMEM; | 3353 | return -ENOMEM; |
@@ -3401,20 +3414,6 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
3401 | hsotg->gadget.dev.parent = dev; | 3414 | hsotg->gadget.dev.parent = dev; |
3402 | hsotg->gadget.dev.dma_mask = dev->dma_mask; | 3415 | hsotg->gadget.dev.dma_mask = dev->dma_mask; |
3403 | 3416 | ||
3404 | /* setup endpoint information */ | ||
3405 | |||
3406 | INIT_LIST_HEAD(&hsotg->gadget.ep_list); | ||
3407 | hsotg->gadget.ep0 = &hsotg->eps[0].ep; | ||
3408 | |||
3409 | /* allocate EP0 request */ | ||
3410 | |||
3411 | hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, | ||
3412 | GFP_KERNEL); | ||
3413 | if (!hsotg->ctrl_req) { | ||
3414 | dev_err(dev, "failed to allocate ctrl req\n"); | ||
3415 | goto err_regs; | ||
3416 | } | ||
3417 | |||
3418 | /* reset the system */ | 3417 | /* reset the system */ |
3419 | 3418 | ||
3420 | clk_enable(hsotg->clk); | 3419 | clk_enable(hsotg->clk); |
@@ -3444,14 +3443,45 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
3444 | 3443 | ||
3445 | s3c_hsotg_corereset(hsotg); | 3444 | s3c_hsotg_corereset(hsotg); |
3446 | s3c_hsotg_init(hsotg); | 3445 | s3c_hsotg_init(hsotg); |
3446 | s3c_hsotg_hw_cfg(hsotg); | ||
3447 | |||
3448 | /* hsotg->num_of_eps holds number of EPs other than ep0 */ | ||
3449 | |||
3450 | if (hsotg->num_of_eps == 0) { | ||
3451 | dev_err(dev, "wrong number of EPs (zero)\n"); | ||
3452 | goto err_supplies; | ||
3453 | } | ||
3454 | |||
3455 | eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), | ||
3456 | GFP_KERNEL); | ||
3457 | if (!eps) { | ||
3458 | dev_err(dev, "cannot get memory\n"); | ||
3459 | goto err_supplies; | ||
3460 | } | ||
3461 | |||
3462 | hsotg->eps = eps; | ||
3463 | |||
3464 | /* setup endpoint information */ | ||
3465 | |||
3466 | INIT_LIST_HEAD(&hsotg->gadget.ep_list); | ||
3467 | hsotg->gadget.ep0 = &hsotg->eps[0].ep; | ||
3468 | |||
3469 | /* allocate EP0 request */ | ||
3470 | |||
3471 | hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, | ||
3472 | GFP_KERNEL); | ||
3473 | if (!hsotg->ctrl_req) { | ||
3474 | dev_err(dev, "failed to allocate ctrl req\n"); | ||
3475 | goto err_ep_mem; | ||
3476 | } | ||
3447 | 3477 | ||
3448 | /* initialise the endpoints now the core has been initialised */ | 3478 | /* initialise the endpoints now the core has been initialised */ |
3449 | for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) | 3479 | for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) |
3450 | s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); | 3480 | s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); |
3451 | 3481 | ||
3452 | ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); | 3482 | ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); |
3453 | if (ret) | 3483 | if (ret) |
3454 | goto err_supplies; | 3484 | goto err_ep_mem; |
3455 | 3485 | ||
3456 | s3c_hsotg_create_debug(hsotg); | 3486 | s3c_hsotg_create_debug(hsotg); |
3457 | 3487 | ||
@@ -3460,6 +3490,9 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) | |||
3460 | our_hsotg = hsotg; | 3490 | our_hsotg = hsotg; |
3461 | return 0; | 3491 | return 0; |
3462 | 3492 | ||
3493 | err_ep_mem: | ||
3494 | kfree(eps); | ||
3495 | |||
3463 | err_supplies: | 3496 | err_supplies: |
3464 | s3c_hsotg_phy_disable(hsotg); | 3497 | s3c_hsotg_phy_disable(hsotg); |
3465 | 3498 | ||