brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · a421458 Raw
136 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Loongson-2F/3A/3B GPIO Support4 *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		423#define STLS3A_N_GPIO		1624 25#ifdef CONFIG_CPU_LOONGSON6426#define LOONGSON_N_GPIO	STLS3A_N_GPIO27#else28#define LOONGSON_N_GPIO	STLS2F_N_GPIO29#endif30 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 using34 * GPIO_GENERIC.35 */36#define LOONGSON_GPIO_IN_OFFSET	1637 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	else61		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);136