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 18 struct 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 */ 30 static 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 48 static 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 */ 67 static 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 80 static 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, ®); 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 104 unlock: 105 spin_unlock(&gpch->lock); 106 107 return pcibios_err_to_errno(err); 108 } 109 110 /* configure GPIO pin as input */ 111 static 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 */ 119 static 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_rv = 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 189 static struct platform_driver rdc321x_gpio_driver = { 190 .driver.name = "rdc321x-gpio", 191 .probe = rdc321x_gpio_probe, 192 }; 193 194 module_platform_driver(rdc321x_gpio_driver); 195 196 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 197 MODULE_DESCRIPTION("RDC321x GPIO driver"); 198 MODULE_LICENSE("GPL"); 199 MODULE_ALIAS("platform:rdc321x-gpio"); 200