brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · ec7fb92 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * RDC321x GPIO driver4 *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	else59		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 void rdc_gpio_set_value(struct gpio_chip *chip,68				unsigned gpio, 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 78static int rdc_gpio_config(struct gpio_chip *chip,79				unsigned gpio, int value)80{81	struct rdc321x_gpio *gpch;82	int err;83	u32 reg;84 85	gpch = gpiochip_get_data(chip);86 87	spin_lock(&gpch->lock);88	err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?89			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, &reg);90	if (err)91		goto unlock;92 93	reg |= 1 << (gpio & 0x1f);94 95	err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ?96			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg);97	if (err)98		goto unlock;99 100	rdc_gpio_set_value_impl(chip, gpio, value);101 102unlock:103	spin_unlock(&gpch->lock);104 105	return pcibios_err_to_errno(err);106}107 108/* configure GPIO pin as input */109static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)110{111	return rdc_gpio_config(chip, gpio, 1);112}113 114/*115 * Cache the initial value of both GPIO data registers116 */117static int rdc321x_gpio_probe(struct platform_device *pdev)118{119	int err;120	struct resource *r;121	struct rdc321x_gpio *rdc321x_gpio_dev;122	struct rdc321x_gpio_pdata *pdata;123 124	pdata = dev_get_platdata(&pdev->dev);125	if (!pdata) {126		dev_err(&pdev->dev, "no platform data supplied\n");127		return -ENODEV;128	}129 130	rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio),131					GFP_KERNEL);132	if (!rdc321x_gpio_dev)133		return -ENOMEM;134 135	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");136	if (!r) {137		dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");138		return -ENODEV;139	}140 141	spin_lock_init(&rdc321x_gpio_dev->lock);142	rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev;143	rdc321x_gpio_dev->reg1_ctrl_base = r->start;144	rdc321x_gpio_dev->reg1_data_base = r->start + 0x4;145 146	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");147	if (!r) {148		dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");149		return -ENODEV;150	}151 152	rdc321x_gpio_dev->reg2_ctrl_base = r->start;153	rdc321x_gpio_dev->reg2_data_base = r->start + 0x4;154 155	rdc321x_gpio_dev->chip.label = "rdc321x-gpio";156	rdc321x_gpio_dev->chip.owner = THIS_MODULE;157	rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input;158	rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config;159	rdc321x_gpio_dev->chip.get = rdc_gpio_get_value;160	rdc321x_gpio_dev->chip.set = rdc_gpio_set_value;161	rdc321x_gpio_dev->chip.base = 0;162	rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios;163 164	platform_set_drvdata(pdev, rdc321x_gpio_dev);165 166	/* This might not be, what others (BIOS, bootloader, etc.)167	   wrote to these registers before, but it's a good guess. Still168	   better than just using 0xffffffff. */169	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,170					rdc321x_gpio_dev->reg1_data_base,171					&rdc321x_gpio_dev->data_reg[0]);172	if (err)173		return pcibios_err_to_errno(err);174 175	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,176					rdc321x_gpio_dev->reg2_data_base,177					&rdc321x_gpio_dev->data_reg[1]);178	if (err)179		return pcibios_err_to_errno(err);180 181	dev_info(&pdev->dev, "registering %d GPIOs\n",182					rdc321x_gpio_dev->chip.ngpio);183	return devm_gpiochip_add_data(&pdev->dev, &rdc321x_gpio_dev->chip,184				      rdc321x_gpio_dev);185}186 187static struct platform_driver rdc321x_gpio_driver = {188	.driver.name	= "rdc321x-gpio",189	.probe		= rdc321x_gpio_probe,190};191 192module_platform_driver(rdc321x_gpio_driver);193 194MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");195MODULE_DESCRIPTION("RDC321x GPIO driver");196MODULE_LICENSE("GPL");197MODULE_ALIAS("platform:rdc321x-gpio");198