File Index
Files and directories
Sign in
FILE

gpio-loongson.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-loongson.c C
  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 int loongson_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
 52				   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	return 0;
 66}
 67
 68static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 69{
 70	u32 temp;
 71
 72	spin_lock(&gpio_lock);
 73	temp = LOONGSON_GPIOIE;
 74	temp |= BIT(gpio);
 75	LOONGSON_GPIOIE = temp;
 76	spin_unlock(&gpio_lock);
 77
 78	return 0;
 79}
 80
 81static int loongson_gpio_direction_output(struct gpio_chip *chip,
 82		unsigned gpio, int level)
 83{
 84	u32 temp;
 85
 86	loongson_gpio_set_value(chip, gpio, level);
 87	spin_lock(&gpio_lock);
 88	temp = LOONGSON_GPIOIE;
 89	temp &= ~BIT(gpio);
 90	LOONGSON_GPIOIE = temp;
 91	spin_unlock(&gpio_lock);
 92
 93	return 0;
 94}
 95
 96static int loongson_gpio_probe(struct platform_device *pdev)
 97{
 98	struct gpio_chip *gc;
 99	struct device *dev = &pdev->dev;
100
101	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
102	if (!gc)
103		return -ENOMEM;
104
105	gc->label = "loongson-gpio-chip";
106	gc->base = 0;
107	gc->ngpio = LOONGSON_N_GPIO;
108	gc->get = loongson_gpio_get_value;
109	gc->set = loongson_gpio_set_value;
110	gc->direction_input = loongson_gpio_direction_input;
111	gc->direction_output = loongson_gpio_direction_output;
112
113	return gpiochip_add_data(gc, NULL);
114}
115
116static struct platform_driver loongson_gpio_driver = {
117	.driver = {
118		.name = "loongson-gpio",
119	},
120	.probe = loongson_gpio_probe,
121};
122
123static int __init loongson_gpio_setup(void)
124{
125	struct platform_device *pdev;
126	int ret;
127
128	ret = platform_driver_register(&loongson_gpio_driver);
129	if (ret) {
130		pr_err("error registering loongson GPIO driver\n");
131		return ret;
132	}
133
134	pdev = platform_device_register_simple("loongson-gpio", -1, NULL, 0);
135	return PTR_ERR_OR_ZERO(pdev);
136}
137postcore_initcall(loongson_gpio_setup);
~/ Read-only file preview.