linux/drivers/gpio/gpio-loongson.c
<<
>>
Prefs
   1/*
   2 *  Loongson-2F/3A/3B GPIO Support
   3 *
   4 *  Copyright (c) 2008 Richard Liu,  STMicroelectronics  <richard.liu@st.com>
   5 *  Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
   6 *  Copyright (c) 2013 Hongbing Hu <huhb@lemote.com>
   7 *  Copyright (c) 2014 Huacai Chen <chenhc@lemote.com>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or
  12 *  (at your option) any later version.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/init.h>
  17#include <linux/module.h>
  18#include <linux/spinlock.h>
  19#include <linux/err.h>
  20#include <asm/types.h>
  21#include <loongson.h>
  22#include <linux/gpio.h>
  23
  24#define STLS2F_N_GPIO           4
  25#define STLS3A_N_GPIO           16
  26
  27#ifdef CONFIG_CPU_LOONGSON3
  28#define LOONGSON_N_GPIO STLS3A_N_GPIO
  29#else
  30#define LOONGSON_N_GPIO STLS2F_N_GPIO
  31#endif
  32
  33#define LOONGSON_GPIO_IN_OFFSET 16
  34
  35static DEFINE_SPINLOCK(gpio_lock);
  36
  37static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  38{
  39        u32 temp;
  40        u32 mask;
  41
  42        spin_lock(&gpio_lock);
  43        mask = 1 << gpio;
  44        temp = LOONGSON_GPIOIE;
  45        temp |= mask;
  46        LOONGSON_GPIOIE = temp;
  47        spin_unlock(&gpio_lock);
  48
  49        return 0;
  50}
  51
  52static int loongson_gpio_direction_output(struct gpio_chip *chip,
  53                unsigned gpio, int level)
  54{
  55        u32 temp;
  56        u32 mask;
  57
  58        gpio_set_value(gpio, level);
  59        spin_lock(&gpio_lock);
  60        mask = 1 << gpio;
  61        temp = LOONGSON_GPIOIE;
  62        temp &= (~mask);
  63        LOONGSON_GPIOIE = temp;
  64        spin_unlock(&gpio_lock);
  65
  66        return 0;
  67}
  68
  69static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  70{
  71        u32 val;
  72        u32 mask;
  73
  74        mask = 1 << (gpio + LOONGSON_GPIO_IN_OFFSET);
  75        spin_lock(&gpio_lock);
  76        val = LOONGSON_GPIODATA;
  77        spin_unlock(&gpio_lock);
  78
  79        return (val & mask) != 0;
  80}
  81
  82static void loongson_gpio_set_value(struct gpio_chip *chip,
  83                unsigned gpio, int value)
  84{
  85        u32 val;
  86        u32 mask;
  87
  88        mask = 1 << gpio;
  89
  90        spin_lock(&gpio_lock);
  91        val = LOONGSON_GPIODATA;
  92        if (value)
  93                val |= mask;
  94        else
  95                val &= (~mask);
  96        LOONGSON_GPIODATA = val;
  97        spin_unlock(&gpio_lock);
  98}
  99
 100static struct gpio_chip loongson_chip = {
 101        .label                  = "Loongson-gpio-chip",
 102        .direction_input        = loongson_gpio_direction_input,
 103        .get                    = loongson_gpio_get_value,
 104        .direction_output       = loongson_gpio_direction_output,
 105        .set                    = loongson_gpio_set_value,
 106        .base                   = 0,
 107        .ngpio                  = LOONGSON_N_GPIO,
 108        .can_sleep              = false,
 109};
 110
 111static int __init loongson_gpio_setup(void)
 112{
 113        return gpiochip_add_data(&loongson_chip, NULL);
 114}
 115postcore_initcall(loongson_gpio_setup);
 116