diff options
Diffstat (limited to 'drivers/misc/mchp_pci1xxxx')
-rw-r--r-- | drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 9 | ||||
-rw-r--r-- | drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 110 | ||||
-rw-r--r-- | drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c | 6 |
3 files changed, 114 insertions, 11 deletions
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c index 32af2b14ff34..34c9be437432 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c @@ -69,8 +69,10 @@ static int gp_aux_bus_probe(struct pci_dev *pdev, const struct pci_device_id *id aux_bus->aux_device_wrapper[1] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[1]), GFP_KERNEL); - if (!aux_bus->aux_device_wrapper[1]) - return -ENOMEM; + if (!aux_bus->aux_device_wrapper[1]) { + retval = -ENOMEM; + goto err_aux_dev_add_0; + } retval = ida_alloc(&gp_client_ida, GFP_KERNEL); if (retval < 0) @@ -111,6 +113,7 @@ static int gp_aux_bus_probe(struct pci_dev *pdev, const struct pci_device_id *id err_aux_dev_add_1: auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev); + goto err_aux_dev_add_0; err_aux_dev_init_1: ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id); @@ -120,6 +123,7 @@ err_ida_alloc_1: err_aux_dev_add_0: auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev); + goto err_ret; err_aux_dev_init_0: ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id); @@ -127,6 +131,7 @@ err_aux_dev_init_0: err_ida_alloc_0: kfree(aux_bus->aux_device_wrapper[0]); +err_ret: return retval; } diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c index e616e3ec2b42..ff8f4404d10f 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c @@ -7,12 +7,14 @@ #include <linux/gpio/driver.h> #include <linux/bio.h> #include <linux/mutex.h> +#include <linux/pci.h> #include <linux/kthread.h> #include <linux/interrupt.h> #include "mchp_pci1xxxx_gp.h" #define PCI1XXXX_NR_PINS 93 +#define PCI_DEV_REV_OFFSET 0x08 #define PERI_GEN_RESET 0 #define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400) #define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10) @@ -37,11 +39,30 @@ struct pci1xxxx_gpio { struct auxiliary_device *aux_dev; void __iomem *reg_base; + raw_spinlock_t wa_lock; struct gpio_chip gpio; spinlock_t lock; + u32 gpio_wake_mask[3]; int irq_base; + u8 dev_rev; }; +static int pci1xxxx_gpio_get_device_revision(struct pci1xxxx_gpio *priv) +{ + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + int ret; + u32 val; + + ret = pci_read_config_dword(pcidev, PCI_DEV_REV_OFFSET, &val); + if (ret) + return ret; + + priv->dev_rev = val; + + return 0; +} + static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr) { struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio); @@ -114,8 +135,7 @@ static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio, return 0; } -static void pci1xxxx_gpio_set(struct gpio_chip *gpio, - unsigned int nr, int val) +static int pci1xxxx_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) { struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio); unsigned long flags; @@ -123,6 +143,8 @@ static void pci1xxxx_gpio_set(struct gpio_chip *gpio, spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, OUT_OFFSET(nr), (nr % 32), val); spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset, @@ -147,8 +169,11 @@ static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset, case PIN_CONFIG_DRIVE_OPEN_DRAIN: pci1xxx_assign_bit(priv->reg_base, OPENDRAIN_OFFSET(offset), (offset % 32), true); break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + pci1xxx_assign_bit(priv->reg_base, OPENDRAIN_OFFSET(offset), (offset % 32), false); + break; default: - ret = -EOPNOTSUPP; + ret = -ENOTSUPP; break; } spin_unlock_irqrestore(&priv->lock, flags); @@ -164,7 +189,7 @@ static void pci1xxxx_gpio_irq_ack(struct irq_data *data) unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - pci1xxx_assign_bit(priv->reg_base, INTR_STAT_OFFSET(gpio), (gpio % 32), true); + writel(BIT(gpio % 32), priv->reg_base + INTR_STAT_OFFSET(gpio)); spin_unlock_irqrestore(&priv->lock, flags); } @@ -249,11 +274,28 @@ static int pci1xxxx_gpio_set_type(struct irq_data *data, unsigned int trigger_ty return true; } +static int pci1xxxx_gpio_set_wake(struct irq_data *data, unsigned int enable) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct pci1xxxx_gpio *priv = gpiochip_get_data(chip); + unsigned int gpio = irqd_to_hwirq(data); + unsigned int bitpos = gpio % 32; + unsigned int bank = gpio / 32; + + if (enable) + priv->gpio_wake_mask[bank] |= (1 << bitpos); + else + priv->gpio_wake_mask[bank] &= ~(1 << bitpos); + + return 0; +} + static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) { struct pci1xxxx_gpio *priv = dev_id; struct gpio_chip *gc = &priv->gpio; unsigned long int_status = 0; + unsigned long wa_flags; unsigned long flags; u8 pincount; int bit; @@ -277,7 +319,9 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) writel(BIT(bit), priv->reg_base + INTR_STATUS_OFFSET(gpiobank)); spin_unlock_irqrestore(&priv->lock, flags); irq = irq_find_mapping(gc->irq.domain, (bit + (gpiobank * 32))); + raw_spin_lock_irqsave(&priv->wa_lock, wa_flags); generic_handle_irq(irq); + raw_spin_unlock_irqrestore(&priv->wa_lock, wa_flags); } } spin_lock_irqsave(&priv->lock, flags); @@ -293,6 +337,7 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = { .irq_mask = pci1xxxx_gpio_irq_mask, .irq_unmask = pci1xxxx_gpio_irq_unmask, .irq_set_type = pci1xxxx_gpio_set_type, + .irq_set_wake = pci1xxxx_gpio_set_wake, .flags = IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; @@ -300,32 +345,83 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = { static int pci1xxxx_gpio_suspend(struct device *dev) { struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + unsigned int gpio_bank_base; + unsigned int wake_mask; + unsigned int gpiobank; unsigned long flags; + for (gpiobank = 0; gpiobank < 3; gpiobank++) { + wake_mask = priv->gpio_wake_mask[gpiobank]; + + if (wake_mask) { + gpio_bank_base = gpiobank * 32; + + pci1xxx_assign_bit(priv->reg_base, + PIO_PCI_CTRL_REG_OFFSET, 0, true); + writel(~wake_mask, priv->reg_base + + WAKEMASK_OFFSET(gpio_bank_base)); + } + } + spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, true); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 17, false); pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, true); + + if (priv->dev_rev >= 0xC0) + pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, true); + spin_unlock_irqrestore(&priv->lock, flags); + device_set_wakeup_enable(&pcidev->dev, true); + pci_wake_from_d3(pcidev, true); + return 0; } static int pci1xxxx_gpio_resume(struct device *dev) { struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); + struct device *parent = priv->aux_dev->dev.parent; + struct pci_dev *pcidev = to_pci_dev(parent); + unsigned int gpio_bank_base; + unsigned int wake_mask; + unsigned int gpiobank; unsigned long flags; + for (gpiobank = 0; gpiobank < 3; gpiobank++) { + wake_mask = priv->gpio_wake_mask[gpiobank]; + + if (wake_mask) { + gpio_bank_base = gpiobank * 32; + + writel(wake_mask, priv->reg_base + + INTR_STAT_OFFSET(gpio_bank_base)); + pci1xxx_assign_bit(priv->reg_base, + PIO_PCI_CTRL_REG_OFFSET, 0, false); + writel(0xffffffff, priv->reg_base + + WAKEMASK_OFFSET(gpio_bank_base)); + } + } + spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 17, true); pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, false); pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, false); + + if (priv->dev_rev >= 0xC0) + pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, false); + spin_unlock_irqrestore(&priv->lock, flags); + pci_wake_from_d3(pcidev, false); + return 0; } @@ -342,7 +438,7 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq) gchip->direction_output = pci1xxxx_gpio_direction_output; gchip->get_direction = pci1xxxx_gpio_get_direction; gchip->get = pci1xxxx_gpio_get; - gchip->set = pci1xxxx_gpio_set; + gchip->set_rv = pci1xxxx_gpio_set; gchip->set_config = pci1xxxx_gpio_set_config; gchip->dbg_show = NULL; gchip->base = -1; @@ -405,6 +501,10 @@ static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev, if (retval < 0) return retval; + retval = pci1xxxx_gpio_get_device_revision(priv); + if (retval) + return retval; + dev_set_drvdata(&aux_dev->dev, priv); return devm_gpiochip_add_data(&aux_dev->dev, &priv->gpio, priv); diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c index 16695cb5e69c..a2ed477e0370 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c @@ -153,7 +153,6 @@ static int pci1xxxx_eeprom_read(void *priv_t, unsigned int off, buf[byte] = readl(rb + MMAP_EEPROM_OFFSET(EEPROM_DATA_REG)); } - ret = byte; error: release_sys_lock(priv); return ret; @@ -197,7 +196,6 @@ static int pci1xxxx_eeprom_write(void *priv_t, unsigned int off, goto error; } } - ret = byte; error: release_sys_lock(priv); return ret; @@ -258,7 +256,6 @@ static int pci1xxxx_otp_read(void *priv_t, unsigned int off, buf[byte] = readl(rb + MMAP_OTP_OFFSET(OTP_RD_DATA_OFFSET)); } - ret = byte; error: release_sys_lock(priv); return ret; @@ -315,7 +312,6 @@ static int pci1xxxx_otp_write(void *priv_t, unsigned int off, goto error; } } - ret = byte; error: release_sys_lock(priv); return ret; @@ -368,6 +364,7 @@ static int pci1xxxx_otp_eeprom_probe(struct auxiliary_device *aux_dev, if (is_eeprom_responsive(priv)) { priv->nvmem_config_eeprom.type = NVMEM_TYPE_EEPROM; priv->nvmem_config_eeprom.name = EEPROM_NAME; + priv->nvmem_config_eeprom.id = NVMEM_DEVID_AUTO; priv->nvmem_config_eeprom.dev = &aux_dev->dev; priv->nvmem_config_eeprom.owner = THIS_MODULE; priv->nvmem_config_eeprom.reg_read = pci1xxxx_eeprom_read; @@ -387,6 +384,7 @@ static int pci1xxxx_otp_eeprom_probe(struct auxiliary_device *aux_dev, priv->nvmem_config_otp.type = NVMEM_TYPE_OTP; priv->nvmem_config_otp.name = OTP_NAME; + priv->nvmem_config_otp.id = NVMEM_DEVID_AUTO; priv->nvmem_config_otp.dev = &aux_dev->dev; priv->nvmem_config_otp.owner = THIS_MODULE; priv->nvmem_config_otp.reg_read = pci1xxxx_otp_read; |