aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorNate Case <ncase@xes-inc.com>2008-06-17 12:11:38 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:16:33 -0400
commit3faefc88c1a32b0b4a00b9089fab5d917996b16c (patch)
tree705994b76bea1968e3ae7d4149bd77139374220c /drivers/usb/host
parent6d243e5c76b632a94d54cac2fe7fe8c0b41cd482 (diff)
USB: isp1760: Support board-specific hardware configurations
This adds support for hardware configurations that don't match the chip default register settings (e.g., 16-bit data bus, DACK and DREQ pulled up instead of down, analog overcurrent mode). These settings are passed in via the OF device tree. The PCI interface still assumes the same default values. Signed-off-by: Nate Case <ncase@xes-inc.com> Acked-by: Olof Johansson <olof@lixom.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/isp1760-hcd.c67
-rw-r--r--drivers/usb/host/isp1760-hcd.h20
-rw-r--r--drivers/usb/host/isp1760-if.c35
3 files changed, 104 insertions, 18 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index d318af39c27f..c858f2adb929 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -38,6 +38,7 @@ struct isp1760_hcd {
38 unsigned i_thresh; 38 unsigned i_thresh;
39 unsigned long reset_done; 39 unsigned long reset_done;
40 unsigned long next_statechange; 40 unsigned long next_statechange;
41 unsigned int devflags;
41}; 42};
42 43
43static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) 44static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
@@ -378,9 +379,31 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
378{ 379{
379 struct isp1760_hcd *priv = hcd_to_priv(hcd); 380 struct isp1760_hcd *priv = hcd_to_priv(hcd);
380 int result; 381 int result;
381 u32 scratch; 382 u32 scratch, hwmode;
383
384 /* Setup HW Mode Control: This assumes a level active-low interrupt */
385 hwmode = HW_DATA_BUS_32BIT;
386
387 if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
388 hwmode &= ~HW_DATA_BUS_32BIT;
389 if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
390 hwmode |= HW_ANA_DIGI_OC;
391 if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
392 hwmode |= HW_DACK_POL_HIGH;
393 if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
394 hwmode |= HW_DREQ_POL_HIGH;
395
396 /*
397 * We have to set this first in case we're in 16-bit mode.
398 * Write it twice to ensure correct upper bits if switching
399 * to 16-bit mode.
400 */
401 isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL);
402 isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL);
382 403
383 isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); 404 isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG);
405 /* Change bus pattern */
406 scratch = isp1760_readl(hcd->regs + HC_CHIP_ID_REG);
384 scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); 407 scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG);
385 if (scratch != 0xdeadbabe) { 408 if (scratch != 0xdeadbabe) {
386 printk(KERN_ERR "ISP1760: Scratch test failed.\n"); 409 printk(KERN_ERR "ISP1760: Scratch test failed.\n");
@@ -403,17 +426,29 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
403 426
404 /* Step 11 passed */ 427 /* Step 11 passed */
405 428
406 isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); 429 isp1760_info(priv, "bus width: %d, oc: %s\n",
407 isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); 430 (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
431 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
432 "analog" : "digital");
408 433
409 /* ATL reset */ 434 /* ATL reset */
410 scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); 435 isp1760_writel(hwmode | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
411 isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
412 mdelay(10); 436 mdelay(10);
413 isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL); 437 isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL);
414 438
415 isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL); 439 isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG);
416 mdelay(10); 440 isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE);
441
442 /*
443 * PORT 1 Control register of the ISP1760 is the OTG control
444 * register on ISP1761.
445 */
446 if (!(priv->devflags & ISP1760_FLAG_ISP1761) &&
447 !(priv->devflags & ISP1760_FLAG_PORT1_DIS)) {
448 isp1760_writel(PORT1_POWER | PORT1_INIT2,
449 hcd->regs + HC_PORT1_CTRL);
450 mdelay(10);
451 }
417 452
418 priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); 453 priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
419 454
@@ -453,8 +488,7 @@ static int isp1760_run(struct usb_hcd *hcd)
453 hcd->state = HC_STATE_RUNNING; 488 hcd->state = HC_STATE_RUNNING;
454 isp1760_enable_interrupts(hcd); 489 isp1760_enable_interrupts(hcd);
455 temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); 490 temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
456 temp |= FINAL_HW_CONFIG; 491 isp1760_writel(temp | HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL);
457 isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL);
458 492
459 command = isp1760_readl(hcd->regs + HC_USBCMD); 493 command = isp1760_readl(hcd->regs + HC_USBCMD);
460 command &= ~(CMD_LRESET|CMD_RESET); 494 command &= ~(CMD_LRESET|CMD_RESET);
@@ -2112,6 +2146,7 @@ static int isp1760_get_frame(struct usb_hcd *hcd)
2112static void isp1760_stop(struct usb_hcd *hcd) 2146static void isp1760_stop(struct usb_hcd *hcd)
2113{ 2147{
2114 struct isp1760_hcd *priv = hcd_to_priv(hcd); 2148 struct isp1760_hcd *priv = hcd_to_priv(hcd);
2149 u32 temp;
2115 2150
2116 isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, 2151 isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
2117 NULL, 0); 2152 NULL, 0);
@@ -2120,7 +2155,8 @@ static void isp1760_stop(struct usb_hcd *hcd)
2120 spin_lock_irq(&priv->lock); 2155 spin_lock_irq(&priv->lock);
2121 ehci_reset(priv); 2156 ehci_reset(priv);
2122 /* Disable IRQ */ 2157 /* Disable IRQ */
2123 isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); 2158 temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
2159 isp1760_writel(temp &= ~HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL);
2124 spin_unlock_irq(&priv->lock); 2160 spin_unlock_irq(&priv->lock);
2125 2161
2126 isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); 2162 isp1760_writel(0, hcd->regs + HC_CONFIGFLAG);
@@ -2128,10 +2164,11 @@ static void isp1760_stop(struct usb_hcd *hcd)
2128 2164
2129static void isp1760_shutdown(struct usb_hcd *hcd) 2165static void isp1760_shutdown(struct usb_hcd *hcd)
2130{ 2166{
2131 u32 command; 2167 u32 command, temp;
2132 2168
2133 isp1760_stop(hcd); 2169 isp1760_stop(hcd);
2134 isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); 2170 temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
2171 isp1760_writel(temp &= ~HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL);
2135 2172
2136 command = isp1760_readl(hcd->regs + HC_USBCMD); 2173 command = isp1760_readl(hcd->regs + HC_USBCMD);
2137 command &= ~CMD_RUN; 2174 command &= ~CMD_RUN;
@@ -2183,7 +2220,8 @@ void deinit_kmem_cache(void)
2183} 2220}
2184 2221
2185struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, 2222struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
2186 u64 irqflags, struct device *dev, const char *busname) 2223 u64 irqflags, struct device *dev, const char *busname,
2224 unsigned int devflags)
2187{ 2225{
2188 struct usb_hcd *hcd; 2226 struct usb_hcd *hcd;
2189 struct isp1760_hcd *priv; 2227 struct isp1760_hcd *priv;
@@ -2200,6 +2238,7 @@ struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
2200 return ERR_PTR(-ENOMEM); 2238 return ERR_PTR(-ENOMEM);
2201 2239
2202 priv = hcd_to_priv(hcd); 2240 priv = hcd_to_priv(hcd);
2241 priv->devflags = devflags;
2203 init_memory(priv); 2242 init_memory(priv);
2204 hcd->regs = ioremap(res_start, res_len); 2243 hcd->regs = ioremap(res_start, res_len);
2205 if (!hcd->regs) { 2244 if (!hcd->regs) {
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
index 3d86d0f6b147..6473dd86993c 100644
--- a/drivers/usb/host/isp1760-hcd.h
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -3,7 +3,8 @@
3 3
4/* exports for if */ 4/* exports for if */
5struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, 5struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
6 u64 irqflags, struct device *dev, const char *busname); 6 u64 irqflags, struct device *dev, const char *busname,
7 unsigned int devflags);
7int init_kmem_once(void); 8int init_kmem_once(void);
8void deinit_kmem_cache(void); 9void deinit_kmem_cache(void);
9 10
@@ -31,6 +32,7 @@ void deinit_kmem_cache(void);
31/* Configuration Register */ 32/* Configuration Register */
32#define HC_HW_MODE_CTRL 0x300 33#define HC_HW_MODE_CTRL 0x300
33#define ALL_ATX_RESET (1 << 31) 34#define ALL_ATX_RESET (1 << 31)
35#define HW_ANA_DIGI_OC (1 << 15)
34#define HW_DATA_BUS_32BIT (1 << 8) 36#define HW_DATA_BUS_32BIT (1 << 8)
35#define HW_DACK_POL_HIGH (1 << 6) 37#define HW_DACK_POL_HIGH (1 << 6)
36#define HW_DREQ_POL_HIGH (1 << 5) 38#define HW_DREQ_POL_HIGH (1 << 5)
@@ -56,13 +58,14 @@ void deinit_kmem_cache(void);
56#define PORT1_POWER (3 << 3) 58#define PORT1_POWER (3 << 3)
57#define PORT1_INIT1 (1 << 7) 59#define PORT1_INIT1 (1 << 7)
58#define PORT1_INIT2 (1 << 23) 60#define PORT1_INIT2 (1 << 23)
61#define HW_OTG_CTRL_SET 0x374
62#define HW_OTG_CTRL_CLR 0x376
59 63
60/* Interrupt Register */ 64/* Interrupt Register */
61#define HC_INTERRUPT_REG 0x310 65#define HC_INTERRUPT_REG 0x310
62 66
63#define HC_INTERRUPT_ENABLE 0x314 67#define HC_INTERRUPT_ENABLE 0x314
64#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT) 68#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
65#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
66 69
67#define HC_ISO_INT (1 << 9) 70#define HC_ISO_INT (1 << 9)
68#define HC_ATL_INT (1 << 8) 71#define HC_ATL_INT (1 << 8)
@@ -122,6 +125,19 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
122#define isp1760_err(priv, fmt, args...) \ 125#define isp1760_err(priv, fmt, args...) \
123 dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args) 126 dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
124 127
128/*
129 * Device flags that can vary from board to board. All of these
130 * indicate the most "atypical" case, so that a devflags of 0 is
131 * a sane default configuration.
132 */
133#define ISP1760_FLAG_PORT1_DIS 0x00000001 /* Port 1 disabled */
134#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
135#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
136#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
137#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
138#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
139#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
140
125/* chip memory management */ 141/* chip memory management */
126struct memory_chunk { 142struct memory_chunk {
127 unsigned int start; 143 unsigned int start;
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index ad833661ff34..051ef7b6bdc6 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -35,6 +35,8 @@ static int of_isp1760_probe(struct of_device *dev,
35 int virq; 35 int virq;
36 u64 res_len; 36 u64 res_len;
37 int ret; 37 int ret;
38 const unsigned int *prop;
39 unsigned int devflags = 0;
38 40
39 ret = of_address_to_resource(dp, 0, &memory); 41 ret = of_address_to_resource(dp, 0, &memory);
40 if (ret) 42 if (ret)
@@ -55,8 +57,32 @@ static int of_isp1760_probe(struct of_device *dev,
55 virq = irq_create_of_mapping(oirq.controller, oirq.specifier, 57 virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
56 oirq.size); 58 oirq.size);
57 59
60 if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
61 devflags |= ISP1760_FLAG_ISP1761;
62
63 if (of_get_property(dp, "port1-disable", NULL) != NULL)
64 devflags |= ISP1760_FLAG_PORT1_DIS;
65
66 /* Some systems wire up only 16 of the 32 data lines */
67 prop = of_get_property(dp, "bus-width", NULL);
68 if (prop && *prop == 16)
69 devflags |= ISP1760_FLAG_BUS_WIDTH_16;
70
71 if (of_get_property(dp, "port1-otg", NULL) != NULL)
72 devflags |= ISP1760_FLAG_OTG_EN;
73
74 if (of_get_property(dp, "analog-oc", NULL) != NULL)
75 devflags |= ISP1760_FLAG_ANALOG_OC;
76
77 if (of_get_property(dp, "dack-polarity", NULL) != NULL)
78 devflags |= ISP1760_FLAG_DACK_POL_HIGH;
79
80 if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
81 devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
82
58 hcd = isp1760_register(memory.start, res_len, virq, 83 hcd = isp1760_register(memory.start, res_len, virq,
59 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev)); 84 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
85 devflags);
60 if (IS_ERR(hcd)) { 86 if (IS_ERR(hcd)) {
61 ret = PTR_ERR(hcd); 87 ret = PTR_ERR(hcd);
62 goto release_reg; 88 goto release_reg;
@@ -87,6 +113,9 @@ static struct of_device_id of_isp1760_match[] = {
87 { 113 {
88 .compatible = "nxp,usb-isp1760", 114 .compatible = "nxp,usb-isp1760",
89 }, 115 },
116 {
117 .compatible = "nxp,usb-isp1761",
118 },
90 { }, 119 { },
91}; 120};
92MODULE_DEVICE_TABLE(of, of_isp1760_match); 121MODULE_DEVICE_TABLE(of, of_isp1760_match);
@@ -116,6 +145,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
116 int length; 145 int length;
117 int status = 1; 146 int status = 1;
118 struct usb_hcd *hcd; 147 struct usb_hcd *hcd;
148 unsigned int devflags = 0;
119 149
120 if (usb_disabled()) 150 if (usb_disabled())
121 return -ENODEV; 151 return -ENODEV;
@@ -200,7 +230,8 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
200 230
201 dev->dev.dma_mask = NULL; 231 dev->dev.dma_mask = NULL;
202 hcd = isp1760_register(pci_mem_phy0, length, dev->irq, 232 hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
203 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev)); 233 IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
234 devflags);
204 pci_set_drvdata(dev, hcd); 235 pci_set_drvdata(dev, hcd);
205 if (!hcd) 236 if (!hcd)
206 return 0; 237 return 0;