File Index
Files and directories
Sign in
FILE

gpio-rdc321x.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-rdc321x.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * RDC321x GPIO driver
  4 *
  5 * Copyright (C) 2008, Volker Weiss <dev@tintuc.de>
  6 * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
  7 */
  8#include <linux/module.h>
  9#include <linux/kernel.h>
 10#include <linux/init.h>
 11#include <linux/spinlock.h>
 12#include <linux/platform_device.h>
 13#include <linux/pci.h>
 14#include <linux/gpio/driver.h>
 15#include <linux/mfd/rdc321x.h>
 16#include <linux/slab.h>
 17
 18struct rdc321x_gpio {
 19	spinlock_t		lock;
 20	struct pci_dev		*sb_pdev;
 21	u32			data_reg[2];
 22	int			reg1_ctrl_base;
 23	int			reg1_data_base;
 24	int			reg2_ctrl_base;
 25	int			reg2_data_base;
 26	struct gpio_chip	chip;
 27};
 28
 29/* read GPIO pin */
 30static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 31{
 32	struct rdc321x_gpio *gpch;
 33	u32 value = 0;
 34	int reg;
 35
 36	gpch = gpiochip_get_data(chip);
 37	reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
 38
 39	spin_lock(&gpch->lock);
 40	pci_write_config_dword(gpch->sb_pdev, reg,
 41					gpch->data_reg[gpio < 32 ? 0 : 1]);
 42	pci_read_config_dword(gpch->sb_pdev, reg, &value);
 43	spin_unlock(&gpch->lock);
 44
 45	return (1 << (gpio & 0x1f)) & value ? 1 : 0;
 46}
 47
 48static void rdc_gpio_set_value_impl(struct gpio_chip *chip,
 49				unsigned gpio, int value)
 50{
 51	struct rdc321x_gpio *gpch;
 52	int reg = (gpio < 32) ? 0 : 1;
 53
 54	gpch = gpiochip_get_data(chip);
 55
 56	if (value)
 57		gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
 58	else
 59		gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f));
 60
 61	pci_write_config_dword(gpch->sb_pdev,
 62			reg ? gpch->reg2_data_base : gpch->reg1_data_base,
 63			gpch->data_reg[reg]);
 64}
 65
 66/* set GPIO pin to value */
 67static int rdc_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
 68			      int value)
 69{
 70	struct rdc321x_gpio *gpch;
 71
 72	gpch = gpiochip_get_data(chip);
 73	spin_lock(&gpch->lock);
 74	rdc_gpio_set_value_impl(chip, gpio, value);
 75	spin_unlock(&gpch->lock);
 76
 77	return 0;
 78}
 79
 80static int rdc_gpio_config(struct gpio_chip *chip,
 81				unsigned gpio, int value)
 82{
 83	struct rdc321x_gpio *gpch;
 84	int err;
 85	u32 reg;
 86
 87	gpch = gpiochip_get_data(chip);
 88
 89	spin_lock(&gpch->lock);
 90	err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
 91			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, &reg);
 92	if (err)
 93		goto unlock;
 94
 95	reg |= 1 << (gpio & 0x1f);
 96
 97	err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ?
 98			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg);
 99	if (err)
100		goto unlock;
101
102	rdc_gpio_set_value_impl(chip, gpio, value);
103
104unlock:
105	spin_unlock(&gpch->lock);
106
107	return pcibios_err_to_errno(err);
108}
109
110/* configure GPIO pin as input */
111static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
112{
113	return rdc_gpio_config(chip, gpio, 1);
114}
115
116/*
117 * Cache the initial value of both GPIO data registers
118 */
119static int rdc321x_gpio_probe(struct platform_device *pdev)
120{
121	int err;
122	struct resource *r;
123	struct rdc321x_gpio *rdc321x_gpio_dev;
124	struct rdc321x_gpio_pdata *pdata;
125
126	pdata = dev_get_platdata(&pdev->dev);
127	if (!pdata) {
128		dev_err(&pdev->dev, "no platform data supplied\n");
129		return -ENODEV;
130	}
131
132	rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio),
133					GFP_KERNEL);
134	if (!rdc321x_gpio_dev)
135		return -ENOMEM;
136
137	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
138	if (!r) {
139		dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
140		return -ENODEV;
141	}
142
143	spin_lock_init(&rdc321x_gpio_dev->lock);
144	rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev;
145	rdc321x_gpio_dev->reg1_ctrl_base = r->start;
146	rdc321x_gpio_dev->reg1_data_base = r->start + 0x4;
147
148	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
149	if (!r) {
150		dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
151		return -ENODEV;
152	}
153
154	rdc321x_gpio_dev->reg2_ctrl_base = r->start;
155	rdc321x_gpio_dev->reg2_data_base = r->start + 0x4;
156
157	rdc321x_gpio_dev->chip.label = "rdc321x-gpio";
158	rdc321x_gpio_dev->chip.owner = THIS_MODULE;
159	rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input;
160	rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config;
161	rdc321x_gpio_dev->chip.get = rdc_gpio_get_value;
162	rdc321x_gpio_dev->chip.set = rdc_gpio_set_value;
163	rdc321x_gpio_dev->chip.base = 0;
164	rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios;
165
166	platform_set_drvdata(pdev, rdc321x_gpio_dev);
167
168	/* This might not be, what others (BIOS, bootloader, etc.)
169	   wrote to these registers before, but it's a good guess. Still
170	   better than just using 0xffffffff. */
171	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
172					rdc321x_gpio_dev->reg1_data_base,
173					&rdc321x_gpio_dev->data_reg[0]);
174	if (err)
175		return pcibios_err_to_errno(err);
176
177	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
178					rdc321x_gpio_dev->reg2_data_base,
179					&rdc321x_gpio_dev->data_reg[1]);
180	if (err)
181		return pcibios_err_to_errno(err);
182
183	dev_info(&pdev->dev, "registering %d GPIOs\n",
184					rdc321x_gpio_dev->chip.ngpio);
185	return devm_gpiochip_add_data(&pdev->dev, &rdc321x_gpio_dev->chip,
186				      rdc321x_gpio_dev);
187}
188
189static struct platform_driver rdc321x_gpio_driver = {
190	.driver.name	= "rdc321x-gpio",
191	.probe		= rdc321x_gpio_probe,
192};
193
194module_platform_driver(rdc321x_gpio_driver);
195
196MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
197MODULE_DESCRIPTION("RDC321x GPIO driver");
198MODULE_LICENSE("GPL");
199MODULE_ALIAS("platform:rdc321x-gpio");
~/ Read-only file preview.