Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Loongson-2F/3A/3B GPIO Support
0004  *
0005  *  Copyright (c) 2008 Richard Liu,  STMicroelectronics  <richard.liu@st.com>
0006  *  Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
0007  *  Copyright (c) 2013 Hongbing Hu <huhb@lemote.com>
0008  *  Copyright (c) 2014 Huacai Chen <chenhc@lemote.com>
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  * Offset into the register where we read lines, we write them from offset 0.
0033  * This offset is the only thing that stand between us and using
0034  * GPIO_GENERIC.
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);