linux/arch/arm/mach-s3c2410/usb-simtec.c
<<
>>
Prefs
   1/* linux/arch/arm/mach-s3c2410/usb-simtec.c
   2 *
   3 * Copyright (c) 2004,2005 Simtec Electronics
   4 *   Ben Dooks <ben@simtec.co.uk>
   5 *
   6 * http://www.simtec.co.uk/products/EB2410ITX/
   7 *
   8 * Simtec BAST and Thorcom VR1000 USB port support functions
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13*/
  14
  15#define DEBUG
  16
  17#include <linux/kernel.h>
  18#include <linux/types.h>
  19#include <linux/interrupt.h>
  20#include <linux/list.h>
  21#include <linux/gpio.h>
  22#include <linux/timer.h>
  23#include <linux/init.h>
  24#include <linux/device.h>
  25#include <linux/io.h>
  26
  27#include <asm/mach/arch.h>
  28#include <asm/mach/map.h>
  29#include <asm/mach/irq.h>
  30
  31#include <mach/bast-map.h>
  32#include <mach/bast-irq.h>
  33
  34#include <mach/hardware.h>
  35#include <asm/irq.h>
  36
  37#include <plat/usb-control.h>
  38#include <plat/devs.h>
  39
  40#include "usb-simtec.h"
  41
  42/* control power and monitor over-current events on various Simtec
  43 * designed boards.
  44*/
  45
  46static unsigned int power_state[2];
  47
  48static void
  49usb_simtec_powercontrol(int port, int to)
  50{
  51        pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
  52
  53        power_state[port] = to;
  54
  55        if (power_state[0] && power_state[1])
  56                gpio_set_value(S3C2410_GPB(4), 0);
  57        else
  58                gpio_set_value(S3C2410_GPB(4), 1);
  59}
  60
  61static irqreturn_t
  62usb_simtec_ocirq(int irq, void *pw)
  63{
  64        struct s3c2410_hcd_info *info = pw;
  65
  66        if (gpio_get_value(S3C2410_GPG(10)) == 0) {
  67                pr_debug("usb_simtec: over-current irq (oc detected)\n");
  68                s3c2410_usb_report_oc(info, 3);
  69        } else {
  70                pr_debug("usb_simtec: over-current irq (oc cleared)\n");
  71                s3c2410_usb_report_oc(info, 0);
  72        }
  73
  74        return IRQ_HANDLED;
  75}
  76
  77static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
  78{
  79        int ret;
  80
  81        if (on) {
  82                ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
  83                                  IRQF_DISABLED | IRQF_TRIGGER_RISING |
  84                                   IRQF_TRIGGER_FALLING,
  85                                  "USB Over-current", info);
  86                if (ret != 0) {
  87                        printk(KERN_ERR "failed to request usb oc irq\n");
  88                }
  89        } else {
  90                free_irq(IRQ_USBOC, info);
  91        }
  92}
  93
  94static struct s3c2410_hcd_info usb_simtec_info = {
  95        .port[0]        = {
  96                .flags  = S3C_HCDFLG_USED
  97        },
  98        .port[1]        = {
  99                .flags  = S3C_HCDFLG_USED
 100        },
 101
 102        .power_control  = usb_simtec_powercontrol,
 103        .enable_oc      = usb_simtec_enableoc,
 104};
 105
 106
 107int usb_simtec_init(void)
 108{
 109        int ret;
 110
 111        printk("USB Power Control, (c) 2004 Simtec Electronics\n");
 112
 113        ret = gpio_request(S3C2410_GPB(4), "USB power control");
 114        if (ret < 0) {
 115                pr_err("%s: failed to get GPB4\n", __func__);
 116                return ret;
 117        }
 118
 119        ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
 120        if (ret < 0) {
 121                pr_err("%s: failed to get GPG10\n", __func__);
 122                gpio_free(S3C2410_GPB(4));
 123                return ret;
 124        }
 125
 126        /* turn power on */
 127        gpio_direction_output(S3C2410_GPB(4), 1);
 128        gpio_direction_input(S3C2410_GPG(10));
 129
 130        s3c_device_usb.dev.platform_data = &usb_simtec_info;
 131        return 0;
 132}
 133