0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/err.h>
0016 #include <linux/gpio/driver.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/bitops.h>
0019 #include <asm/types.h>
0020 #include <loongson.h>
0021
0022 #define STLS2F_N_GPIO 4
0023 #define STLS3A_N_GPIO 16
0024
0025 #ifdef CONFIG_CPU_LOONGSON64
0026 #define LOONGSON_N_GPIO STLS3A_N_GPIO
0027 #else
0028 #define LOONGSON_N_GPIO STLS2F_N_GPIO
0029 #endif
0030
0031
0032
0033
0034
0035
0036 #define LOONGSON_GPIO_IN_OFFSET 16
0037
0038 static DEFINE_SPINLOCK(gpio_lock);
0039
0040 static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
0041 {
0042 u32 val;
0043
0044 spin_lock(&gpio_lock);
0045 val = LOONGSON_GPIODATA;
0046 spin_unlock(&gpio_lock);
0047
0048 return !!(val & BIT(gpio + LOONGSON_GPIO_IN_OFFSET));
0049 }
0050
0051 static void loongson_gpio_set_value(struct gpio_chip *chip,
0052 unsigned gpio, int value)
0053 {
0054 u32 val;
0055
0056 spin_lock(&gpio_lock);
0057 val = LOONGSON_GPIODATA;
0058 if (value)
0059 val |= BIT(gpio);
0060 else
0061 val &= ~BIT(gpio);
0062 LOONGSON_GPIODATA = val;
0063 spin_unlock(&gpio_lock);
0064 }
0065
0066 static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
0067 {
0068 u32 temp;
0069
0070 spin_lock(&gpio_lock);
0071 temp = LOONGSON_GPIOIE;
0072 temp |= BIT(gpio);
0073 LOONGSON_GPIOIE = temp;
0074 spin_unlock(&gpio_lock);
0075
0076 return 0;
0077 }
0078
0079 static int loongson_gpio_direction_output(struct gpio_chip *chip,
0080 unsigned gpio, int level)
0081 {
0082 u32 temp;
0083
0084 loongson_gpio_set_value(chip, gpio, level);
0085 spin_lock(&gpio_lock);
0086 temp = LOONGSON_GPIOIE;
0087 temp &= ~BIT(gpio);
0088 LOONGSON_GPIOIE = temp;
0089 spin_unlock(&gpio_lock);
0090
0091 return 0;
0092 }
0093
0094 static int loongson_gpio_probe(struct platform_device *pdev)
0095 {
0096 struct gpio_chip *gc;
0097 struct device *dev = &pdev->dev;
0098
0099 gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
0100 if (!gc)
0101 return -ENOMEM;
0102
0103 gc->label = "loongson-gpio-chip";
0104 gc->base = 0;
0105 gc->ngpio = LOONGSON_N_GPIO;
0106 gc->get = loongson_gpio_get_value;
0107 gc->set = loongson_gpio_set_value;
0108 gc->direction_input = loongson_gpio_direction_input;
0109 gc->direction_output = loongson_gpio_direction_output;
0110
0111 return gpiochip_add_data(gc, NULL);
0112 }
0113
0114 static struct platform_driver loongson_gpio_driver = {
0115 .driver = {
0116 .name = "loongson-gpio",
0117 },
0118 .probe = loongson_gpio_probe,
0119 };
0120
0121 static int __init loongson_gpio_setup(void)
0122 {
0123 struct platform_device *pdev;
0124 int ret;
0125
0126 ret = platform_driver_register(&loongson_gpio_driver);
0127 if (ret) {
0128 pr_err("error registering loongson GPIO driver\n");
0129 return ret;
0130 }
0131
0132 pdev = platform_device_register_simple("loongson-gpio", -1, NULL, 0);
0133 return PTR_ERR_OR_ZERO(pdev);
0134 }
0135 postcore_initcall(loongson_gpio_setup);