diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 12 | ||||
-rw-r--r-- | drivers/gpio/gpio-mxs.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/davinci_mmc.c | 13 | ||||
-rw-r--r-- | drivers/usb/host/ohci-at91.c | 239 |
4 files changed, 247 insertions, 19 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 4340acae3bd3..b588f8a41e60 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/of_device.h> | 31 | #include <linux/of_device.h> |
32 | #include <asm-generic/bug.h> | 32 | #include <asm-generic/bug.h> |
33 | 33 | ||
34 | #define irq_to_gpio(irq) ((irq) - MXC_GPIO_IRQ_START) | ||
35 | |||
34 | enum mxc_gpio_hwtype { | 36 | enum mxc_gpio_hwtype { |
35 | IMX1_GPIO, /* runs on i.mx1 */ | 37 | IMX1_GPIO, /* runs on i.mx1 */ |
36 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ | 38 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ |
@@ -337,6 +339,15 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) | |||
337 | mxc_gpio_hwtype = hwtype; | 339 | mxc_gpio_hwtype = hwtype; |
338 | } | 340 | } |
339 | 341 | ||
342 | static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
343 | { | ||
344 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
345 | struct mxc_gpio_port *port = | ||
346 | container_of(bgc, struct mxc_gpio_port, bgc); | ||
347 | |||
348 | return port->virtual_irq_start + offset; | ||
349 | } | ||
350 | |||
340 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) | 351 | static int __devinit mxc_gpio_probe(struct platform_device *pdev) |
341 | { | 352 | { |
342 | struct device_node *np = pdev->dev.of_node; | 353 | struct device_node *np = pdev->dev.of_node; |
@@ -403,6 +414,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) | |||
403 | if (err) | 414 | if (err) |
404 | goto out_iounmap; | 415 | goto out_iounmap; |
405 | 416 | ||
417 | port->bgc.gc.to_irq = mxc_gpio_to_irq; | ||
406 | port->bgc.gc.base = pdev->id * 32; | 418 | port->bgc.gc.base = pdev->id * 32; |
407 | port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); | 419 | port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); |
408 | port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); | 420 | port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); |
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index af55a8577c2e..292b50481db9 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #define GPIO_INT_LEV_MASK (1 << 0) | 49 | #define GPIO_INT_LEV_MASK (1 << 0) |
50 | #define GPIO_INT_POL_MASK (1 << 1) | 50 | #define GPIO_INT_POL_MASK (1 << 1) |
51 | 51 | ||
52 | #define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START) | ||
53 | |||
52 | struct mxs_gpio_port { | 54 | struct mxs_gpio_port { |
53 | void __iomem *base; | 55 | void __iomem *base; |
54 | int id; | 56 | int id; |
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 0076c7448fe6..64a8325a4a8a 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c | |||
@@ -807,12 +807,25 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) | |||
807 | static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 807 | static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
808 | { | 808 | { |
809 | struct mmc_davinci_host *host = mmc_priv(mmc); | 809 | struct mmc_davinci_host *host = mmc_priv(mmc); |
810 | struct platform_device *pdev = to_platform_device(mmc->parent); | ||
811 | struct davinci_mmc_config *config = pdev->dev.platform_data; | ||
810 | 812 | ||
811 | dev_dbg(mmc_dev(host->mmc), | 813 | dev_dbg(mmc_dev(host->mmc), |
812 | "clock %dHz busmode %d powermode %d Vdd %04x\n", | 814 | "clock %dHz busmode %d powermode %d Vdd %04x\n", |
813 | ios->clock, ios->bus_mode, ios->power_mode, | 815 | ios->clock, ios->bus_mode, ios->power_mode, |
814 | ios->vdd); | 816 | ios->vdd); |
815 | 817 | ||
818 | switch (ios->power_mode) { | ||
819 | case MMC_POWER_OFF: | ||
820 | if (config && config->set_power) | ||
821 | config->set_power(pdev->id, false); | ||
822 | break; | ||
823 | case MMC_POWER_UP: | ||
824 | if (config && config->set_power) | ||
825 | config->set_power(pdev->id, true); | ||
826 | break; | ||
827 | } | ||
828 | |||
816 | switch (ios->bus_width) { | 829 | switch (ios->bus_width) { |
817 | case MMC_BUS_WIDTH_8: | 830 | case MMC_BUS_WIDTH_8: |
818 | dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); | 831 | dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); |
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 944291e10f97..ba3a46b78b75 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c | |||
@@ -35,8 +35,7 @@ extern int usb_disabled(void); | |||
35 | 35 | ||
36 | static void at91_start_clock(void) | 36 | static void at91_start_clock(void) |
37 | { | 37 | { |
38 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) | 38 | clk_enable(hclk); |
39 | clk_enable(hclk); | ||
40 | clk_enable(iclk); | 39 | clk_enable(iclk); |
41 | clk_enable(fclk); | 40 | clk_enable(fclk); |
42 | clocked = 1; | 41 | clocked = 1; |
@@ -46,8 +45,7 @@ static void at91_stop_clock(void) | |||
46 | { | 45 | { |
47 | clk_disable(fclk); | 46 | clk_disable(fclk); |
48 | clk_disable(iclk); | 47 | clk_disable(iclk); |
49 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) | 48 | clk_disable(hclk); |
50 | clk_disable(hclk); | ||
51 | clocked = 0; | 49 | clocked = 0; |
52 | } | 50 | } |
53 | 51 | ||
@@ -142,8 +140,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, | |||
142 | 140 | ||
143 | iclk = clk_get(&pdev->dev, "ohci_clk"); | 141 | iclk = clk_get(&pdev->dev, "ohci_clk"); |
144 | fclk = clk_get(&pdev->dev, "uhpck"); | 142 | fclk = clk_get(&pdev->dev, "uhpck"); |
145 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) | 143 | hclk = clk_get(&pdev->dev, "hclk"); |
146 | hclk = clk_get(&pdev->dev, "hck0"); | ||
147 | 144 | ||
148 | at91_start_hc(pdev); | 145 | at91_start_hc(pdev); |
149 | ohci_hcd_init(hcd_to_ohci(hcd)); | 146 | ohci_hcd_init(hcd_to_ohci(hcd)); |
@@ -155,8 +152,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, | |||
155 | /* Error handling */ | 152 | /* Error handling */ |
156 | at91_stop_hc(pdev); | 153 | at91_stop_hc(pdev); |
157 | 154 | ||
158 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) | 155 | clk_put(hclk); |
159 | clk_put(hclk); | ||
160 | clk_put(fclk); | 156 | clk_put(fclk); |
161 | clk_put(iclk); | 157 | clk_put(iclk); |
162 | 158 | ||
@@ -192,8 +188,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, | |||
192 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 188 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
193 | usb_put_hcd(hcd); | 189 | usb_put_hcd(hcd); |
194 | 190 | ||
195 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) | 191 | clk_put(hclk); |
196 | clk_put(hclk); | ||
197 | clk_put(fclk); | 192 | clk_put(fclk); |
198 | clk_put(iclk); | 193 | clk_put(iclk); |
199 | fclk = iclk = hclk = NULL; | 194 | fclk = iclk = hclk = NULL; |
@@ -223,6 +218,156 @@ ohci_at91_start (struct usb_hcd *hcd) | |||
223 | return 0; | 218 | return 0; |
224 | } | 219 | } |
225 | 220 | ||
221 | static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) | ||
222 | { | ||
223 | if (port < 0 || port >= 2) | ||
224 | return; | ||
225 | |||
226 | gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable); | ||
227 | } | ||
228 | |||
229 | static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) | ||
230 | { | ||
231 | if (port < 0 || port >= 2) | ||
232 | return -EINVAL; | ||
233 | |||
234 | return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Update the status data from the hub with the over-current indicator change. | ||
239 | */ | ||
240 | static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
241 | { | ||
242 | struct at91_usbh_data *pdata = hcd->self.controller->platform_data; | ||
243 | int length = ohci_hub_status_data(hcd, buf); | ||
244 | int port; | ||
245 | |||
246 | for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { | ||
247 | if (pdata->overcurrent_changed[port]) { | ||
248 | if (! length) | ||
249 | length = 1; | ||
250 | buf[0] |= 1 << (port + 1); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | return length; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Look at the control requests to the root hub and see if we need to override. | ||
259 | */ | ||
260 | static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | ||
261 | u16 wIndex, char *buf, u16 wLength) | ||
262 | { | ||
263 | struct at91_usbh_data *pdata = hcd->self.controller->platform_data; | ||
264 | struct usb_hub_descriptor *desc; | ||
265 | int ret = -EINVAL; | ||
266 | u32 *data = (u32 *)buf; | ||
267 | |||
268 | dev_dbg(hcd->self.controller, | ||
269 | "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", | ||
270 | hcd, typeReq, wValue, wIndex, buf, wLength); | ||
271 | |||
272 | switch (typeReq) { | ||
273 | case SetPortFeature: | ||
274 | if (wValue == USB_PORT_FEAT_POWER) { | ||
275 | dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); | ||
276 | ohci_at91_usb_set_power(pdata, wIndex - 1, 1); | ||
277 | goto out; | ||
278 | } | ||
279 | break; | ||
280 | |||
281 | case ClearPortFeature: | ||
282 | switch (wValue) { | ||
283 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
284 | dev_dbg(hcd->self.controller, | ||
285 | "ClearPortFeature: C_OVER_CURRENT\n"); | ||
286 | |||
287 | if (wIndex == 1 || wIndex == 2) { | ||
288 | pdata->overcurrent_changed[wIndex-1] = 0; | ||
289 | pdata->overcurrent_status[wIndex-1] = 0; | ||
290 | } | ||
291 | |||
292 | goto out; | ||
293 | |||
294 | case USB_PORT_FEAT_OVER_CURRENT: | ||
295 | dev_dbg(hcd->self.controller, | ||
296 | "ClearPortFeature: OVER_CURRENT\n"); | ||
297 | |||
298 | if (wIndex == 1 || wIndex == 2) { | ||
299 | pdata->overcurrent_status[wIndex-1] = 0; | ||
300 | } | ||
301 | |||
302 | goto out; | ||
303 | |||
304 | case USB_PORT_FEAT_POWER: | ||
305 | dev_dbg(hcd->self.controller, | ||
306 | "ClearPortFeature: POWER\n"); | ||
307 | |||
308 | if (wIndex == 1 || wIndex == 2) { | ||
309 | ohci_at91_usb_set_power(pdata, wIndex - 1, 0); | ||
310 | return 0; | ||
311 | } | ||
312 | } | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); | ||
317 | if (ret) | ||
318 | goto out; | ||
319 | |||
320 | switch (typeReq) { | ||
321 | case GetHubDescriptor: | ||
322 | |||
323 | /* update the hub's descriptor */ | ||
324 | |||
325 | desc = (struct usb_hub_descriptor *)buf; | ||
326 | |||
327 | dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", | ||
328 | desc->wHubCharacteristics); | ||
329 | |||
330 | /* remove the old configurations for power-switching, and | ||
331 | * over-current protection, and insert our new configuration | ||
332 | */ | ||
333 | |||
334 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); | ||
335 | desc->wHubCharacteristics |= cpu_to_le16(0x0001); | ||
336 | |||
337 | if (pdata->overcurrent_supported) { | ||
338 | desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); | ||
339 | desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); | ||
340 | } | ||
341 | |||
342 | dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", | ||
343 | desc->wHubCharacteristics); | ||
344 | |||
345 | return ret; | ||
346 | |||
347 | case GetPortStatus: | ||
348 | /* check port status */ | ||
349 | |||
350 | dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); | ||
351 | |||
352 | if (wIndex == 1 || wIndex == 2) { | ||
353 | if (! ohci_at91_usb_get_power(pdata, wIndex-1)) { | ||
354 | *data &= ~cpu_to_le32(RH_PS_PPS); | ||
355 | } | ||
356 | |||
357 | if (pdata->overcurrent_changed[wIndex-1]) { | ||
358 | *data |= cpu_to_le32(RH_PS_OCIC); | ||
359 | } | ||
360 | |||
361 | if (pdata->overcurrent_status[wIndex-1]) { | ||
362 | *data |= cpu_to_le32(RH_PS_POCI); | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | out: | ||
368 | return ret; | ||
369 | } | ||
370 | |||
226 | /*-------------------------------------------------------------------------*/ | 371 | /*-------------------------------------------------------------------------*/ |
227 | 372 | ||
228 | static const struct hc_driver ohci_at91_hc_driver = { | 373 | static const struct hc_driver ohci_at91_hc_driver = { |
@@ -258,8 +403,8 @@ static const struct hc_driver ohci_at91_hc_driver = { | |||
258 | /* | 403 | /* |
259 | * root hub support | 404 | * root hub support |
260 | */ | 405 | */ |
261 | .hub_status_data = ohci_hub_status_data, | 406 | .hub_status_data = ohci_at91_hub_status_data, |
262 | .hub_control = ohci_hub_control, | 407 | .hub_control = ohci_at91_hub_control, |
263 | #ifdef CONFIG_PM | 408 | #ifdef CONFIG_PM |
264 | .bus_suspend = ohci_bus_suspend, | 409 | .bus_suspend = ohci_bus_suspend, |
265 | .bus_resume = ohci_bus_resume, | 410 | .bus_resume = ohci_bus_resume, |
@@ -269,22 +414,71 @@ static const struct hc_driver ohci_at91_hc_driver = { | |||
269 | 414 | ||
270 | /*-------------------------------------------------------------------------*/ | 415 | /*-------------------------------------------------------------------------*/ |
271 | 416 | ||
417 | static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) | ||
418 | { | ||
419 | struct platform_device *pdev = data; | ||
420 | struct at91_usbh_data *pdata = pdev->dev.platform_data; | ||
421 | int val, gpio, port; | ||
422 | |||
423 | /* From the GPIO notifying the over-current situation, find | ||
424 | * out the corresponding port */ | ||
425 | gpio = irq_to_gpio(irq); | ||
426 | for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { | ||
427 | if (pdata->overcurrent_pin[port] == gpio) | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | if (port == ARRAY_SIZE(pdata->overcurrent_pin)) { | ||
432 | dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); | ||
433 | return IRQ_HANDLED; | ||
434 | } | ||
435 | |||
436 | val = gpio_get_value(gpio); | ||
437 | |||
438 | /* When notified of an over-current situation, disable power | ||
439 | on the corresponding port, and mark this port in | ||
440 | over-current. */ | ||
441 | if (! val) { | ||
442 | ohci_at91_usb_set_power(pdata, port, 0); | ||
443 | pdata->overcurrent_status[port] = 1; | ||
444 | pdata->overcurrent_changed[port] = 1; | ||
445 | } | ||
446 | |||
447 | dev_dbg(& pdev->dev, "overcurrent situation %s\n", | ||
448 | val ? "exited" : "notified"); | ||
449 | |||
450 | return IRQ_HANDLED; | ||
451 | } | ||
452 | |||
453 | /*-------------------------------------------------------------------------*/ | ||
454 | |||
272 | static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) | 455 | static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) |
273 | { | 456 | { |
274 | struct at91_usbh_data *pdata = pdev->dev.platform_data; | 457 | struct at91_usbh_data *pdata = pdev->dev.platform_data; |
275 | int i; | 458 | int i; |
276 | 459 | ||
277 | if (pdata) { | 460 | if (pdata) { |
278 | /* REVISIT make the driver support per-port power switching, | ||
279 | * and also overcurrent detection. Here we assume the ports | ||
280 | * are always powered while this driver is active, and use | ||
281 | * active-low power switches. | ||
282 | */ | ||
283 | for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { | 461 | for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { |
284 | if (pdata->vbus_pin[i] <= 0) | 462 | if (pdata->vbus_pin[i] <= 0) |
285 | continue; | 463 | continue; |
286 | gpio_request(pdata->vbus_pin[i], "ohci_vbus"); | 464 | gpio_request(pdata->vbus_pin[i], "ohci_vbus"); |
287 | gpio_direction_output(pdata->vbus_pin[i], 0); | 465 | ohci_at91_usb_set_power(pdata, i, 1); |
466 | } | ||
467 | |||
468 | for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { | ||
469 | int ret; | ||
470 | |||
471 | if (pdata->overcurrent_pin[i] <= 0) | ||
472 | continue; | ||
473 | gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent"); | ||
474 | |||
475 | ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]), | ||
476 | ohci_hcd_at91_overcurrent_irq, | ||
477 | IRQF_SHARED, "ohci_overcurrent", pdev); | ||
478 | if (ret) { | ||
479 | gpio_free(pdata->overcurrent_pin[i]); | ||
480 | dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n"); | ||
481 | } | ||
288 | } | 482 | } |
289 | } | 483 | } |
290 | 484 | ||
@@ -301,9 +495,16 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) | |||
301 | for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { | 495 | for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { |
302 | if (pdata->vbus_pin[i] <= 0) | 496 | if (pdata->vbus_pin[i] <= 0) |
303 | continue; | 497 | continue; |
304 | gpio_direction_output(pdata->vbus_pin[i], 1); | 498 | ohci_at91_usb_set_power(pdata, i, 0); |
305 | gpio_free(pdata->vbus_pin[i]); | 499 | gpio_free(pdata->vbus_pin[i]); |
306 | } | 500 | } |
501 | |||
502 | for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { | ||
503 | if (pdata->overcurrent_pin[i] <= 0) | ||
504 | continue; | ||
505 | free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); | ||
506 | gpio_free(pdata->overcurrent_pin[i]); | ||
507 | } | ||
307 | } | 508 | } |
308 | 509 | ||
309 | device_init_wakeup(&pdev->dev, 0); | 510 | device_init_wakeup(&pdev->dev, 0); |