File Index
Files and directories
Sign in
FILE

gpio-loongson1.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-loongson1.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * GPIO Driver for Loongson 1 SoC
  4 *
  5 * Copyright (C) 2015-2023 Keguang Zhang <keguang.zhang@gmail.com>
  6 */
  7
  8#include <linux/bitops.h>
  9#include <linux/module.h>
 10#include <linux/gpio/driver.h>
 11#include <linux/gpio/generic.h>
 12#include <linux/platform_device.h>
 13
 14/* Loongson 1 GPIO Register Definitions */
 15#define GPIO_CFG		0x0
 16#define GPIO_DIR		0x10
 17#define GPIO_DATA		0x20
 18#define GPIO_OUTPUT		0x30
 19
 20struct ls1x_gpio_chip {
 21	struct gpio_generic_chip chip;
 22	void __iomem *reg_base;
 23};
 24
 25static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
 26{
 27	struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
 28
 29	guard(gpio_generic_lock_irqsave)(&ls1x_gc->chip);
 30
 31	__raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) | BIT(offset),
 32		     ls1x_gc->reg_base + GPIO_CFG);
 33
 34	return 0;
 35}
 36
 37static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
 38{
 39	struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
 40
 41	guard(gpio_generic_lock_irqsave)(&ls1x_gc->chip);
 42
 43	__raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) & ~BIT(offset),
 44		     ls1x_gc->reg_base + GPIO_CFG);
 45}
 46
 47static int ls1x_gpio_probe(struct platform_device *pdev)
 48{
 49	struct gpio_generic_chip_config config;
 50	struct device *dev = &pdev->dev;
 51	struct ls1x_gpio_chip *ls1x_gc;
 52	int ret;
 53
 54	ls1x_gc = devm_kzalloc(dev, sizeof(*ls1x_gc), GFP_KERNEL);
 55	if (!ls1x_gc)
 56		return -ENOMEM;
 57
 58	ls1x_gc->reg_base = devm_platform_ioremap_resource(pdev, 0);
 59	if (IS_ERR(ls1x_gc->reg_base))
 60		return PTR_ERR(ls1x_gc->reg_base);
 61
 62	config = (struct gpio_generic_chip_config) {
 63		.dev = dev,
 64		.sz = 4,
 65		.dat = ls1x_gc->reg_base + GPIO_DATA,
 66		.set = ls1x_gc->reg_base + GPIO_OUTPUT,
 67		.dirin = ls1x_gc->reg_base + GPIO_DIR,
 68	};
 69
 70	ret = gpio_generic_chip_init(&ls1x_gc->chip, &config);
 71	if (ret)
 72		goto err;
 73
 74	ls1x_gc->chip.gc.owner = THIS_MODULE;
 75	ls1x_gc->chip.gc.request = ls1x_gpio_request;
 76	ls1x_gc->chip.gc.free = ls1x_gpio_free;
 77	/*
 78	 * Clear ngpio to let gpiolib get the correct number
 79	 * by reading ngpios property
 80	 */
 81	ls1x_gc->chip.gc.ngpio = 0;
 82
 83	ret = devm_gpiochip_add_data(dev, &ls1x_gc->chip.gc, ls1x_gc);
 84	if (ret)
 85		goto err;
 86
 87	platform_set_drvdata(pdev, ls1x_gc);
 88
 89	dev_info(dev, "GPIO controller registered with %d pins\n",
 90		 ls1x_gc->chip.gc.ngpio);
 91
 92	return 0;
 93err:
 94	dev_err(dev, "failed to register GPIO controller\n");
 95	return ret;
 96}
 97
 98static const struct of_device_id ls1x_gpio_dt_ids[] = {
 99	{ .compatible = "loongson,ls1x-gpio" },
100	{ /* sentinel */ }
101};
102MODULE_DEVICE_TABLE(of, ls1x_gpio_dt_ids);
103
104static struct platform_driver ls1x_gpio_driver = {
105	.probe	= ls1x_gpio_probe,
106	.driver	= {
107		.name	= "ls1x-gpio",
108		.of_match_table = ls1x_gpio_dt_ids,
109	},
110};
111
112module_platform_driver(ls1x_gpio_driver);
113
114MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
115MODULE_DESCRIPTION("Loongson1 GPIO driver");
116MODULE_LICENSE("GPL");
~/ Read-only file preview.