1/* 2 * STLS2F 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 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/module.h> 16#include <linux/spinlock.h> 17#include <linux/err.h> 18#include <asm/types.h> 19#include <loongson.h> 20#include <linux/gpio.h> 21 22#define STLS2F_N_GPIO 4 23#define STLS2F_GPIO_IN_OFFSET 16 24 25static DEFINE_SPINLOCK(gpio_lock); 26 27int gpio_get_value(unsigned gpio) 28{ 29 u32 val; 30 u32 mask; 31 32 if (gpio >= STLS2F_N_GPIO) 33 return __gpio_get_value(gpio); 34 35 mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET); 36 spin_lock(&gpio_lock); 37 val = LOONGSON_GPIODATA; 38 spin_unlock(&gpio_lock); 39 40 return ((val & mask) != 0); 41} 42EXPORT_SYMBOL(gpio_get_value); 43 44void gpio_set_value(unsigned gpio, int state) 45{ 46 u32 val; 47 u32 mask; 48 49 if (gpio >= STLS2F_N_GPIO) { 50 __gpio_set_value(gpio, state); 51 return ; 52 } 53 54 mask = 1 << gpio; 55 56 spin_lock(&gpio_lock); 57 val = LOONGSON_GPIODATA; 58 if (state) 59 val |= mask; 60 else 61 val &= (~mask); 62 LOONGSON_GPIODATA = val; 63 spin_unlock(&gpio_lock); 64} 65EXPORT_SYMBOL(gpio_set_value); 66 67int gpio_cansleep(unsigned gpio) 68{ 69 if (gpio < STLS2F_N_GPIO) 70 return 0; 71 else 72 return __gpio_cansleep(gpio); 73} 74EXPORT_SYMBOL(gpio_cansleep); 75 76static int ls2f_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 77{ 78 u32 temp; 79 u32 mask; 80 81 if (gpio >= STLS2F_N_GPIO) 82 return -EINVAL; 83 84 spin_lock(&gpio_lock); 85 mask = 1 << gpio; 86 temp = LOONGSON_GPIOIE; 87 temp |= mask; 88 LOONGSON_GPIOIE = temp; 89 spin_unlock(&gpio_lock); 90 91 return 0; 92} 93 94static int ls2f_gpio_direction_output(struct gpio_chip *chip, 95 unsigned gpio, int level) 96{ 97 u32 temp; 98 u32 mask; 99 100 if (gpio >= STLS2F_N_GPIO) 101 return -EINVAL; 102 103 gpio_set_value(gpio, level); 104 spin_lock(&gpio_lock); 105 mask = 1 << gpio; 106 temp = LOONGSON_GPIOIE; 107 temp &= (~mask); 108 LOONGSON_GPIOIE = temp; 109 spin_unlock(&gpio_lock); 110 111 return 0; 112} 113 114static int ls2f_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 115{ 116 return gpio_get_value(gpio); 117} 118 119static void ls2f_gpio_set_value(struct gpio_chip *chip, 120 unsigned gpio, int value) 121{ 122 gpio_set_value(gpio, value); 123} 124 125static struct gpio_chip ls2f_chip = { 126 .label = "ls2f", 127 .direction_input = ls2f_gpio_direction_input, 128 .get = ls2f_gpio_get_value, 129 .direction_output = ls2f_gpio_direction_output, 130 .set = ls2f_gpio_set_value, 131 .base = 0, 132 .ngpio = STLS2F_N_GPIO, 133}; 134 135static int __init ls2f_gpio_setup(void) 136{ 137 return gpiochip_add(&ls2f_chip); 138} 139arch_initcall(ls2f_gpio_setup); 140