0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/ioport.h>
0026 #include <linux/module.h>
0027 #include <linux/kernel.h>
0028 #include <linux/gpio/driver.h>
0029 #include <linux/pci.h>
0030 #include <linux/spinlock.h>
0031
0032 #define PMBASE_OFFSET 0xb0
0033 #define PMBASE_SIZE 0x30
0034
0035 #define AMD_REG_GPIO(i) (0x10 + (i))
0036
0037 #define AMD_GPIO_LTCH_STS 0x40
0038 #define AMD_GPIO_RTIN 0x20
0039 #define AMD_GPIO_DEBOUNCE 0x10
0040 #define AMD_GPIO_MODE_MASK 0x0c
0041 #define AMD_GPIO_MODE_IN 0x00
0042 #define AMD_GPIO_MODE_OUT 0x04
0043
0044 #define AMD_GPIO_MODE_ALTFN 0x08
0045 #define AMD_GPIO_X_MASK 0x03
0046 #define AMD_GPIO_X_IN_ACTIVEHI 0x01
0047 #define AMD_GPIO_X_IN_LATCH 0x02
0048 #define AMD_GPIO_X_OUT_LOW 0x00
0049 #define AMD_GPIO_X_OUT_HI 0x01
0050 #define AMD_GPIO_X_OUT_CLK0 0x02
0051 #define AMD_GPIO_X_OUT_CLK1 0x03
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 static const struct pci_device_id pci_tbl[] = {
0062 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 },
0063 { 0, },
0064 };
0065 MODULE_DEVICE_TABLE(pci, pci_tbl);
0066
0067 struct amd_gpio {
0068 struct gpio_chip chip;
0069 u32 pmbase;
0070 void __iomem *pm;
0071 struct pci_dev *pdev;
0072 spinlock_t lock;
0073 u8 orig[32];
0074 };
0075
0076 static int amd_gpio_request(struct gpio_chip *chip, unsigned offset)
0077 {
0078 struct amd_gpio *agp = gpiochip_get_data(chip);
0079
0080 agp->orig[offset] = ioread8(agp->pm + AMD_REG_GPIO(offset)) &
0081 (AMD_GPIO_DEBOUNCE | AMD_GPIO_MODE_MASK | AMD_GPIO_X_MASK);
0082
0083 dev_dbg(&agp->pdev->dev, "Requested gpio %d, data %x\n", offset, agp->orig[offset]);
0084
0085 return 0;
0086 }
0087
0088 static void amd_gpio_free(struct gpio_chip *chip, unsigned offset)
0089 {
0090 struct amd_gpio *agp = gpiochip_get_data(chip);
0091
0092 dev_dbg(&agp->pdev->dev, "Freed gpio %d, data %x\n", offset, agp->orig[offset]);
0093
0094 iowrite8(agp->orig[offset], agp->pm + AMD_REG_GPIO(offset));
0095 }
0096
0097 static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
0098 {
0099 struct amd_gpio *agp = gpiochip_get_data(chip);
0100 u8 temp;
0101 unsigned long flags;
0102
0103 spin_lock_irqsave(&agp->lock, flags);
0104 temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
0105 temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_OUT | (value ? AMD_GPIO_X_OUT_HI : AMD_GPIO_X_OUT_LOW);
0106 iowrite8(temp, agp->pm + AMD_REG_GPIO(offset));
0107 spin_unlock_irqrestore(&agp->lock, flags);
0108
0109 dev_dbg(&agp->pdev->dev, "Setting gpio %d, value %d, reg=%02x\n", offset, !!value, temp);
0110 }
0111
0112 static int amd_gpio_get(struct gpio_chip *chip, unsigned offset)
0113 {
0114 struct amd_gpio *agp = gpiochip_get_data(chip);
0115 u8 temp;
0116
0117 temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
0118
0119 dev_dbg(&agp->pdev->dev, "Getting gpio %d, reg=%02x\n", offset, temp);
0120
0121 return (temp & AMD_GPIO_RTIN) ? 1 : 0;
0122 }
0123
0124 static int amd_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value)
0125 {
0126 struct amd_gpio *agp = gpiochip_get_data(chip);
0127 u8 temp;
0128 unsigned long flags;
0129
0130 spin_lock_irqsave(&agp->lock, flags);
0131 temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
0132 temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_OUT | (value ? AMD_GPIO_X_OUT_HI : AMD_GPIO_X_OUT_LOW);
0133 iowrite8(temp, agp->pm + AMD_REG_GPIO(offset));
0134 spin_unlock_irqrestore(&agp->lock, flags);
0135
0136 dev_dbg(&agp->pdev->dev, "Dirout gpio %d, value %d, reg=%02x\n", offset, !!value, temp);
0137
0138 return 0;
0139 }
0140
0141 static int amd_gpio_dirin(struct gpio_chip *chip, unsigned offset)
0142 {
0143 struct amd_gpio *agp = gpiochip_get_data(chip);
0144 u8 temp;
0145 unsigned long flags;
0146
0147 spin_lock_irqsave(&agp->lock, flags);
0148 temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
0149 temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_IN;
0150 iowrite8(temp, agp->pm + AMD_REG_GPIO(offset));
0151 spin_unlock_irqrestore(&agp->lock, flags);
0152
0153 dev_dbg(&agp->pdev->dev, "Dirin gpio %d, reg=%02x\n", offset, temp);
0154
0155 return 0;
0156 }
0157
0158 static struct amd_gpio gp = {
0159 .chip = {
0160 .label = "AMD GPIO",
0161 .owner = THIS_MODULE,
0162 .base = -1,
0163 .ngpio = 32,
0164 .request = amd_gpio_request,
0165 .free = amd_gpio_free,
0166 .set = amd_gpio_set,
0167 .get = amd_gpio_get,
0168 .direction_output = amd_gpio_dirout,
0169 .direction_input = amd_gpio_dirin,
0170 },
0171 };
0172
0173 static int __init amd_gpio_init(void)
0174 {
0175 int err = -ENODEV;
0176 struct pci_dev *pdev = NULL;
0177 const struct pci_device_id *ent;
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 for_each_pci_dev(pdev) {
0189 ent = pci_match_id(pci_tbl, pdev);
0190 if (ent)
0191 goto found;
0192 }
0193
0194 goto out;
0195
0196 found:
0197 err = pci_read_config_dword(pdev, 0x58, &gp.pmbase);
0198 if (err)
0199 goto out;
0200 err = -EIO;
0201 gp.pmbase &= 0x0000FF00;
0202 if (gp.pmbase == 0)
0203 goto out;
0204 if (!devm_request_region(&pdev->dev, gp.pmbase + PMBASE_OFFSET,
0205 PMBASE_SIZE, "AMD GPIO")) {
0206 dev_err(&pdev->dev, "AMD GPIO region 0x%x already in use!\n",
0207 gp.pmbase + PMBASE_OFFSET);
0208 err = -EBUSY;
0209 goto out;
0210 }
0211 gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
0212 if (!gp.pm) {
0213 dev_err(&pdev->dev, "Couldn't map io port into io memory\n");
0214 err = -ENOMEM;
0215 goto out;
0216 }
0217 gp.pdev = pdev;
0218 gp.chip.parent = &pdev->dev;
0219
0220 spin_lock_init(&gp.lock);
0221
0222 dev_info(&pdev->dev, "AMD-8111 GPIO detected\n");
0223 err = gpiochip_add_data(&gp.chip, &gp);
0224 if (err) {
0225 dev_err(&pdev->dev, "GPIO registering failed (%d)\n", err);
0226 ioport_unmap(gp.pm);
0227 goto out;
0228 }
0229 out:
0230 return err;
0231 }
0232
0233 static void __exit amd_gpio_exit(void)
0234 {
0235 gpiochip_remove(&gp.chip);
0236 ioport_unmap(gp.pm);
0237 }
0238
0239 module_init(amd_gpio_init);
0240 module_exit(amd_gpio_exit);
0241
0242 MODULE_AUTHOR("The Linux Kernel team");
0243 MODULE_DESCRIPTION("GPIO driver for AMD chipsets");
0244 MODULE_LICENSE("GPL");