]>
Commit | Line | Data |
---|---|---|
4b1a577d LP |
1 | /* |
2 | * Driver for the NXP ISP1760 chip | |
3 | * | |
4 | * Copyright 2014 Laurent Pinchart | |
5 | * Copyright 2007 Sebastian Siewior | |
6 | * | |
7 | * Contacts: | |
8 | * Sebastian Siewior <bigeasy@linutronix.de> | |
9 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License | |
13 | * version 2 as published by the Free Software Foundation. | |
14 | */ | |
15 | ||
5171446a LP |
16 | #include <linux/delay.h> |
17 | #include <linux/gpio/consumer.h> | |
4b1a577d LP |
18 | #include <linux/io.h> |
19 | #include <linux/kernel.h> | |
20 | #include <linux/module.h> | |
21 | #include <linux/slab.h> | |
22 | #include <linux/usb.h> | |
23 | ||
24 | #include "isp1760-core.h" | |
25 | #include "isp1760-hcd.h" | |
5171446a | 26 | #include "isp1760-regs.h" |
0316ca63 | 27 | #include "isp1760-udc.h" |
5171446a LP |
28 | |
29 | static void isp1760_init_core(struct isp1760_device *isp) | |
30 | { | |
0316ca63 | 31 | u32 otgctrl; |
5171446a LP |
32 | u32 hwmode; |
33 | ||
34 | /* Low-level chip reset */ | |
35 | if (isp->rst_gpio) { | |
36 | gpiod_set_value_cansleep(isp->rst_gpio, 1); | |
37 | mdelay(50); | |
38 | gpiod_set_value_cansleep(isp->rst_gpio, 0); | |
39 | } | |
40 | ||
41 | /* | |
42 | * Reset the host controller, including the CPU interface | |
43 | * configuration. | |
44 | */ | |
45 | isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL); | |
46 | msleep(100); | |
47 | ||
48 | /* Setup HW Mode Control: This assumes a level active-low interrupt */ | |
49 | hwmode = HW_DATA_BUS_32BIT; | |
50 | ||
51 | if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16) | |
52 | hwmode &= ~HW_DATA_BUS_32BIT; | |
53 | if (isp->devflags & ISP1760_FLAG_ANALOG_OC) | |
54 | hwmode |= HW_ANA_DIGI_OC; | |
55 | if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH) | |
56 | hwmode |= HW_DACK_POL_HIGH; | |
57 | if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH) | |
58 | hwmode |= HW_DREQ_POL_HIGH; | |
59 | if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH) | |
60 | hwmode |= HW_INTR_HIGH_ACT; | |
61 | if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) | |
62 | hwmode |= HW_INTR_EDGE_TRIG; | |
63 | ||
0316ca63 LP |
64 | /* |
65 | * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC | |
66 | * IRQ line for both the host and device controllers. Hardcode IRQ | |
67 | * sharing for now and disable the DC interrupts globally to avoid | |
68 | * spurious interrupts during HCD registration. | |
69 | */ | |
70 | if (isp->devflags & ISP1760_FLAG_ISP1761) { | |
71 | isp1760_write32(isp->regs, DC_MODE, 0); | |
72 | hwmode |= HW_COMN_IRQ; | |
73 | } | |
74 | ||
5171446a LP |
75 | /* |
76 | * We have to set this first in case we're in 16-bit mode. | |
77 | * Write it twice to ensure correct upper bits if switching | |
78 | * to 16-bit mode. | |
79 | */ | |
80 | isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode); | |
81 | isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode); | |
82 | ||
9a66e132 | 83 | /* |
0316ca63 LP |
84 | * PORT 1 Control register of the ISP1760 is the OTG control register |
85 | * on ISP1761. | |
86 | * | |
87 | * TODO: Really support OTG. For now we configure port 1 in device mode | |
88 | * when OTG is requested. | |
9a66e132 | 89 | */ |
0316ca63 LP |
90 | if ((isp->devflags & ISP1760_FLAG_ISP1761) && |
91 | (isp->devflags & ISP1760_FLAG_OTG_EN)) | |
92 | otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16) | |
93 | | HW_OTG_DISABLE; | |
94 | else | |
95 | otgctrl = (HW_SW_SEL_HC_DC << 16) | |
96 | | (HW_VBUS_DRV | HW_SEL_CP_EXT); | |
97 | ||
98 | isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl); | |
9a66e132 | 99 | |
5171446a LP |
100 | dev_info(isp->dev, "bus width: %u, oc: %s\n", |
101 | isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32, | |
102 | isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital"); | |
103 | } | |
4b1a577d | 104 | |
0316ca63 LP |
105 | void isp1760_set_pullup(struct isp1760_device *isp, bool enable) |
106 | { | |
107 | isp1760_write32(isp->regs, HW_OTG_CTRL_SET, | |
108 | enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16); | |
109 | } | |
110 | ||
4b1a577d LP |
111 | int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, |
112 | struct device *dev, unsigned int devflags) | |
113 | { | |
114 | struct isp1760_device *isp; | |
115 | int ret; | |
116 | ||
117 | if (usb_disabled()) | |
118 | return -ENODEV; | |
119 | ||
120 | /* prevent usb-core allocating DMA pages */ | |
121 | dev->dma_mask = NULL; | |
122 | ||
123 | isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); | |
124 | if (!isp) | |
125 | return -ENOMEM; | |
126 | ||
5171446a LP |
127 | isp->dev = dev; |
128 | isp->devflags = devflags; | |
129 | ||
130 | isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); | |
131 | if (IS_ERR(isp->rst_gpio)) | |
132 | return PTR_ERR(isp->rst_gpio); | |
133 | ||
4b1a577d LP |
134 | isp->regs = devm_ioremap_resource(dev, mem); |
135 | if (IS_ERR(isp->regs)) | |
136 | return PTR_ERR(isp->regs); | |
137 | ||
5171446a LP |
138 | isp1760_init_core(isp); |
139 | ||
667c45c2 | 140 | ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq, |
5171446a | 141 | irqflags | IRQF_SHARED, dev); |
4b1a577d LP |
142 | if (ret < 0) |
143 | return ret; | |
144 | ||
0316ca63 LP |
145 | if (devflags & ISP1760_FLAG_ISP1761) { |
146 | ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED | | |
147 | IRQF_DISABLED); | |
148 | if (ret < 0) { | |
149 | isp1760_hcd_unregister(&isp->hcd); | |
150 | return ret; | |
151 | } | |
152 | } | |
153 | ||
4b1a577d LP |
154 | dev_set_drvdata(dev, isp); |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | void isp1760_unregister(struct device *dev) | |
160 | { | |
161 | struct isp1760_device *isp = dev_get_drvdata(dev); | |
162 | ||
0316ca63 LP |
163 | if (isp->devflags & ISP1760_FLAG_ISP1761) |
164 | isp1760_udc_unregister(isp); | |
165 | ||
4b1a577d LP |
166 | isp1760_hcd_unregister(&isp->hcd); |
167 | } | |
168 | ||
169 | MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); | |
170 | MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>"); | |
171 | MODULE_LICENSE("GPL v2"); |