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 35 static DEFINE_SPINLOCK(gpio_lock); 36 37 static 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 52 static 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 69 static 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 82 static 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 100 static 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 111 static int __init loongson_gpio_setup(void) 112 { 113 return gpiochip_add_data(&loongson_chip, NULL); 114 } 115 postcore_initcall(loongson_gpio_setup); 116