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