linux/arch/arm/mach-s3c24xx/simtec-usb.c
<<
>>
Prefs
   1/* linux/arch/arm/mach-s3c2410/usb-simtec.c
   2 *
   3 * Copyright 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/hardware.h>
  32#include <mach/gpio-samsung.h>
  33#include <asm/irq.h>
  34
  35#include <linux/platform_data/usb-ohci-s3c2410.h>
  36#include <plat/devs.h>
  37
  38#include "bast.h"
  39#include "simtec.h"
  40
  41/* control power and monitor over-current events on various Simtec
  42 * designed boards.
  43*/
  44
  45static unsigned int power_state[2];
  46
  47static void
  48usb_simtec_powercontrol(int port, int to)
  49{
  50        pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
  51
  52        power_state[port] = to;
  53
  54        if (power_state[0] && power_state[1])
  55                gpio_set_value(S3C2410_GPB(4), 0);
  56        else
  57                gpio_set_value(S3C2410_GPB(4), 1);
  58}
  59
  60static irqreturn_t
  61usb_simtec_ocirq(int irq, void *pw)
  62{
  63        struct s3c2410_hcd_info *info = pw;
  64
  65        if (gpio_get_value(S3C2410_GPG(10)) == 0) {
  66                pr_debug("usb_simtec: over-current irq (oc detected)\n");
  67                s3c2410_usb_report_oc(info, 3);
  68        } else {
  69                pr_debug("usb_simtec: over-current irq (oc cleared)\n");
  70                s3c2410_usb_report_oc(info, 0);
  71        }
  72
  73        return IRQ_HANDLED;
  74}
  75
  76static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
  77{
  78        int ret;
  79
  80        if (on) {
  81                ret = request_irq(BAST_IRQ_USBOC, usb_simtec_ocirq,
  82                                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  83                                  "USB Over-current", info);
  84                if (ret != 0) {
  85                        printk(KERN_ERR "failed to request usb oc irq\n");
  86                }
  87        } else {
  88                free_irq(BAST_IRQ_USBOC, info);
  89        }
  90}
  91
  92static struct s3c2410_hcd_info usb_simtec_info __initdata = {
  93        .port[0]        = {
  94                .flags  = S3C_HCDFLG_USED
  95        },
  96        .port[1]        = {
  97                .flags  = S3C_HCDFLG_USED
  98        },
  99
 100        .power_control  = usb_simtec_powercontrol,
 101        .enable_oc      = usb_simtec_enableoc,
 102};
 103
 104
 105int __init usb_simtec_init(void)
 106{
 107        int ret;
 108
 109        printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
 110
 111        ret = gpio_request(S3C2410_GPB(4), "USB power control");
 112        if (ret < 0) {
 113                pr_err("%s: failed to get GPB4\n", __func__);
 114                return ret;
 115        }
 116
 117        ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
 118        if (ret < 0) {
 119                pr_err("%s: failed to get GPG10\n", __func__);
 120                gpio_free(S3C2410_GPB(4));
 121                return ret;
 122        }
 123
 124        /* turn power on */
 125        gpio_direction_output(S3C2410_GPB(4), 1);
 126        gpio_direction_input(S3C2410_GPG(10));
 127
 128        s3c_ohci_set_platdata(&usb_simtec_info);
 129        return 0;
 130}
 131