cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio-loongson.c (3031B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Loongson-2F/3A/3B GPIO Support
      4 *
      5 *  Copyright (c) 2008 Richard Liu,  STMicroelectronics	 <richard.liu@st.com>
      6 *  Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
      7 *  Copyright (c) 2013 Hongbing Hu <huhb@lemote.com>
      8 *  Copyright (c) 2014 Huacai Chen <chenhc@lemote.com>
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/init.h>
     13#include <linux/module.h>
     14#include <linux/spinlock.h>
     15#include <linux/err.h>
     16#include <linux/gpio/driver.h>
     17#include <linux/platform_device.h>
     18#include <linux/bitops.h>
     19#include <asm/types.h>
     20#include <loongson.h>
     21
     22#define STLS2F_N_GPIO		4
     23#define STLS3A_N_GPIO		16
     24
     25#ifdef CONFIG_CPU_LOONGSON64
     26#define LOONGSON_N_GPIO	STLS3A_N_GPIO
     27#else
     28#define LOONGSON_N_GPIO	STLS2F_N_GPIO
     29#endif
     30
     31/*
     32 * Offset into the register where we read lines, we write them from offset 0.
     33 * This offset is the only thing that stand between us and using
     34 * GPIO_GENERIC.
     35 */
     36#define LOONGSON_GPIO_IN_OFFSET	16
     37
     38static DEFINE_SPINLOCK(gpio_lock);
     39
     40static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
     41{
     42	u32 val;
     43
     44	spin_lock(&gpio_lock);
     45	val = LOONGSON_GPIODATA;
     46	spin_unlock(&gpio_lock);
     47
     48	return !!(val & BIT(gpio + LOONGSON_GPIO_IN_OFFSET));
     49}
     50
     51static void loongson_gpio_set_value(struct gpio_chip *chip,
     52		unsigned gpio, int value)
     53{
     54	u32 val;
     55
     56	spin_lock(&gpio_lock);
     57	val = LOONGSON_GPIODATA;
     58	if (value)
     59		val |= BIT(gpio);
     60	else
     61		val &= ~BIT(gpio);
     62	LOONGSON_GPIODATA = val;
     63	spin_unlock(&gpio_lock);
     64}
     65
     66static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
     67{
     68	u32 temp;
     69
     70	spin_lock(&gpio_lock);
     71	temp = LOONGSON_GPIOIE;
     72	temp |= BIT(gpio);
     73	LOONGSON_GPIOIE = temp;
     74	spin_unlock(&gpio_lock);
     75
     76	return 0;
     77}
     78
     79static int loongson_gpio_direction_output(struct gpio_chip *chip,
     80		unsigned gpio, int level)
     81{
     82	u32 temp;
     83
     84	loongson_gpio_set_value(chip, gpio, level);
     85	spin_lock(&gpio_lock);
     86	temp = LOONGSON_GPIOIE;
     87	temp &= ~BIT(gpio);
     88	LOONGSON_GPIOIE = temp;
     89	spin_unlock(&gpio_lock);
     90
     91	return 0;
     92}
     93
     94static int loongson_gpio_probe(struct platform_device *pdev)
     95{
     96	struct gpio_chip *gc;
     97	struct device *dev = &pdev->dev;
     98
     99	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
    100	if (!gc)
    101		return -ENOMEM;
    102
    103	gc->label = "loongson-gpio-chip";
    104	gc->base = 0;
    105	gc->ngpio = LOONGSON_N_GPIO;
    106	gc->get = loongson_gpio_get_value;
    107	gc->set = loongson_gpio_set_value;
    108	gc->direction_input = loongson_gpio_direction_input;
    109	gc->direction_output = loongson_gpio_direction_output;
    110
    111	return gpiochip_add_data(gc, NULL);
    112}
    113
    114static struct platform_driver loongson_gpio_driver = {
    115	.driver = {
    116		.name = "loongson-gpio",
    117	},
    118	.probe = loongson_gpio_probe,
    119};
    120
    121static int __init loongson_gpio_setup(void)
    122{
    123	struct platform_device *pdev;
    124	int ret;
    125
    126	ret = platform_driver_register(&loongson_gpio_driver);
    127	if (ret) {
    128		pr_err("error registering loongson GPIO driver\n");
    129		return ret;
    130	}
    131
    132	pdev = platform_device_register_simple("loongson-gpio", -1, NULL, 0);
    133	return PTR_ERR_OR_ZERO(pdev);
    134}
    135postcore_initcall(loongson_gpio_setup);