gpio-rdc321x.c (5137B)
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 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, ®); 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 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 registers 116 */ 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. Still 168 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 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 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");