Blame view
drivers/gpio/gpio-rdc321x.c
5.65 KB
9956d02d6 gpio: Add support... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* * RDC321x GPIO driver * * Copyright (C) 2008, Volker Weiss <dev@tintuc.de> * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/pci.h> #include <linux/gpio.h> #include <linux/mfd/rdc321x.h> |
374b72eca gpio: Update gfp/... |
30 |
#include <linux/slab.h> |
9956d02d6 gpio: Add support... |
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
struct rdc321x_gpio { spinlock_t lock; struct pci_dev *sb_pdev; u32 data_reg[2]; int reg1_ctrl_base; int reg1_data_base; int reg2_ctrl_base; int reg2_data_base; struct gpio_chip chip; }; /* read GPIO pin */ static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) { struct rdc321x_gpio *gpch; u32 value = 0; int reg; |
78132252c gpio: rdc321x: us... |
49 |
gpch = gpiochip_get_data(chip); |
9956d02d6 gpio: Add support... |
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base; spin_lock(&gpch->lock); pci_write_config_dword(gpch->sb_pdev, reg, gpch->data_reg[gpio < 32 ? 0 : 1]); pci_read_config_dword(gpch->sb_pdev, reg, &value); spin_unlock(&gpch->lock); return (1 << (gpio & 0x1f)) & value ? 1 : 0; } static void rdc_gpio_set_value_impl(struct gpio_chip *chip, unsigned gpio, int value) { struct rdc321x_gpio *gpch; int reg = (gpio < 32) ? 0 : 1; |
78132252c gpio: rdc321x: us... |
66 |
gpch = gpiochip_get_data(chip); |
9956d02d6 gpio: Add support... |
67 68 69 70 71 72 73 |
if (value) gpch->data_reg[reg] |= 1 << (gpio & 0x1f); else gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f)); pci_write_config_dword(gpch->sb_pdev, |
75907a115 gpio: Fix inverte... |
74 |
reg ? gpch->reg2_data_base : gpch->reg1_data_base, |
9956d02d6 gpio: Add support... |
75 76 77 78 79 80 81 82 |
gpch->data_reg[reg]); } /* set GPIO pin to value */ static void rdc_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) { struct rdc321x_gpio *gpch; |
78132252c gpio: rdc321x: us... |
83 |
gpch = gpiochip_get_data(chip); |
9956d02d6 gpio: Add support... |
84 85 86 87 88 89 90 91 92 93 94 |
spin_lock(&gpch->lock); rdc_gpio_set_value_impl(chip, gpio, value); spin_unlock(&gpch->lock); } static int rdc_gpio_config(struct gpio_chip *chip, unsigned gpio, int value) { struct rdc321x_gpio *gpch; int err; u32 reg; |
78132252c gpio: rdc321x: us... |
95 |
gpch = gpiochip_get_data(chip); |
9956d02d6 gpio: Add support... |
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
spin_lock(&gpch->lock); err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ? gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, ®); if (err) goto unlock; reg |= 1 << (gpio & 0x1f); err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ? gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg); if (err) goto unlock; rdc_gpio_set_value_impl(chip, gpio, value); unlock: spin_unlock(&gpch->lock); return err; } /* configure GPIO pin as input */ static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { return rdc_gpio_config(chip, gpio, 1); } /* * Cache the initial value of both GPIO data registers */ |
3836309d9 gpio: remove use ... |
127 |
static int rdc321x_gpio_probe(struct platform_device *pdev) |
9956d02d6 gpio: Add support... |
128 129 130 131 132 |
{ int err; struct resource *r; struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; |
e56aee189 gpio: use dev_get... |
133 |
pdata = dev_get_platdata(&pdev->dev); |
9956d02d6 gpio: Add support... |
134 135 136 137 138 |
if (!pdata) { dev_err(&pdev->dev, "no platform data supplied "); return -ENODEV; } |
95ad6b9da gpio: rdc321x: Co... |
139 140 |
rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio), GFP_KERNEL); |
84e27f97e gpio: rdc321x: re... |
141 |
if (!rdc321x_gpio_dev) |
9956d02d6 gpio: Add support... |
142 |
return -ENOMEM; |
9956d02d6 gpio: Add support... |
143 |
|
8deca39e5 mfd: Change rdc32... |
144 |
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1"); |
9956d02d6 gpio: Add support... |
145 146 147 |
if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg1 resource "); |
95ad6b9da gpio: rdc321x: Co... |
148 |
return -ENODEV; |
9956d02d6 gpio: Add support... |
149 150 151 152 153 154 |
} spin_lock_init(&rdc321x_gpio_dev->lock); rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev; rdc321x_gpio_dev->reg1_ctrl_base = r->start; rdc321x_gpio_dev->reg1_data_base = r->start + 0x4; |
8deca39e5 mfd: Change rdc32... |
155 |
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2"); |
9956d02d6 gpio: Add support... |
156 157 158 |
if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg2 resource "); |
95ad6b9da gpio: rdc321x: Co... |
159 |
return -ENODEV; |
9956d02d6 gpio: Add support... |
160 161 162 163 164 165 |
} rdc321x_gpio_dev->reg2_ctrl_base = r->start; rdc321x_gpio_dev->reg2_data_base = r->start + 0x4; rdc321x_gpio_dev->chip.label = "rdc321x-gpio"; |
1146f8822 gpio: rdc321x: Pr... |
166 |
rdc321x_gpio_dev->chip.owner = THIS_MODULE; |
9956d02d6 gpio: Add support... |
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input; rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config; rdc321x_gpio_dev->chip.get = rdc_gpio_get_value; rdc321x_gpio_dev->chip.set = rdc_gpio_set_value; rdc321x_gpio_dev->chip.base = 0; rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios; platform_set_drvdata(pdev, rdc321x_gpio_dev); /* This might not be, what others (BIOS, bootloader, etc.) wrote to these registers before, but it's a good guess. Still better than just using 0xffffffff. */ err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, rdc321x_gpio_dev->reg1_data_base, &rdc321x_gpio_dev->data_reg[0]); if (err) |
95ad6b9da gpio: rdc321x: Co... |
183 |
return err; |
9956d02d6 gpio: Add support... |
184 185 186 187 188 |
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, rdc321x_gpio_dev->reg2_data_base, &rdc321x_gpio_dev->data_reg[1]); if (err) |
95ad6b9da gpio: rdc321x: Co... |
189 |
return err; |
9956d02d6 gpio: Add support... |
190 191 192 193 |
dev_info(&pdev->dev, "registering %d GPIOs ", rdc321x_gpio_dev->chip.ngpio); |
cfae2c908 gpio: rdc321x: Us... |
194 195 |
return devm_gpiochip_add_data(&pdev->dev, &rdc321x_gpio_dev->chip, rdc321x_gpio_dev); |
9956d02d6 gpio: Add support... |
196 197 198 199 |
} static struct platform_driver rdc321x_gpio_driver = { .driver.name = "rdc321x-gpio", |
9956d02d6 gpio: Add support... |
200 |
.probe = rdc321x_gpio_probe, |
9956d02d6 gpio: Add support... |
201 |
}; |
6f61415e9 gpio: Convert GPI... |
202 |
module_platform_driver(rdc321x_gpio_driver); |
9956d02d6 gpio: Add support... |
203 204 205 206 207 |
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); MODULE_DESCRIPTION("RDC321x GPIO driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:rdc321x-gpio"); |